Skip to main content
Object Oriented Design, Analysis and Programming

Introduction to Java and Object-Oriented Programming Foundations

Published: 2026-08-19
Level: postgraduate
Audience: Postgraduate students in Object Oriented Design, Analysis and Programming

Prerequisite Knowledge

This lecture builds on the following concepts from earlier lectures. If any feel unfamiliar, review the linked notes before proceeding.

Previously Covered in This Subject

  • 16.10 Encapsulation — Binding Data With the Code That Manipulates It — covered in Lecture 1: Object-Oriented Analysis and Design
  • 16.11 Inheritance — One Class Acquiring Properties of Another — covered in Lecture 1: Object-Oriented Analysis and Design
  • 16.12 Polymorphism — Many Forms — covered in Lecture 1: Object-Oriented Analysis and Design

This lecture introduces Java as both a language and a platform, traces the bytecode execution path that gives Java its portability, inventories the JDK, JRE, JVM, and JIT layers, surveys where Java runs across billions of devices, and builds the core object model — classes as blueprints, objects as filled instances, the structure of a first program, manual command-line build steps, Eclipse project flow, and the three organizing principles and code organization tools of encapsulation, inheritance, polymorphism, and packages.

16.1 Java as a Language and as a Platform

16.1.1 Course Setup and the Flipped Approach

This course is offered through the work integrated learning program and it uses a flipped mode. Recorded lectures, slides, and course material are shared on the portal before the live session. The live session assumes you have gone through that material. The focus is on discussion, problem solving, and interactive examples rather than repeating slides. The course handout on the portal lists the exact pattern. A programming background in C or C++ is helpful, because you will recognise variables, control flow, and functions, yet the course is built so that even without that background you can follow the Java material from the start. The first session therefore spends extra time on what object oriented programming is, what Java is, what editors exist, how to debug, and how to write and run your very first program.

Hook: Why does Java insist you need a whole "platform" when C only needs a compiler? The answer decides whether your program runs on one laptop or on any device with a single build.

Flipped learning here means you first watch the pre-contact video and read the slides that cover vocabulary like class, object, and platform, then you use the live hour to debug a real Hello World together and to argue about what "platform" really means. This order moves memorisation outside class and leaves class time for the mistakes you learn most from, such as mistyping System.out.println and reading the compiler error.

Exam note: Be ready to explain the flipped pattern in one sentence: pre-contact material on the portal plus live discussion and problem solving, with the course handout as the source for the exact schedule. Practice is expected before you arrive.

16.1.2 What a Platform Means

When you hear platform, you might think of several things. In the discussion, responses included a place to develop, a software layer, a user interface that builds on a particular technology, an operating system, and an application level interface. All of these point toward the same central idea.

Intuition — the stage analogy: Think of a platform the way you think of a stage in a theatre. The stage itself is not the play, but without the stage, lights, and sound system, no play can run. The stage combines the wooden floor (hardware) with the lights and curtains (software) to give actors a place to perform. A computer platform does the same — it combines hardware and software services so that an application can run on top of it. The analogy breaks where a theatre stage is fixed and physical; a software platform is portable and can be installed on many kinds of hardware.

Formal idea: A platform is any hardware or software environment where a program runs. Think of it as a combined unit of hardware and software that gives other applications a place to execute. It provides the way to run programs, processes, and software. In everyday examples, Windows on a laptop, Android on a phone, or a browser with its runtime are platforms because each combines hardware access and software services to let code execute. Two questions tell you if something is a platform: does it control the processor and memory for you, and does it offer libraries or services that your code calls?

Visual intuition: Picture a vertical stack. At the bottom is raw hardware — processor, memory, disk. Just above it is the operating system that drives the hardware. At the top is your application. A platform is the whole slab you stand on when you run the application — sometimes that slab is "hardware + operating system", sometimes it is "hardware + operating system + Java runtime". The one-sentence takeaway: without the slab, the application has nowhere to stand.

Scope: The definition applies whenever code needs services beyond bare metal. If your program talks directly to hardware registers without any intervening software layer, you are working without a platform abstraction. For Java, that never happens — every Java program assumes a platform that can load bytecode and offer standard libraries.

Pitfalls:

  • Treating "platform" as only an operating system. A browser, a JVM, and even a game engine are platforms when they host your code.
  • Thinking platform is the language. C is a language that compiles to native code and then leans on the host operating system as its platform. Java brings its own platform with it.

16.1.3 Why Java Is Called Both a Language and a Platform

Java is a programming language you use to write source code in files ending with .java. At the same time, Java is called a platform because it brings its own runtime environment.

Formal idea: That environment is the Java Runtime Environment, usually written as JRE, plus the Application Programming Interface (API) libraries. The JRE holds the tools, support code, and libraries needed to run a Java program. Because of this self-contained runtime, a Java program does not rely directly on the host operating system's compiler setup. A C program can be compiled to a native executable that runs directly on Windows, Unix, Mac, or other systems if you have a compiler for that system. A Java program instead needs the JRE present. Once the JRE is present, the Java code has the whole support system it needs. In short, Java the language is what you write; Java the platform is the JRE plus API that gives that writing a place to run.

Comparison — Java versus C on platforms: In C, you ship source and rely on a separate compiler for each target, and the resulting executable is tied to one operating system and processor. In Java, you ship bytecode and rely on a port of the JRE for each target, and the same bytecode runs wherever that port exists. Pick C-style native compilation when you need maximal startup speed or direct hardware access without any virtual machine. Pick Java's platform approach when you need "build once, run many places" and automatic services like memory management and standard libraries.

Real-world: this is why the same Java code base can be used on many kinds of devices while only the JRE port for that device changes. A bank's account service, for example, can be built once on a developer laptop and then run on a Linux server, a Windows test machine, and a container in the cloud, because each target offers the same Java platform on top of different hardware.

Q: What do you understand by the word platform? A: Students offered: a place to develop, a software layer, a user interface that builds on a particular technology, an operating system, an application level interface. All answers are partially correct. The synthesis is: a platform is any hardware or software environment where a program runs, a combined hardware plus software unit that lets other applications execute. In Java, the JRE plus API forms that platform. The correction matters because it moves you from a narrow "it is an OS" idea to the broader "any environment that hosts execution" idea — and Java's claim is that it is itself such an environment.

Recap: A platform is the hardware-plus-software slab your code runs on. Java earns the word platform because, beyond syntax, it supplies a full runtime — the JRE and its API — that hosts bytecode on any hardware that provides a JVM. Bridge: That JRE claim only makes sense if you see how Java inserts an extra step — bytecode — between your .java file and the machine. Next, we trace that exact path.

16.2 Bytecode and the Way a Java Program Executes

16.2.1 The Execution Path With an Intermediate Step

A Java program does not go directly from source file to executable file. The intermediate step is what gives Java its portability.

Hook: If a compiler could go straight to an executable, why add an extra step that looks slower? Java adds the step on purpose to buy portability.

The source file, for example First.java, contains the text you write. You compile it. The output of the compiler is not a native .exe but a .class file that holds bytecode. That bytecode is then handled by an interpreter to reach a form that the underlying machine can run. The chain is:

First.java (source text you write)
  -- compile with javac --> First.class (bytecode)
  -- interpret with java --> output ready to run

Formal idea: Bytecode is a set of highly optimized instructions that the Java runtime system can execute. It is not tied to Windows or Unix or Mac by itself. Concretely, javac First.java reads your Java syntax, checks types and syntax, and emits a compact instruction stream into First.class. The Java launcher java First then starts a Java Virtual Machine, which loads that .class, verifies the bytecode for safety, and interprets or just-in-time compiles it to the host processor's native instructions.

Bytecode is described as highly optimized instructions that the Java runtime system can execute. It is not tied to Windows or Unix or Mac by itself. This is the core of Java's "write once, run anywhere" promise — the compiler's output is neutral.

16.2.2 Java's Magic and Portability

Bytecode is often called Java's magic. You write and compile on one system, for example Windows, and produce First.class. You can then take that same .class file to a Unix system, a Mac, or any other system and run it, provided the target system has a JRE available. You do not recompile the source. You carry the error-free compiled form and execute it directly.

Intuition — the travel adapter analogy: Think of bytecode like a travel adapter's universal plug. You manufacture the plug once in your home factory (compile on Windows). Every country (Unix, Mac, Linux, Solaris) has its own wall socket, but each also sells an adapter for the universal plug (a port of the JVM). Carry the single plug with you, plug it in through the local adapter, and it works. The analogy breaks where electricity is simple voltage; bytecode verification also checks safety rules such as type correctness before running.

Contrast this with a direct native compilation where you would generate a platform-specific .exe. Different platforms have different configurations, so a single native executable cannot run everywhere. That is the gap that the C tool chain faces without a dedicated compiler per platform.

With Java, your own system provides the compiler, you generate bytecode, and the bytecode travels. Each target provides the matching Java Virtual Machine (JVM) inside its JRE to interpret the bytecode.

Worked execution — First.java source compiled to First.class bytecode then interpreted with java: Start with an empty folder. Create First.java with the Hello World class. Run javac First.java from the command prompt after changing directory with cd to that folder. If there is no syntax error, the compiler creates First.class alongside First.java — you can see the new file appear with type "class file". Now copy only First.class to a second machine that runs Unix and has a JRE, without copying First.java. On that Unix shell, run java First (no .class suffix). The JVM loads the bytecode, verifies it, and prints Hello World to the console. No recompilation happened on the Unix side. The same sequence works in reverse: compile on Unix, run on Windows. Sense-check: if the target lacks a JRE, java is not found and the .class file is just data — it cannot execute.

Real-world: this portability is the reason the same backend service JAR can be built once and deployed on Linux servers, developer laptops, and cloud containers without rebuilding. The build server produces a JAR of .class files; each deployment target only needs the correct Java runtime.

Visual intuition: Draw a horizontal pipeline with three boxes and two arrows. Box 1 is First.java (text, human-readable, .java extension). Arrow 1 labeled javac points to Box 2 First.class (bytecode, compact, portable). Arrow 2 labeled java + JVM points to Box 3 "native execution + Hello World output". The key landmark is that Box 2 is portable; it can branch to many Box 3 instances on different operating systems. One-sentence takeaway: one compilation fans out to many executions.

Scope and assumptions: Bytecode portability holds when you use only standard libraries and avoid platform-specific assumptions such as hard-coded file paths like C:\temp or line endings. The bytecode itself is portable, but your program's logic may not be if you assume one operating system's file layout. Also, you still need a matching Java version — bytecode built with Java 18 may not run on a much older JRE that lacks those class formats.

Pitfalls:

  • Trying to run java First.java instead of java First. The java launcher expects a class name, not a file name; include no extension.
  • Editing First.class in a text editor. It is binary bytecode, not text — it will look garbled and editing it corrupts it.
  • Assuming bytecode is source code. First.class cannot be fixed by re-editing it; you edit First.java and recompile with javac.

Q: Why are we creating bytecode and then interpreting it, instead of making an exe directly? A: If you generate a direct exe, that exe must be complete for every platform you want to support — Windows, Mac, Linux, Unix, Solaris, and others — each with its own configuration. Keeping a separate compiler for each platform is the problem that appears with C-style tool chains. Java breaks the chain: you compile once to bytecode on your own system. Because the compiled bytecode is error-free, you can carry it to any platform where a JVM is available and execute it without recompiling. That portability is the core benefit of the intermediate bytecode. Several students asked this same "why not direct exe" confusion — the answer is always portability, not speed.

16.2.3 How to Describe the Process in Words

When you write notes on this flow, keep the spoken description alongside the steps: source file First.java is the program you have written; after compilation you get a First.class file; that file is the bytecode; bytecode with the help of an interpreter becomes the final executable form ready to run. Saying it in order — "I wrote First dot java, I compiled it with javac to First dot class bytecode, I then interpreted it with the java launcher on a JVM" — cements the chain better than memorizing arrows alone. In an exam, that ordered sentence is what shows you understand the intermediate step.

Recap: Java does not compile straight to native code. It compiles to neutral bytecode (First.class) that any JVM can load and run, which is the whole reason the same class file travels unchanged between Windows and Unix. Bridge: That travel only works because each target provides a machine that understands bytecode — the JVM — wrapped in larger environments we name JRE and JDK.

16.3 Components of the Java Execution Environment — JDK, JRE, JVM and JIT

16.3.1 The Nested Diagram

The environment is best seen as nested boxes. The innermost rectangle is the Java Virtual Machine (JVM). Around it is the Java Runtime Environment (JRE), often shown as a green box. Around both is the Java Development Kit (JDK). A fourth label, JIT, is an optimization layer that improves interpretation and final execution time.

Visual intuition: Picture three concentric rectangles. The smallest inner rectangle is labeled JVM — the engine. The middle rectangle, often colored green in slides, is labeled JRE — engine plus fuel and libraries. The outer rectangle is labeled JDK — the full workshop that contains the engine, the fuel, and all the tools to build engines. A floating badge labeled JIT sits on the JVM boundary, with an arrow saying "makes hot code faster while running". The one-sentence takeaway: each outer box adds capability, but only the inner JVM actually executes bytecode.

Scope: This nesting describes the classic distribution from Oracle and OpenJDK. Modern installers sometimes bundle a JRE inside a JDK directory; the logical nesting remains, even if the folder layout looks flat. The diagram is about responsibility, not exact folder names.

16.3.2 JVM — What It Does

A JVM is the interpreter for bytecode. Where First.class is the result of compilation, the JVM provides the runtime for executing that .class file. It loads the bytecode, verifies it, and executes it. Without a JVM, the .class file is just data. With a JVM, it becomes a running program.

JVM in depth: When you run java First, you start a JVM instance. It performs three jobs in order. First, the class loader finds First.class on the classpath and brings its bytecode into memory. Next, the bytecode verifier checks the stream for violations — wrong types, stack overflows, illegal casts — and rejects it if it is unsafe, so broken or malicious bytecode never runs. Then the execution engine interprets the bytecode instruction by instruction, or hands hot sections to the JIT compiler. An engine analogy helps: the JVM is the engine that turns fuel (bytecode) into motion (native instructions). Without the engine, fuel just sits in the tank.

Pitfalls: Calling the JVM a compiler. javac is the compiler that emits bytecode; the JVM is the runtime that loads, verifies, and executes that bytecode. Mixing the names loses marks.

16.3.3 JRE — What It Adds

The JRE is the runtime environment for bytecode execution. It contains the JVM plus the libraries and files that the JVM uses. If the JVM is the engine, the JRE is the engine plus the supporting libraries, resources, and runtime files that make the engine usable. Running programs requires a JRE, not just a JVM in isolation.

JRE in depth: The JRE adds the standard class libraries — java.lang, java.util, java.io and many more — plus native support files and property files that the JVM needs to find classes and handle security and deployment. Think of it as engine plus the fuel system, coolant, and handbook. If you only need to run a Java program that someone else built, installing a JRE is enough. Since Java 11, many vendors no longer ship a separate JRE download; they ship a JDK that contains the runtime, but the logical distinction remains: JRE equals JVM plus libraries for running, without development tools.

16.3.4 JDK — The Full Development Kit

The JDK contains everything needed to develop Java applications. It includes the JRE and the JVM, plus the Java compiler (javac), the Java interpreter (java), and the Java documentation and tools. The outer rectangle in the diagram represents this complete system. If you are only running programs, a JRE is enough. If you are writing, compiling, and building programs, you need the JDK.

JDK in depth: Inside the JDK's bin folder live javac (compiler), java (launcher that starts a JVM), javadoc (documentation generator), jar (archiver), and debuggers and profilers. The outer rectangle means the JDK contains everything inner: you get the JRE's libraries and the JVM as a subset. On a developer laptop, you install the JDK; on a production server that only runs a built JAR, a JRE or a JDK's runtime image suffices. The lecture's picture of JDK outside JRE outside JVM is the memory hook to recall that dependency: JDK needs JRE needs JVM.

Intuition — workshop analogy: If the JVM is the engine and the JRE is engine plus fuel and roads, then the JDK is the entire workshop that built the engine. The workshop contains the engine room (JRE/JVM), but also the lathe and mill (javac), the test track (java), and the manuals. You would not give a driver the whole workshop; you give them just the car (JRE). You give a builder the workshop (JDK). The analogy breaks where a workshop is a physical place — the JDK is a software collection that you install as files, not a building.

16.3.5 JIT — The Optimizer

JIT stands for Just-In-Time compilation. It optimizes interpretation and improves execution time. The model is simple: first, make the code correct — both syntax and meaning — so it compiles without errors. Then, make it fast and storage-efficient. JIT works at that second stage, tuning the way bytecode is turned into native instructions while the program runs.

JIT in depth: Pure interpretation steps through bytecode one instruction at a time, which is safe but slow. The JIT compiler watches which methods are executed many times — so-called hot spots, such as loops that run thousands of times — and compiles those hot bytecodes into native machine code while the program is running, then caches that native code for reuse. Later calls to the same method jump to the cached native version instead of being reinterpreted. The result is that a long-running server gets faster after a warm-up period, often after seconds or minutes of running. JIT does not change your source or your .class file; it only changes how quickly the JVM executes the bytecodes it already loaded.

Real-world: in production servers, JIT is a reason long-running Java services gain speed after a warm-up period, as the optimizer learns hot paths. A Spring web service may serve the first few hundred requests a bit slower, then stabilize at higher throughput once hot methods have been JIT-compiled. That is why benchmarks usually discard the first seconds as warm-up.

Pitfalls:

  • Thinking JIT runs at compile time (javac). It runs at execution time inside the JVM, while java is already running your program.
  • Expecting JIT to fix incorrect code. JIT only makes correct bytecode faster; it cannot rescue logic errors or missing libraries.

Recap: The JVM is the bytecode interpreter at the core, the JRE is JVM plus libraries to run programs, the JDK is JRE plus tools like javac to build programs, and JIT is the runtime optimizer that turns frequently used bytecode into fast native code. Bridge: Those layers are not abstract — they are why 3 billion devices can claim Java support. Next, we see where that reach actually lands.

16.4 Where Java Is Used

16.4.1 Scale of Adoption

According to Sun Microsystems, 3 billion devices run Java. That number is used to stress how widely the language and its runtime have spread.

Hook: Why would a bank, a phone maker, and a card manufacturer all settle on the same language? Java's run-anywhere bytecode made it the safe shared bet before app stores existed.

The figure is from Sun Microsystems, the original creator of Java, and it counted servers, desktops, phones, smart cards, and embedded controllers that shipped with a Java runtime. Even if you update the number today — Oracle now cites higher counts — the point remains: learning Java's class and object model gives you a skill that transfers across hardware families, not just one product line. That reach is the reason the course invests the first lecture in platform and bytecode before any sophisticated object design.

Scope: "3 billion devices" is a marketing-era snapshot, not a formal census. It includes devices where Java powers a hidden controller, not just devices where you write Java apps yourself. The lesson is breadth, not a precise count to quote as exact today.

16.4.2 Domains

Java appears across many domains:

  • desktop applications
  • enterprise applications
  • mobile systems — Android itself uses Java
  • embedded systems and micro devices, including IoT devices
  • smart cards
  • robotics
  • games
  • web systems

The language provides separate modules for desktop, web, and mobile development, so the same core ideas carry across subdomains. Whether you look at a transactional backend, a desktop tool, a web service, or a device controller, you are likely to meet Java.

What each domain means in practice: Desktop applications use Java's Swing or JavaFX toolkits to build windows, menus, and dialogs — for example, an internal account management tool that shows tables of balances. Enterprise applications are server-side systems such as banking backends and e-commerce order processing, often built with the Java Enterprise stack and Spring, where reliability and transactions matter more than pixels. Mobile systems — Android itself uses Java means that the original Android app model exposed Java APIs, so writing an Android activity reuses the same class and package ideas. Embedded systems and IoT are tiny controllers — sensor gateways, factory controllers, smart meters — where a small JRE runs on limited memory to collect and forward readings. Smart cards are chip cards that carry a Java Card runtime to run applets for authentication. Robotics and games reuse the same object model to manage sensors, actuators, and game worlds, while web systems cover servlets and web services that answer HTTP requests.

Visual intuition: Imagine a fan chart with "core Java (classes, objects, packages)" at the center. Spokes radiate to desktop, web, mobile, embedded, smart card, robotics, games. The fan shows that the center is identical — you write a Student class the same way — while only the outer spoke libraries change. The one-sentence takeaway: master the center once, then pick a spoke for your job.

Real-world: a single team can move between a desktop Swing tool, a Spring web service, and an Android app while staying inside the broader Java ecosystem. The Swing tool might let an analyst edit account records, the Spring service might expose POST /accounts over HTTP, and the Android app might let a field agent view those same accounts on a phone — all three share the Account class and its withdraw and deposit methods without rewriting business rules.

16.4.3 Significance for This Course

Before starting object oriented ideas, this breadth matters because it explains why you learn classes, objects, and packages in a way that transfers directly to many job roles. If Java only powered one kind of device, you could afford to learn a device-specific shortcut. Because it powers many, the course insists on the portable foundation — blueprint thinking with classes, controlled access with encapsulation, reuse with inheritance, flexibility with polymorphism, and organization with packages — that is identical everywhere Java runs.

Pitfalls:

  • Treating Java as only an Android language. Android's use of Java is one spoke; enterprise and embedded are equally important and they use the same object ideas.
  • Skipping platform concepts because they feel introductory. Every later topic, from inheritance to packages, assumes you know that bytecode is portable and that JRE, JDK, and JVM are different responsibilities.

Recap: Sun's 3 billion-devices figure signals that Java is not niche. It runs on desktops, servers, phones, cards, robots, and the web, and it offers distinct modules for each while keeping the core language identical. Bridge: That identical core is classes and objects. Next we look at the blueprint from which every Java object is made.

16.5 Classes — The Blueprint Idea

16.5.1 Starting From Examples Before a Formal Definition

A class is introduced through examples first, then given a formal shape. An attribute is a named data item held by the class. An operation or method is a piece of code that works on those attributes. A class groups attributes and operations into one unit. It is a blueprint from which individual examples are created by supplying concrete values.

Hook: How do you describe a whole family of things without listing every single one by hand? You write one description and stamp out copies.

That one description is the class. It says what data every member will carry and what actions every member can perform. The individual copies then differ only in the values they hold.

16.5.2 Fruit Example

Take a class called Fruit. Within Fruit, there is an attribute name, an attribute color, and an operation cost. Two examples from that blueprint:

  • Left example: name = apple, color = red, cost = 10 dollars
  • Right example: name = mango, color = yellow, cost = 5 dollars

Both apple and mango belong to the same class Fruit, yet you can tell them apart because their attribute values differ. The class name tells you the kind; the attribute values tell you the specific case.

Intuition — blueprint analogy: Think of a class as an architect's blueprint and an object as a house built from it. The blueprint for a two-bedroom house lists walls, doors, and plumbing connections in the abstract. Two houses built from it might be painted red and yellow and sold for different prices, but the wall positions come from the same sheet. Fruit is the sheet: it says every fruit has a name, a color, and a way to compute cost. Apple and mango are the houses: they fill in those blanks with concrete values. The analogy breaks where a physical blueprint cannot enforce behavior — a class also lists the code that calculates or changes values, not just the slots.

Worked — Fruit class apple versus mango: Define class Fruit with attributes name and color and operation cost(). Create example 1 by assigning name to "apple", color to "red"; let cost() return 10 based on its rule. Create example 2 by assigning name to "mango", color to "yellow"; let cost() return 5. Check: both examples respond to the same Fruit name, both have the same attribute slots, both can invoke cost(), but cost() yields different numbers. The sense-check passes: same blueprint, distinct state, distinct result — exactly what a class promises.

Pitfalls: Saying apple is a class. Apple is an object (an instance) of the Fruit class. The class is the generic Fruit description.

16.5.3 Person, Account, Student and Circle Examples

A Person class may hold attributes name, age, gender and operations speak, listen, walk. From that blueprint you can create many persons by varying name, age, and gender, while the operations remain the shared capability of any person.

An Account class may hold attributes accountName, accountBalance with a blue-ink label for data and a separate mark for operations such as withdraw, deposit, determineBalance. Each individual account is produced by giving accountName and accountBalance concrete values.

A Student class may hold attributes name, studentID, age with operations getName, getID. Even if two students share the same name and age, their studentID differs, so they remain distinct objects from the same blueprint.

A Circle class may hold attributes center, radius and operations area, circumference, move. A Rectangle class may hold center, height, width with its own area and circumference. The move idea returns later under inheritance because moving only needs a new center.

Worked — four blueprints at a glance: Person with name = "Asha", age = 30 answers speak() the same way as name = "Ben", age = 22, yet their states differ. Account with accountName = "Savings", accountBalance = 5000 handles withdraw(200) by subtracting from its own balance, while a second account with balance 1200 does the same operation on its own funds. Student with name = "Lee", studentID = 101 is distinct from name = "Lee", studentID = 102 because studentID is the distinguishing state. Circle with center = (2,3), radius = 4 computes area with its own method, while Rectangle with center = (2,3), height = 5, width = 8 uses a different formula — the class determines which formula applies. Final check: in each case, operations are shared, attribute values are per instance.

Visual intuition: Imagine a table where columns are attributes and each row is an instance. The column headers come from the class (name, color, cost for Fruit; center, radius for Circle). Filling a row creates one object. The one-sentence takeaway: the class is the header row; objects are the filled data rows.

Scope: A class describes the shape of data, not the data itself. No memory for attribute values is consumed until you create an object from the class. Declaring a class is like printing a blank form; creating an object is like filling one copy with ink.

16.5.4 Formal View

A class binds data and the code that manipulates it into one unit. Members of a class are its attributes and its member functions. Different sources may call attributes by several names: attributes, member variables, data members, or fields. Operations may be called methods, member functions, or operations — they refer to the same idea. You combine attributes and operations to form the single unit you use as a blueprint.

Formal shape from reference texts: A class is declared with class classname { instance-variables; methods; }. Inside, instance variables are the data (String name, int age, double radius) and each instance keeps its own copy. Methods are the code that reads or changes those variables (void withdraw(int amount), double area()). Together they are the members of the class. In well-written Java, instance variables are reached through methods rather than directly, so that later you can change how the data is stored without breaking outside code. The Box example in the textbooks makes this concrete: a Box class holds width, height, depth and a method volume() that returns width*height*depth instead of letting outside code multiply the fields itself. The Fruit, Person, and Account stories are the same idea with domain-appropriate names.

Q: Can we use the object name directly to work with class members? A: Yes. Once you have an object s1 that is an instance of Student, you can use s1 to reach the attributes and methods of that class, because s1 is that instance. You declare the variable first, as in C you must declare before you use it, and then you use the object name with the dot operator, such as s1.getName() or s1.name. Several students asked this — the mental model is that the object name is the address label for a specific filled-in form, and the dot says "look inside that form".

16.5.5 Why Classes Matter

Real-world: in large Java projects, a class like Student or Account appears as a single file that many parts of the program reuse. Fixing a method in the class fixes the behavior everywhere that class is used. If Account.withdraw once allowed an overdraft bug, correcting that one method repairs every account object in the system without hunting through dozens of copies of procedural code. That single-point fix is the practical payoff of blueprint thinking.

Recap: A class is a blueprint that pairs attributes with the operations that work on them, giving many instances a shared shape but distinct state — apple versus mango, Asha versus Ben, one account balance versus another. Bridge: Blueprints matter only when you build from them. Next we create those buildings — objects and instances — and see how they live in memory.

16.6 Objects and Instances — Concrete Values From a Blueprint

16.6.1 How Objects Are Created

An object is a concrete instance produced from a class by giving all its attributes specific values. The class is the blueprint; the object is the house built from it. Other terms you will see: an instance of a class. They mean the same thing.

Take a class Student whose blueprint holds name, age, ID and the associated operations. To create instances:

  • instance one: name = Mike, age = 25, ID = 1000
  • instance two: name = George, age = 23, ID = 2000

You can keep going and create hundreds or thousands of instances from the same blueprint, as long as the attributes and operations are defined.

Formal creation: In Java you obtain an object in two steps that are usually written as one. First you declare a reference, such as Student s1;. This reserve a label that can point to a Student, but no object yet exists. Then you allocate with new, such as s1 = new Student();, which asks the JVM to reserve memory for a new Student, run its constructor, and return the address. The assignment stores that address in s1. Writing Student s1 = new Student(); simply combines both steps. Each new gives a fresh address with its own copies of name, age, and ID. Giving values like name = Mike then fills that particular copy.

Worked — Student instances Mike and George: Start with class Student that declares String name; int age; int ID;. Execute Student s1 = new Student(); s1.name = "Mike"; s1.age = 25; s1.ID = 1000;. Memory now holds one Student object at some address, say A1, with those three fields filled. Execute Student s2 = new Student(); s2.name = "George"; s2.age = 23; s2.ID = 2000;. Memory now holds a second object at A2 with its own fields. Evaluate s1.name: it reads "Mike" from A1, not "George". Evaluate s2.ID: it reads 2000 from A2. Sense-check: two addresses, two independent states, one shared class description. Creating a third student s3 would add address A3 without touching A1 or A2.

16.6.2 State, Behavior and Identity

An entity has state and behavior. State is the current attribute values for that object. Behavior is the operations you can invoke on it. Each object has an address and takes up memory when it is created and given values.

State, behavior, and identity defined: State is the set of attribute values at a moment in time — for s1, state is Mike-25-1000. Behavior is the set of operations you can ask it to do — for Student, that might be getName(), getID(), speak(). Identity is the fact that each object occupies a distinct place in memory with its own address, even if two objects happen to have identical attribute values. That address is what the reference variable s1 actually holds. You never handle the object itself; you handle a reference that points to it, which is why Box b2 = b1; makes both variables point to the same Box rather than copying the box.

Objects can communicate without knowing each other's internal code or data. The name of the object is enough. If instance1 and instance2 exist, you can write code that refers to one or the other by name, and they can interact through their public operations without exposing private details. This is the client-server view from the crash-course texts: client code requests a service by invoking a method on an object, and the object provides that service.

Visual intuition: Draw two boxes labeled s1 and s2. Each box points with an arrow to its own blob in memory that contains three slots (name, age, ID). The blobs look identical in shape but hold different fill values. The arrows are the references; the blobs are the objects. The one-sentence takeaway: the variable is the arrow, not the blob — copying the arrow copies the pointer, not the contents.

Scope: Identity holds as long as at least one reference points to the object. When no variable points to it any longer, the garbage collector may reclaim its memory automatically. You never need to manually free it.

Pitfalls:

  • Thinking Student s1; already created a student. It only created a label. Until new Student() runs, s1 points to nothing (null) and calling s1.getName() throws a NullPointerException.
  • Thinking assignment copies the object. Student s2 = s1; makes two arrows to the same blob; changing s2.name then appears to change s1.name because both see the same memory.

16.6.3 A Small Class Sketch

Consider a class Dog. It may list attributes for its state and operations for its behavior. Creating an object d1 from Dog means supplying values for those attributes. That d1 then occupies memory and carries its own state distinct from any other Dog object you create. The same pattern repeats for Fruit, Person, Account, and any other class you design. For Dog, think of attributes breed, age, color and behavior bark(), eat(). Doing Dog d1 = new Dog(); d1.breed = "Labrador"; d1.bark(); creates one dog that barks as a Labrador, separate from Dog d2 = new Dog(); d2.breed = "Pug";.

Real-world: in a banking system, each Account object holds a different balance and owner name, yet all of them answer to withdraw and deposit. Creating a new account is just creating a new object from the Account blueprint. A clerk might create Account a1 for one customer with balance 8000 and Account a2 for another with balance 500, and the same withdraw code correctly updates only the targeted object's balance because each object carries its own state.

Recap: An object is a blueprint filled in — a Student with Mike-25-1000 is one filling, George-23-2000 is another — each with its own state, shared behavior, and distinct identity in memory accessed through a reference. Bridge: Objects are powerful, but most Java programs start before any object exists — in a special static method that the JVM calls first.

16.7 First Java Program — Structure and Syntax

16.7.1 The Full Program

The first program is intentionally small. You create a file whose name matches the class name. For a class called First, you save the file as First.java. The structure is:

class First {
    public static void main(String args[]) {
        System.out.println("Hello World");
    }
}

When the program is called, class First is invoked. Execution always starts from main. Inside main, the line System.out.println("Hello World"); directs the program to print Hello World on the console.

Hook: Every Java application, from a phone swipe to a banking backend, starts from this same four-word doorway. What do those four words actually give the JVM?

Worked — Hello World through the structure: Save the text exactly as shown in a file named First.java — capital F, same spelling as the class line class First. Place no other public class in that file. Compile with javac First.java to produce First.class. Run with java First and observe Hello World printed with a newline. Now change only the string to "Hello Java" inside the quotes, save, recompile, rerun, and verify the output changes. Sense-check: if you rename the file to first.java or First.txt, javac still compiles but the convention breaks and later tools like java First look for First.class, which now has a mismatched source name and confuses maintenance.

16.7.2 What Each Word Means

  • class is a keyword that declares a class in Java.
  • public is an access modifier that represents visibility. Making a class or method public makes it visible to all. Java also allows private and protected as other visibility levels. The full role of each modifier is explored later with objects.
  • static is a keyword whose core advantage is that a static method can be invoked without creating an object of its class. How to create objects and when static matters is learned right after you can create objects comfortably.
  • void is the return type of the method. For main, the return type is fixed by the language designers. If you try to change the return type of main itself, you will get an error. For methods you write yourself, you can choose the return type.
  • main represents the starting point of the program. It is invoked by the Java Virtual Machine.
  • String args[] written as String args is used for command line arguments. It appears in every program's main signature and is used when you want to take arguments at the moment you interpret the program. That use is shown in later sessions.
  • System.out.println is a combination of three names: System is the name of a class, out is a field within that class, and println is the method that prints a line. Together they send Hello World to standard output.

Formal meaning of main: public static void main(String args[]) is a contract with the JVM. public means the JVM, which lives outside your class, is allowed to call it. static means the JVM can call it without first doing new First() — essential because no objects exist yet when a program starts, so someone must be able to start without an instance. void means this entry point does not hand a value back to the launcher; it does its job by printing or mutating objects. main is the fixed name the launcher searches for. String args[] is an array of strings that receives any words you type after java First on the command line — for example, java First Alice would give args[0] as "Alice". Inside, System is a predefined class in java.lang, out is its public static field that points to the console output stream, and println is the method on that stream that prints its argument plus a line terminator. The textbook analogy is client-server: your main is the client requesting the System.out service to print.

Visual intuition: Draw a call chain from top to bottom. At the top is the command java First. An arrow drops to First.main (the doorway). Inside main, a horizontal arrow points to System.out.println. The console on the right then shows Hello World with a downward arrow for the newline. The one-sentence takeaway: the JVM knocks on one fixed door, and that door delegates to the printing service.

Scope and rules:

  • One public class per .java file, and the file name must match that class name with correct case. class First must live in First.java, not first.java or MyFirst.java.
  • main must be exactly public static void main(String[] args) or public static void main(String args[]). Other spellings compile as a normal method but java First then reports "Main method not found".

Pitfalls:

  • Changing void to int for main. The language fixes it to void for the entry point; a version returning int is a different method that the JVM will not recognise.
  • Writing System.out.printin with a lowercase L versus capital I, or string in lowercase. Java is fully case-sensitive and will report "cannot find symbol".
  • Including .class or .java when running: java First.class is wrong — use java First.

16.7.3 How to Save and Name

The class holds the entire program. After writing the code inside main, close the method bracket and the class bracket. Save the file as First.java — the class name plus .java. Execution always starts from main, so the JVM looks there first. Use a plain text editor with UTF-8 encoding and ensure the editor does not silently add a double extension like First.java.txt. Check the file manager — the type should be JAVA file, not text file.

Q: What is the return type of the main method? Can we change it? A: For the supplied method main, the return type is void and it is strictly bounded by the language designers. Changing it will cause an error because the JVM looks for exactly that signature. For methods you define yourself, you can choose the return type — for example, a method int add(int a, int b) can return int, while void setName(String s) returns nothing.

Q: Is String args used in every program? A: Yes, String args appears in every main signature. It is used for taking command line arguments when you interpret the program. For example, java First Alice Bob would let args[0] be "Alice" and args[1] be "Bob" inside main. How to pass those arguments at interpretation time is covered in coming sessions. Even if you ignore it today, you keep the parameter so the signature matches what the JVM expects.

Recap: The smallest runnable Java program is a class First with exactly public static void main(String args[]) that delegates to System.out.println. Get the file name, case, and signature identical, and the JVM can start you. Bridge: Source alone never prints. Next we see the two commands that turn that source into bytecode and then into running output. Exam note: Expect to write this skeleton from memory, including the exact phrase public static void main(String args[]) and the placement of System.out.println("Hello World"); with its closing semicolon and braces.

16.8 Compiling, Running and Debugging From the Command Line

16.8.1 Two Steps to Run

After saving First.java, you need exactly two commands:

  • Compile: javac First.java
  • Interpret the bytecode: java First

javac is the name of the Java compiler. When it succeeds, it generates First.class, which is the bytecode. In the file manager, that file appears with type class file. Starting from an empty folder, you see only First.java. After compilation you see First.class added automatically. Then java First uses the interpreter named java to run that bytecode and you see Hello World on the screen.

What each command does: javac First.java reads the source text, parses the class and method syntax, checks types, and emits portable bytecode into First.class. It creates one .class per class in the source — here one file because there is one class. java First does not read .java at all. It starts a JVM, locates First.class via the current directory (the default classpath), loads and verifies the bytecode, then invokes First.main. The name you pass to java is the class name, not a file name, so you never add .java or .class. Success is visible in two places: zero output from javac means no errors, and a new First.class file appears beside the source; success from java is the printed Hello World.

The folder state matters. Before compiling, the folder holds just the source text. After compiling, it holds both the source and the generated bytecode. That visible appearance of a new .class file helps you confirm that compilation succeeded even before you run. Keep source and class files together in the same working directory while learning; packages will later teach you a nested layout.

Visual intuition: Picture the file manager with a before and after snapshot. Before: one icon First.java (text). After javac: two icons — the original plus First.class (class file, binary). After java First: the console window shows the third artifact — the output line Hello World. The one-sentence takeaway: text in, class file out, console out.

Scope: These commands assume the current directory is the one that holds First.java and that the JDK's bin directory is on the system path. If you use packages, the commands grow a directory path, but for a single class in the default package the simple two commands are sufficient.

16.8.2 Live Correction While Compiling

In the demonstration, the file is written in notepad, saved as First.java, then compiled from the command prompt after moving to the directory with cd to the folder that holds the file. The first javac First.java reports an error because System was typed as sysdem with outgroup and println misspelled. Reopening the file, fixing to System.out.println, and running javac First.java again produces no error, which means the file compiled successfully. Going back to the folder then shows First.class has been created. Running java First then prints Hello World.

Worked — Notepad compile, fix sysdem typo, generate First.class, run Hello World: Step 1: Open notepad, type the First program, but deliberately type sysdem.outgroup.println("Hello World");. Save as First.java. Step 2: Open the command prompt, run cd D:\firstProject to move to the folder. Run javac First.java. The compiler prints an error similar to "cannot find symbol: symbol sysdem" and points to that line. Step 3: Return to notepad without changing location, correct the line to System.out.println("Hello World");, save again. Step 4: Run javac First.java once more — this time no output appears, which signals success. Open the folder view and confirm First.class now exists with a newer timestamp. Step 5: Run java First and verify the next line is Hello World. Sense-check: a second run of javac after fixing should not create a console message; the presence of the .class file is the proof.

This sequence shows the edit-compile-observe loop that you will use throughout the course. Every Java fix follows the same cycle: edit the .java text, recompile with javac, confirm the .class updated, rerun with java, observe.

Pitfalls:

  • Saving with hidden extension First.java.txt because notepad added .txt. In the save dialog, choose "All Files" and type the name exactly, or confirm the type column shows CLASS file after compilation.
  • Running javac First without .java. The compiler expects a file name with extension; the launcher java expects a class name without.

16.8.3 Fixing the Path When JDK Is Not Detected

If you installed Java for the first time, your system may not determine the JDK. The symptom is that javac is not recognized. The fix is to set the path.

Worked — Path setting with My Computer, Properties, Advanced, Environment Variables, JDK 9 versus 17 or 18: Symptom: typing javac in a fresh command prompt returns "javac is not recognized as an internal or external command". Fix on Windows: open My Computer, right-click and choose Properties, then Advanced system settings, then Environment variables, then System variables, select Path, click Edit, and append the full path to your JDK's bin folder — for example, C:\Program Files\Java\jdk-17\bin if you installed Java 17, or C:\Program Files\Java\jdk-9.0.4\bin as shown in the lecture's older example. For Oracle JDK 18, the same pattern holds with jdk-18\bin. Click OK to save, close and reopen the command prompt so it reloads the environment, then run javac -version to verify it now prints a version number. Then return to javac First.java and the compile step succeeds. On some installers, the java launcher is placed on the path automatically but javac is not — that is why java -version might work while javac -version does not until you set the path.

Go to My Computer, then Properties, then Advanced system settings, then Environment variables, then System variables, then Path. Add the path to your JDK installation. An example path shown is for JDK 9.0, but you use whatever recent installer you have, for example Java 17 or Java 18 from Oracle. Whichever version you installed, add its bin path to the environment variable so the system can find javac and java.

Real-world: this manual path step is only needed when you run from the command line with notepad. Eclipse hides it, which is why many beginners first run fails in the prompt but succeeds in Eclipse. Knowing the manual step still matters for servers and containers where no IDE is present and you must set PATH or JAVA_HOME yourself.

Q: Will the notepad way of writing programs remain widely used? A: Notepad is a simple text editor with hard coding. Real programmers who are strong at programming can work that way, but Eclipse is more convenient because it shows errors and warnings directly while you write. It displays a yellow warning or a red error at the line and lets you click to see options such as change to print or change to println. That immediate feedback to find and fix minor keyword errors is missing in notepad. The advice is to learn the manual path once so you understand compile versus run, then do daily work in an IDE for productivity.

Recap: javac First.java compiles text to First.class; java First runs that class. A missing javac means the system path to JDK\bin is not set — add it through My Computer → Properties → Advanced → Environment variables → Path and reopen the prompt. Bridge: If the command line teaches you the steps, an IDE teaches you the feedback. Next we let Eclipse do the same work with less typing. Exam note: You should be able to list the path-setting steps in order and recall the two commands javac First.java and java First without reference.

16.9 Eclipse IDE — Integrated Development Environment

16.9.1 What an IDE Provides

Eclipse is a well known Integrated Development Environment (IDE) for writing Java programs. Compared with notepad, where you handle everything manually, Eclipse brings built-in compiler support, project organization, and on-the-fly analysis. Once installed, you do not need to set the path separately. For good practice, you should know both paths: manual notepad with path handling and Eclipse with its integrated tooling.

Hook: If notepad already lets you write Java, why install hundreds of megabytes of IDE? Because an IDE turns a 5-minute typo hunt into a 5-second click.

An IDE is a single program that bundles the editor, compiler, launcher, debugger, and project view. In notepad, you are the build system — you decide where to save, when to run javac, and how to read raw compiler text. In Eclipse, the IDE does that plumbing: it compiles as you type, organizes sources into projects and packages, links the correct JDK, and shows problems inline. The Eclipse console also keeps Hello World output in the same window as your code, so the edit-compile-observe loop stays in one place.

Scope: Eclipse does not change what javac and java do. It simply invokes the same toolchain for you, with the same rules about public static void main and First.java naming. Anything that fails on the command line will also fail in Eclipse — you just see the failure sooner.

16.9.2 Creating a Project and a Class

The flow inside Eclipse is:

  • You see the overall Eclipse console.
  • Go to File, then New, then Java Project. In the field that appears, provide the name of the Java project, for example firstProject. The IDE may suggest starting with a lower case letter. Press Finish. The new project appears on the left side.
  • To add a class, go to File, then New, then Class. Provide the class name First. By default, Eclipse includes a package named demo and prepares the class structure public class First. In notepad you must type all of that yourself.
  • Inside main, write System.out.println("Hello World"); and save. The name of the class is First.

Worked — Eclipse new Java project firstProject, demo package, First class, run Hello World: Step 1: Launch Eclipse and choose a workspace folder. Step 2: File → New → Java Project. In the dialog, type firstProject (lowercase first letter is conventional for project names), keep the default JDK compliance, click Finish. Verify the Package Explorer on the left now lists firstProject with a src folder. Step 3: File → New → Class. In the dialog, ensure Source folder is firstProject/src, Package is demo (type it if not present), Name is First, and the option to generate public static void main is checked. Click Finish. Eclipse creates src/demo/First.java with package demo; public class First { public static void main(String[] args) { } } already filled in. Step 4: Inside the main braces, type System.out.println("Hello World");. Notice Eclipse underlines nothing if correct, and the file saves automatically or on save. Step 5: Right-click the file or press Run → Run As → Java Application, or click Run then Run First.java. In the Console view at the bottom, verify the line Hello World appears. If you view the file system, Eclipse has created bin/demo/First.class as the compiled output, mirroring the earlier javac result but inside the project's bin folder.

Pitfalls:

  • Creating the class in the wrong package. If you leave package blank, the class lands in the default package and later import examples behave differently. The lecture's example uses demo to make the package mechanism visible.
  • Naming the project with capital letters and then being confused by the suggestion. Project names are not class names — they can be lowercase. Only class names must start with uppercase.

16.9.3 Running and Fixing Inside Eclipse

To execute, click Run and then Run First.java. Hello World appears in the output area below.

Eclipse also helps when you make a small mistake. If you write man instead of main, or pri instead of println, it immediately shows a marker. The message might read that the method print is undefined for the type PrintStream and offers a quick fix: change to print or println. Selecting the fix repairs the error in place. In notepad you would only discover such a typo after trying to compile; in Eclipse you see it while typing.

Inline feedback: Eclipse's incremental compiler runs on every save and on small pauses. A yellow bulb means a warning — for example, an unused variable that will not block a run but hints at leftover code. A red squiggle means an error — the program cannot run until it is fixed, such as man not matching any known method. Hovering over the marker shows the compiler message verbatim, and pressing the light-bulb offers quick fixes generated from the compiler's symbol table. The fix is not guessing — it proposes the closest valid name in scope, such as println when you typed pri.

Real-world: teams use Eclipse, IntelliJ, or similar IDEs precisely for this tight feedback, plus built-in build, search, and refactor support. Refactoring a class name in Eclipse renames the file, the class line, and all references together, something a manual notepad edit cannot do safely.

Q: How does program creation in Eclipse differ from notepad? A: In notepad you write every line yourself. In Eclipse the class structure is generated by default when you create a class, the package is included, and the editor marks errors and warnings inline so you can fix them before you try to run. Notepad requires you to manage the file name, the public class line, the package line, and the path; Eclipse scaffolds the first three and links the JDK for the last one. The underlying steps — save .java, compile to .class, run on a JVM — are identical; only the amount you see is different.

Recap: Eclipse is the same Java toolchain with a project-aware editor around it. It creates firstProject/src/demo/First.java, compiles to bin/demo/First.class continuously, and reports typos with immediate yellow warnings and red errors that offer one-click corrections. Bridge: Quick fixes catch spelling slips, but design slips — like exposing raw data — need a principle. Next is the first of the three OOP pillars: encapsulation.

16.10 Encapsulation — Binding Data With the Code That Manipulates It

16.10.1 Core Idea and Access Control

Encapsulation is binding the data with the code that manipulates it. The attributes and operations of a class live together in one unit rather than as disconnected pieces.

Hook: What stops any other class from reaching in and changing your account balance to any number? Encapsulation is the lock on the data.

Two statements capture the intent:

  • The variables or data of a class are hidden from any other class and can be accessed only through member functions of the same class where they are declared.
  • Encapsulation can be achieved by declaring all variables in the class as private and writing public methods in the class to set and get values of those variables.

An access modifier controls how widely a member can be seen. Common choices are private for restricted access and public for visible-to-all access. If you give a getter or setter no explicit modifier, its access is default or package level, which means every class present in the same folder or package can call that method. That fact matters because the getter and setter are meant to sit between an outside caller and the private data.

Access control in detail: Marking a field private int id; means only code inside the same class — the Student class itself — can read or write id directly, even if another class holds a Student object in a variable s1. Marking a method public int getId() means any code that can see a Student object may call it. When you write no modifier, as in int getId(), Java gives it package (default) access — visible to any class in the same package or folder, such as TestStudent when both files sit in demo, but not to classes in a different package. That is why the lecture keeps both classes in the same package while teaching encapsulation; the getter is reachable, but the field is still private and must go through the method.

Visual intuition: Picture the Student object as a safe. The private fields id and name are inside the safe. The public or package methods setId, getId, setName, getName are the keypad on the door. Outside code cannot reach inside the safe; it can only press the keypad. The one-sentence takeaway: the safe wall is private, the keypad is the controlled method path.

Scope: Encapsulation is not the same as security. It is a design discipline that forces all reads and writes through methods so you can later add checks — for example, rejecting a negative age — in one place.

Pitfalls:

  • Declaring fields with no modifier and calling that encapsulated. Package-visible fields are reachable by any class in the same folder — you have not hidden them.
  • Returning a reference to a mutable private field from a getter without copying, which lets callers mutate the private data through the returned reference.

16.10.2 The Student Example in Full

Consider a class named Student with two members, id and name. To enforce encapsulation, both are declared with private:

class Student {
    private int id;
    private String name;

    void setId(int x) { id = x; }
    int getId() { return id; }

    void setName(String s) { name = s; }
    String getName() { return name; }
}

In spoken form: setId receives one argument and assigns that argument's value to id. It is setting the value, so its return type is void. getId takes no assignment argument; it returns the current value of id, so its return type is int, the type of the variable itself. The same pattern repeats for name: setName receives a String argument and assigns it to name; getName returns a String. Initially getName was typed with return type int by mistake; the correction is that it should be String because name is a String.

Worked — Encapsulated Student with private id and name, setId getId setName getName: Step 1: Declare class Student as above with both fields private. Step 2: Define void setId(int x) { id = x; } — when called as s1.setId(5), the parameter x copies the value 5, the assignment id = x stores 5 into the private field of that specific object. Step 3: Define int getId() { return id; } — when called as s1.getId(), it returns the stored 5 to the caller without exposing the field name. Step 4: Define the name pair similarly, ensuring the return type of getName is String, not int. Verify the mistake: if you leave int getName() { return name; } the compiler reports a type mismatch because name is a String. Change to String getName() { return name; } and the file compiles. Sense-check: you can now call s1.setId(5) from TestStudent, but typing s1.id = 5 in TestStudent now fails to compile with "id has private access" — the lock works.

By default, setId, getId, setName, and getName have no modifier written before them, so they are accessible to other classes in the same package. What they reach for, however, is private. Another class in the same package cannot write s1.id directly because id is private, but it can call s1.setId(5) and s1.getId() to work with the value through the method layer. That indirection is the whole point: the data stays hidden, while controlled methods provide the path to read or write it.

16.10.3 Using the Encapsulated Class From Another Class

Create a second class in the same package or folder named TestStudent with public static void main. Inside it:

class TestStudent {
    public static void main(String args[]) {
        Student s1 = new Student();
        s1.setId(5);
        System.out.println(s1.getId());
        s1.setName("Satish");
        System.out.println(s1.getName());
    }
}

In an earlier non-encapsulated version, you might have written s1.id = 253 and s1.name = "Satish" using the dot operator, then printed with System.out.println(s1.id) or s1.name. That style gave the same numeric result but left the fields exposed. With private fields, that direct assignment is no longer possible outside Student. You must call setId with a value such as 5, and that value is assigned to id inside Student. Similarly you assign a name string and later retrieve it with a getter.

Why the dot still matters: The dot operator s1.setId(5) means "start from the reference s1, follow it to the Student object at its address, then invoke the method setId on that object". Before encapsulation, s1.id tried to touch the field directly. After encapsulation, the only legal dot paths are the methods. The object name s1 is still how you specify which student's safe to operate on — s1 versus s2 versus s3.

A separate note made during the session: if you create an object s1 that is an instance of Student itself, then inside the Student class you can reach s1.id directly, because an object of a class can access private members of that same class. If you instead create an object t1 of TestStudent, you cannot write t1.id to reach a student's id — t1 is not a Student. The rule is not about the name after the dot but about which class the object belongs to. Private means "inside this class definition", not "inside this object name".

Worked — Access succeeds inside, fails outside: Inside Student.java, the method void printId(Student s) { System.out.println(s.id); } compiles because the code is inside Student and s is a Student. Inside TestStudent.java, the statement Student s1 = new Student(); System.out.println(s1.id); fails to compile with private access. Change it to System.out.println(s1.getId()); and it compiles and prints the value stored via setId. Sense-check: the class of the code, not the variable name s1, decides legality.

16.10.4 Read-Only and Write-Only Choices

Whether you provide both getter and setter is a design decision.

  • If you want a read-only variable, provide getId as public and omit setId. Whatever value is initialized will then never be modified through the public path.
  • If you want a write-only variable, provide setId and omit getId. Callers can modify the value, but cannot read it back through the class where it lives.

The earlier example showed the full combination with both accessors for both fields. In practice you choose based on the need of the program.

Read-only and write-only by omission: Suppose a Student id should be assigned once at admission and never changed by outside code. Declare private int id; and expose only public int getId() { return id; } with no setter, initializing id via a constructor or a package-private setup method. Outside code can read s1.getId() but cannot call a missing s1.setId. Conversely, a write-only logger might expose public void setLog(String msg) { log = msg; } without a getter so callers can append but not dump the raw log. In many Java beans used by frameworks, both getter and setter are exposed so tools can read and write freely; in domain objects for security or configuration, often only getters are exposed to keep values stable after construction.

Real-world: many Java beans expose every field with both get and set to let frameworks read and write freely, while domain objects for security or configuration expose only getters to keep values immutable after construction. A BankAccount that holds a ledger balance might expose getBalance but no setBalance — the only way to change the balance is through deposit and withdraw methods that preserve invariants such as non-negative balance.

Q: If we make variables private but still allow setting through a public setter, does that defeat the purpose of private? A: No. The private scope still denies direct access from any object of another class. The getter and setter sit as the controlled path. By choosing which accessor to expose and with what visibility, you arrange whether callers can read, write, both, or neither. For example, make getId public and omit setId to make the value read-only after it is set; make setId without getId to make it write-only. Whether to include the getter, the setter, or both depends on the program need and the programmer's design. The earlier demo used the full set of getters and setters to show everything that is possible, but that full exposure is a choice, not a requirement.

Q: We pass a String argument to setName but the return type of getName was written as int. Will that not create a problem? A: Yes. That is a typing error. The return type of getName should be String, matching the type of the variable name. The correction is to change int to String so the method reads String getName() { return name; }. The compiler catches this mismatch because you cannot return a String value where an int return was promised. The fix is one word.

Q: After covering classes and objects, when do we go to the three principles? A: The plan after classes and objects is to cover the first Hello World program and see its structure, then learn the remaining three principles — encapsulation, inheritance, and polymorphism — as the second block. In the lecture this happened after a five-minute break around 75 minutes in, which is why encapsulation, inheritance, and polymorphism feel like a distinct second half. The order is deliberate: you meet data as private, then reuse via inheritance, then flexibility via many forms.

16.10.5 Worked Use With Multiple Objects

Continuing the Student story to show many objects from the same blueprint:

Student s1 = new Student();
s1.setId(253);
s1.setName("Satish");

Student s2 = new Student();
s2.setId(300);
s2.setName("Mike");

// s3, s4, and so on can be added in the same way
System.out.println(s1.getId() + " " + s1.getName());
System.out.println(s2.getId() + " " + s2.getName());

Each object carries its own copy of id and name. The dot operator reaches either the accessor method or the field depending on the access rules, but the encapsulated form replaces s1.id = 253 with s1.setId(253) for code outside Student.

Worked — Multiple Student objects s1 with 253 Satish and s2 with 300 Mike, plus read-only and write-only cases: Execute Student s1 = new Student(); s1.setId(253); s1.setName("Satish"); — memory now holds object A with id 253 and name Satish, reachable through s1. Execute Student s2 = new Student(); s2.setId(300); s2.setName("Mike"); — memory adds object B with id 300 and name Mike, reachable through s2. Now evaluate s1.getId() → 253, s1.getName() → Satish; separately s2.getId() → 300, s2.getName() → Mike. Changing s2 never affects s1. For a read-only variant, create class ReadOnlyStudent { private int id; ReadOnlyStudent(int v){ id=v; } public int getId(){return id;} } — outside code can read id but cannot write it because no setter exists. For a write-only variant, omit the getter. Run System.out.println(s1.getId() + " " + s1.getName()); and verify the console prints 253 Satish on one line and 300 Mike on the next. Sense-check: each arrow (s1, s2) sees only its own blob.

Pitfalls:

  • Forgetting that each object has its own copy. Setting s1.id to 253 does not set s2.id.
  • Adding a public setter for an id that should be stable after construction. If the model says identity never changes, expose only a constructor and a getter.

Recap: Encapsulation hides fields as private and exposes only chosen methods. Controlled access lets you allow read, write, both, or neither per field, and the methods are the only legal dot paths from outside. Bridge: Hiding is about one class. The next pillar is about two classes where one reuses the other's hidden-plus-public shape.

16.11 Inheritance — One Class Acquiring Properties of Another

16.11.1 The Intuition From a Classroom Image

A picture is used to make the idea memorable: an examination is in progress with three students. The student in the blue t-shirt is writing the answer independently. The student in the middle tries to copy something from the student on the left or right. The student on the far side then tries to copy from the middle student. The information available with the parent flows to the child, and an intermediate child can then pass it further. That copying is the everyday image for inheritance: existing capability is reused rather than rewritten.

Intuition — why the copy is disciplined: In the picture, copying is informal and risky. In Java, inheritance is a declared relationship: you say class Student extends Person and the compiler copies the accessible members for you, checks types, and keeps the link visible in the hierarchy. The picture is memorable because it captures flow direction — parent to child — and chaining — child can be parent to another child. The analogy breaks where a student copies answers during an exam; a subclass inherits structure at design time and can then add or refine behavior, not just duplicate text.

About 75 minutes into the session, a short five minute break is taken before starting these three principles, which is why the encapsulation, inheritance, and polymorphism material appears as a distinct second block. That break is a useful landmark: if you recall "before the break was classes and Hello World, after the break was the three pillars", you will never mix the order.

Scope: The picture emphasizes reuse of capability. In real inheritance, a child inherits behavior and structure that are accessible, not every private internal. Private fields of the parent exist in the child object but are not directly reachable without a protected or public accessor.

16.11.2 Definition and Roles

Inheritance is the property by which one class acquires the properties of another. The source is called the parent class, superclass, or base class. The receiver is called the child class, subclass, or derived class. The child inherits certain capabilities from the parent, shown in diagrams with one color for inherited features and another for its own local features. If a parent class has ten features, a child might inherit two of them and add several of its own. The relationship is that the child is a usable extension of the parent.

Formal idea: In Java you write class Child extends Parent { } to establish the link. After that, any code that works with a Parent reference can also work with a Child object where allowed, because the child is a specialization of the parent's type. Inheritance is a top-down classification: general at the top, specific at each step down. The textbook hierarchy — class animal, then subclass mammal, then subclass dog, then subclass Labrador — illustrates the same layering: each subclass adds specifics (type of teeth, breed traits) while retaining general animal attributes (size, growth, breathing) inherited from ancestors. The power is linear growth: a new subclass brings its own handful of attributes while silently carrying all ancestral behavior, so the system grows by addition rather than duplication.

Visual intuition: Imagine a vertical tree where Person sits at the top with four slots: name, age, gender, address. Branching down left is Student and down right is Lecturer. Each child box shows the same top four slots in one color (inherited) plus its own slots — rollNumber, year for Student and staffID, department for Lecturer — in a second color (local). The one-sentence takeaway: write the shared slots once at the parent, and every child automatically carries them in the same color.

Pitfalls:

  • Saying inheritance copies code text. It establishes a type relationship and method dispatch path — the parent code is not duplicated as source text in the child file, but behavior is available at runtime.
  • Confusing "inherits everything" with "can access directly everything". A subclass object contains private parent fields, but direct access to them requires a protected or public parent method.

16.11.3 Person Example — Sharing Common Attributes

Take a Person class that holds attributes common to many people: name, age, gender, and address. A Student class needs those four plus its own local attributes such as rollNumber and year. A Lecturer class needs the same four plus staffID and department. Instead of writing name, age, gender, and address repeatedly in Student and Lecturer, you place them once in Person and let both children inherit them. You then add only the local fields to each child.

Worked — Person with name age gender address reused in Student and Lecturer: Define class Person { String name; int age; String gender; String address; }. Define class Student extends Person { int rollNumber; int year; } and class Lecturer extends Person { String staffID; String department; }. Create Student s = new Student(); s.name = "Aisha"; s.rollNumber = 104;s responds to name even though name was never declared in Student.java — it was acquired from Person. Create Lecturer l = new Lecturer(); l.name = "Kumar"; l.staffID = "E231"; — same inheritance. Now change Person to add a method String greeting() { return "Hello " + name; }. Both s.greeting() and l.greeting() immediately return greetings without editing Student or Lecturer. That edit-once, inherit-everywhere effect is the exact savings counted when the parent has ten features and the child inherits two: you type two less per child. Sense-check: s.rollNumber is accessible on a Student but l.rollNumber is not — local features stay local.

The hierarchy can be extended: Student and Lecturer are children of Person, and further specializations can inherit from them. For example, ResearchStudent could extend Student and inherit both Person and Student traits while adding thesis fields, forming a chain where information flows parent → child → grandchild just like the three students in the picture.

16.11.4 Shape Example — Sharing a Common Method

A Shape class holds an attribute center and a method moveTo(newCenter). A Circle subclass holds center, radius, and methods area, circumference, plus inherited movement. A Rectangle subclass holds center, height, width, and its own area, circumference. The way area and circumference are calculated differs between circle and rectangle. The way moveTo works is the same in both: take the new coordinates and assign them as the center. Instead of writing moveTo twice, you move that method out of Circle and Rectangle and keep it once in Shape. Both children then simply inherit it. The advantage is reuse: write once, use in many children.

Worked — Shape with center and moveTo reused in Circle and Rectangle: Define class Shape { Point center; void moveTo(Point newCenter) { center = newCenter; } }. Define class Circle extends Shape { double radius; double area(){ return Math.PI * radius * radius; } double circumference(){ return 2 * Math.PI * radius; } } and class Rectangle extends Shape { double height, width; double area(){ return height*width; } double circumference(){ return 2*(height+width); } }. Execute Circle c = new Circle(); c.center = new Point(2,3); c.radius = 4; c.moveTo(new Point(5,6));moveTo was never written in Circle, yet the call shifts the same center field that area later uses. Execute Rectangle r = new Rectangle(); r.center = new Point(2,3); r.height=5; r.width=8; r.moveTo(new Point(5,6)); — the identical moveTo code moves a rectangle. Now fix a bug once in Shape.moveTo — for example, add a null check for newCenter — and both shapes gain the fix without a second edit. Contrast with duplicating moveTo in each shape: one fix would need two edits and risks divergence. Sense-check: c.area() uses Math.PI * radius * radius while r.area() uses height times width — differing formulas coexist with a shared movement method.

Real-world: in a graphics toolkit, Shape.moveTo written once fixes movement for every shape that inherits from Shape, so a bug fix in one place repairs all derived shapes. The same holds for a UI toolkit where Component.setVisible sits in the superclass and Button and Label simply inherit visibility control.

Recap: Inheritance is extension by reuse. Put what is common — four Person fields or Shape center plus move — once in the parent, let Student, Lecturer, Circle, and Rectangle acquire it, and keep only what differs locally. Bridge: Reuse gives you many related types. The next pillar asks how one name can correctly serve all of them.

16.12 Polymorphism — Many Forms

16.12.1 Meaning and the Everyday Image

Polymorphism means many forms. The parts poly meaning many and morph meaning form come from Greek. The idea is that a single name can have many forms of use.

A vivid image is used: a character known as Ben10 who has multiple alien forms. Selecting a different form changes what the character can do, yet it remains the same character. In code, the same method name can be written in several forms, and the system picks the right one based on how it is called. That many-forms idea is polymorphism.

Intuition — Ben10 analogy made precise: Ben10 is the interface — one name the viewer remembers. Each alien — Heatblast, Four Arms — is an implementation with its own powers. Pressing the watch and choosing an alien is the call site choosing arguments. The show knows which alien to display from the choice on the watch; the compiler knows which method to invoke from the argument list in the call. The analogy breaks where Ben10's transformation is visual and story-driven; method polymorphism is resolved by formal rules on argument types and counts, not by preference.

Formal view: Polymorphism in Java often appears as "one interface, multiple methods". One general name — such as stack.push, println, or initialize — labels a family of allowed actions. The compiler selects the specific method that matches the situation. That selection can happen at compile time based on argument shape — called overloading — or at runtime based on object type — called overriding with inheritance — but this lecture focuses on the first case because it needs no extra hierarchy to understand.

Visual intuition: Draw a single label initialize at the top, with two arrows down to two boxes. The left box is labeled initialize(int k) and the right box initialize(int k, int l). Call arrows come from two objects both labeled S1 but carrying one versus two arguments, and each arrow lands on exactly one box. The one-sentence takeaway: one name fans out to many implementations, chosen by call shape.

16.12.2 Method Overloading as a Form of Polymorphism

A straightforward form is method overloading. Consider a method named initialize:

void initialize(int k) { /* method one */ }
void initialize(int k, int l) { /* method two */ }

If you create an object S1 of the class and write S1.initialize(k) with a single argument, the one-argument version (method one) is called. If you write S1.initialize(k, l) with two arguments, the two-argument version (method two) is called. The name initialize stays the same; the choice of definition is made automatically from the number of arguments you supply. That automatic selection based on call shape is what we call method overloading, a form of polymorphism. Types, counts, or orders of arguments can drive the selection, but the session focuses on count.

Worked — Polymorphism through method overloading with initialize single argument versus two arguments, Ben10 style: Define a class Configurator { void initialize(int k){ System.out.println("one arg: "+k); } void initialize(int k, int l){ System.out.println("two args: "+(k+l)); } }. Create Configurator S1 = new Configurator();. Call S1.initialize(5); — the compiler counts one argument of type int and binds to the first definition; console shows one arg: 5. Call S1.initialize(5, 7); — count is two ints, so it binds to the second definition; console shows two args: 12. Now change the call to S1.initialize(5, 7, 9) — compilation fails because no three-argument initialize exists, just as the Ben10 watch cannot select an alien that was never designed. For a closer type example, an overload set like void show(int x) and void show(String s) would let S1.show(10) pick the int form and S1.show("Hello") pick the string form from the same name. Sense-check: one object S1, one name initialize, two distinct bodies, correct body reached without any if in your call site.

Scope and limits: Overloading is chosen at compile time from the declared argument types and counts. Changing only the return type without changing parameters is not sufficient to create a distinct overload — the parameters must differ in number, type, or order.

Real-world: Java libraries overload constructors and utility methods so callers need to remember only one name, such as println for many argument shapes. System.out.println() has overloads for int, double, String, Object, and others. You call the same println whether you have println(42) or println("Hello") or println(3.14), and the compiler routes each to the matching body.

Pitfalls:

  • Expecting polymorphism to pick based on what the method returns. It does not — the call's argument shape decides, not the assignment that receives the result.
  • Creating overloads that differ only in names that are too similar to remember. The benefit of one interface is lost if callers cannot guess which argument pattern triggers which behavior; keep overloads few and intuitive.

Recap: Polymorphism means many forms for one name. With method overloading, initialize written twice — once with one argument k and once with two arguments k and l — is two forms of the same idea, and the compiler dispatches the call S1.initialize(...) to the form whose argument count matches. Bridge: Many forms need organization, otherwise one name per form becomes clutter. Packages supply that organization by folding related classes into folders you can import.

16.13 Packages — Organizing Code With Folders and Import

16.13.1 What Packages Are

A package is broadly a directory or folder that organizes classes and files. On a computer, you might create a folder on D drive called firstProject, and inside it another folder called demo. In Java terminology that inner folder is a package. It holds various classes and files that you may want to call from your program.

Hook: With one or two classes, one folder is fine. With three hundred classes, how do you avoid hunting for the right file and colliding names like two different HelloWorld classes?

In Eclipse you create that same structure by choosing File, then New, then Package, giving it a name. The name you give is the package name you will use in code. The crash-course texts put it this way: large programs consist of many classes in multiple packages, and the class files must live in subdirectories whose names match the package names. Writing package demo; as the first line of First.java places First inside demo, and the compiler expects the file to sit at src/demo/First.java inside project firstProject.

Package as namespace: A package name such as demo, classOne, or classroom is a dot-separated namespace that qualifies the class name. Two classes can share the simple name HelloWorld as long as their full names differ — for example, classOne.HelloWorld versus classroom.HelloWorld. The full name is package.Class. The folder layout mirrors the qualified name: package edu.sjsu.cs.cs151.alice corresponds to folders edu/sjsu/cs/cs151/alice under the project base directory. This rule guarantees unique class names across a team and lets the compiler find the right file from its qualified name.

Visual intuition: Draw a file tree with firstProject at the top, branching to src/demo/First.java and src/classOne/HelloWorld.java and src/classroom/HelloWorld.java. Next to each file, write its full name: demo.First, classOne.HelloWorld, classroom.HelloWorld. An arrow from demo.First points to an import line import classOne.*; showing the link. The one-sentence takeaway: the folder path is the package name, written in dots for code and slashes for the file system.

Scope: A package declaration, if present, must be the first non-comment statement in a .java file. A file without any package line is in the unnamed default package, which is fine for tiny examples but not for production code where names can collide.

16.13.2 Importing All Classes From a Package

Suppose a class named HelloWorld is available inside a package named classOne (a folder classOne). Your program lives in a different package, say classTwo. To use the earlier code you need to import it.

To bring every class from classOne into your program, write:

import classOne.*;

import is the keyword that provides the name of the folder or package plus .*. The * means all classes available in that folder become importable. After that line you can write ordinary code that uses those classes if they are public:

HelloWorld H = new HelloWorld();
H.show();

You created an object of HelloWorld and called its method show through the object H.

Worked — Importing all classes with classOne star: Setup: folder src/classOne/ contains HelloWorld.java with package classOne; public class HelloWorld { public void show(){ System.out.println("Hello from classOne"); } }. In src/classTwo/App.java you write package classTwo; import classOne.*; public class App { public static void main(String args[]){ HelloWorld H = new HelloWorld(); H.show(); } }. Compile from the base directory with javac classTwo/App.java. Run with java classTwo.App — the launcher uses the full name because the class is in a package. Console output is Hello from classOne. What happened: import classOne.*; tells the compiler that the short name HelloWorld means classOne.HelloWorld. Without the import, the short name would not resolve and the compiler would report "cannot find symbol: HelloWorld". Sense-check: the import does not insert code — it only lets you omit the package prefix in the rest of the file.

This was demonstrated in Eclipse by showing how to create a package and how it appears as a folder structure in the project explorer. In the Package Explorer, classOne appears as a expandable folder that reveals its classes; writing the import then turns a red unknown-type marker into a resolved reference.

Pitfalls: Thinking import classOne.*; loads code at runtime. It is a compile-time shorthand that tells the compiler how to resolve short names; the class loader still finds the same .class files at runtime whether you used import classOne.*; or wrote the full name classOne.HelloWorld everywhere.

16.13.3 Importing a Single Class From a Package

If you only need one class, you can import that class specifically instead of *.

With a folder named classroom that holds a class named HelloWorld:

import classroom.HelloWorld;

The rest stays the same: you create an object of that class in the normal way and access its methods through the object.

Worked — Importing single class classroom HelloWorld and calling H.show: Setup: folder src/classroom/HelloWorld.java holds package classroom; public class HelloWorld { public void show(){ System.out.println("Hi classroom"); } }. In src/classTwo/App2.java write package classTwo; import classroom.HelloWorld; public class App2 { public static void main(String args[]){ HelloWorld H = new HelloWorld(); H.show(); } }. Compile from the base directory: javac classTwo/App2.java. Run: java classTwo.App2 and see Hi classroom. Contrast the two forms: import classroom.HelloWorld; brings exactly one class, while import classOne.*; brings all. Use the single-class form when you want to make dependencies explicit and to avoid accidentally pulling in a second HelloWorld from another star import.

You can have multiple packages in your Java environment, in your working folder or working directory, and import the respective classes into your program using import for each package you want to use. The order of import lines does not affect execution, but keeping them sorted helps readers see dependencies at a glance.

Real-world: large applications group classes into packages such as com.company.model, com.company.service, and com.company.util so that import com.company.model.* or specific imports keep code organized and collisions low. A model package might hold User, Account, and Transaction; a service package holds the logic that operates on them; a utility package holds helpers. Import lines then document which layer reaches into which.

Scope and name collisions: If you simultaneously import two packages each containing a HelloWorld, a star import for both makes HelloWorld ambiguous — you must then use the full name for one of them, such as classOne.HelloWorld versus classroom.HelloWorld. Specific single-class imports reduce this risk.

16.13.4 How Eclipse Shows Packages

Eclipse makes packages visible as folder trees. Creating a package with File, New, Package places a directory under the project. Writing import classOne.*; or import classroom.HelloWorld; then resolves against that directory view. The IDE marks missing imports as errors, which is another advantage over notepad where a missing import is only seen at compilation. The Package Explorer shows a chain firstProject > src > classOne > HelloWorld.java; the editor underlines an unknown type in red until you add the matching import, then the underline clears immediately. You also get an organizer: Source → Organize Imports will add needed imports and remove unused ones automatically.

Recap: A package is a named folder. Declare it with package name;, mirror it with directories, and bridge into it with import classOne.*; for all classes or import classroom.HelloWorld; for one class, then use the short name and the dot operator as usual. Bridge: With platform, bytecode, environment, classes, objects, program structure, tooling, and the four organizing principles now in place, the chapter's practice checklist becomes the map for what to rehearse before the next lecture.

Exam Guidance Summary

The session does not announce distribution of marks or question patterns for a final exam. Instead it gives practice guidance that directly affects how you should study from the first class.

  • The pre-contact and post-contact session material covers the foundation. Go through that material and the recordings to stay ready before each live session.
  • From the very first class, build a strong connection with program structure. Practicing the small Hello World program and the encapsulation example with getters and setters pays off when later, higher topics are added.
  • Practice both ways: first on the Eclipse IDE, then also by executing the same programs on notepad with the command line. That pair gives you an understanding of how a program is created, how it compiles, how bytecode is generated, and how it is interpreted.
  • Practice material is readily available: searching for Java examples gives many exercises, and an additional document with practice problems may be provided to work from.
  • A good connect with the program structure early makes it quick to grab new material in coming sessions as the course moves toward higher topics.

Exam note: while no specific marks are stated, the emphasis is that the more you practice, the more you enjoy the programming work. Treat bytecode steps, JDK versus JRE versus JVM, class versus object, encapsulation with getter and setter, inheritance with Person and Shape examples, polymorphism with method overloading, and packages with import as the core checklist to be able to write and explain.

Exam note — what to rehearse for this lecture: Be able to write from memory class First { public static void main(String args[]) { System.out.println("Hello World"); } }, name it First.java, compile with javac First.java and run with java First, explain the bytecode chain First.java → First.class → JVM, distinguish JDK (tools including javac and java), JRE (runtime with JVM and libraries), JVM (loader, verifier, interpreter), and JIT (runtime optimizer for hot code), define class versus object with the Fruit apple-red-10 versus mango-yellow-5 and Student Mike-1000 versus George-2000 examples, write the encapsulated Student with private id and name plus setId, getId, setName, getName and show the read-only versus write-only choice, illustrate inheritance with Person name age gender address shared into Student and Lecturer and with Shape moveTo shared into Circle and Rectangle, describe polymorphism as method overloading with initialize(int k) versus initialize(int k, int l), and use import classOne.*; versus import classroom.HelloWorld; to bring a package into your program. Pre-contact and post-contact material and daily practice on both Eclipse and the command line remain the foundation.

Exam pitfalls to avoid: Changing public static void main signature, running java First.java or java First.class, thinking star import loads code at runtime, exposing private fields directly instead of through accessors, and calling a method on a variable that still holds null.

Key Industry Applications

  • Java platform in products: Java's own runtime environment together with its API is the reason Java is described as a platform, not just a language. Any hardware or software environment that lets code run is a platform; Java supplies its own. Vendors port the JRE to servers, laptops, and devices so the same bytecode can ship everywhere.
  • Portable bytecode delivery: Bytecode portability lets a compiled class file built on Windows run on Unix or Mac wherever the JVM is available. The interpreter in the JVM turns bytecode into native actions on each target. Build systems produce JARs once and deploy them unchanged to test, staging, and production.
  • Environment layers in operations: The JDK includes the compiler, interpreter, documentation, JVM, and JRE; the JRE includes the JVM plus libraries; the JVM loads, verifies, and executes bytecode. JIT optimization during interpretation improves speed in long-running applications, which is why teams benchmark after warm-up.
  • Scale and domains: Sun Microsystems' figure of 3 billion devices running Java spans desktop applications, enterprise applications, mobile including Android, embedded systems, smart cards, robotics, games, IoT and web systems. Separate Java modules exist for desktop, web, and mobile work, yet the core class and object model is identical across them.
  • Classes and objects in codebases: Classes as blueprints appear everywhere: Fruit with apple 10 dollars red and mango 5 dollars yellow, Person with name age gender and speak listen walk, Account with accountName accountBalance and withdraw deposit, Student with name studentID and getName getID, Circle with center radius and area circumference. Each object such as Mike 25 ID 1000 or George 23 ID 2000 or Satish 253 shows a distinct state with shared behavior, created with new and reached through references.
  • First program and toolchain: The First program class First { public static void main(String args[]) { System.out.println("Hello World"); } } saved as First.java compiled with javac First.java to First.class and run with java First is the same start that real developers use for the smallest deployable service and the same path that fails when the JDK path is not set.
  • IDE feedback: Eclipse lets you create a Java Project firstProject and a class First in package demo with default structure already filled in, run it to see Hello World, and get immediate yellow warnings or red errors such as method print is undefined for type PrintStream with a one-click fix. Notepad lacks that.
  • Encapsulation as a bean pattern: Encapsulation with private id and name plus public setId, getId, setName, getName is the standard Java bean pattern for hiding data and exposing controlled read or write paths, including read-only by omitting a setter or write-only by omitting a getter. Teams use it with constructors to make identity fields stable after construction.
  • Inheritance for reuse: Inheritance reuse is shown by moving shared attributes like name age gender address into Person for reuse in Student and Lecturer, and by moving moveTo(newCenter) into Shape for reuse in Circle and Rectangle instead of duplicating it. A single bug fix in the parent then repairs every child.
  • Polymorphism via overloading: Polymorphism through method overloading lets a single name initialize with one argument or two arguments dispatch to the matching definition, the same idea that lets Java's own libraries overload constructors and print methods such as println so callers remember one name.
  • Packages at team scale: Packages as directories let you organize firstProject/demo and import with import classOne.* for all classes or import classroom.HelloWorld for one class, a habit that scales to com.company.model and similar namespaces in production code. Explicit single-class imports reduce collisions when two packages share a short name.

OODAP Lecture 16 notes · Introduction to Java and Object-Oriented Programming Foundations

Object Oriented Design, Analysis and Programming Architecture· postgraduate· 2026-08-19

Sections Breakdown

1Java as a Language and as a Platform

Defines platform as a combined hardware-plus-software execution environment and shows why Java is both a language and its own platform via the JRE plus API.

2Bytecode and the Way a Java Program Executes

Explains the compile-to-bytecode then interpret flow First.java to First.class and the portability win of shipping bytecode to any JVM.

3Components of the Java Execution Environment — JDK, JRE, JVM and JIT

Maps the nested environment JDK contains JRE contains JVM, with JIT as the runtime optimizer for hot bytecode.

4Where Java Is Used

Cites Sun's 3-billion-devices reach and surveys domains from desktop and enterprise to mobile Android, embedded IoT, smart cards, robotics, games, and web.

5Classes — The Blueprint Idea

Introduces class as blueprint pairing attributes with operations, illustrated by Fruit apple/mango, Person, Account, Student, Circle, Rectangle.

6Objects and Instances — Concrete Values From a Blueprint

Shows how new allocates an object with its own state, behavior, and identity via references, exemplified by Student Mike 1000 and George 2000.

7First Java Program — Structure and Syntax

Dissects class First with public static void main and System.out.println, plus file naming and signature rules.

8Compiling, Running and Debugging From the Command Line

Demonstrates the two-step javac then java flow, fixing the sysdem typo live, and repairing PATH when javac is not found.

9Eclipse IDE — Integrated Development Environment

Walks through Eclipse project firstProject, demo package, First class scaffolding, Run, and inline warning/error quick fixes versus notepad.

10Encapsulation — Binding Data With the Code That Manipulates It

Defines binding data with code, private fields with accessors, Student id name example, TestStudent usage, and read-only versus write-only design.

11Inheritance — One Class Acquiring Properties of Another

Presents inheritance via classroom copy image, parent/child roles, Person reuse in Student Lecturer and Shape moveTo reuse in Circle Rectangle.

12Polymorphism — Many Forms

Defines poly many morph form and illustrates method overloading with initialize one versus two arguments and Ben10 analogy.

13Packages — Organizing Code With Folders and Import

Treats package as directory, shows import classOne star for all versus import classroom.HelloWorld for one, and Eclipse folder view.

14Exam Guidance Summary

Collects practice guidance: pre-contact material, connecting with program structure early, practicing both Eclipse and command line, and rehearsal checklist.

15Key Industry Applications

Summarizes industry uses of platform, bytecode portability, environment layers, domains, blueprint, toolchain, IDE, encapsulation, inheritance, polymorphism, and packages.

Postgraduate students in Object Oriented Design, Analysis and Programming

Exam Revision Notes

Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.

Java as a Language and as a Platform

Must-know: Platform equals any hardware or software environment where code runs; Java is a platform because it supplies the JRE plus API runtime.

⚠️ Top pitfall: Thinking platform means only operating system — a browser or JVM is also a platform.

Self-check: Why is Java called a platform and not just a language?

Connects to: 16.2, 16.3

Bytecode and the Way a Java Program Executes

Must-know: Java chain First.java --javac--> First.class bytecode --java--> execution; bytecode is portable, JVM is per-platform.

⚠️ Top pitfall: Running java First.java instead of java First, or editing First.class as text.

Self-check: Why does Java use bytecode instead of a direct exe?

Connects to: 16.3, 16.8

Components of the Java Execution Environment — JDK, JRE, JVM and JIT

Must-know: JVM loads verifies executes bytecode; JRE is JVM plus libraries; JDK is JRE plus javac/java/tools; JIT recompiles hot bytecode to native while running.

⚠️ Top pitfall: Calling JVM the compiler; javac is the compiler, JVM is the runtime.

Self-check: Which part do you install to only run programs versus to develop them?

Connects to: 16.2, 16.8

Where Java Is Used

Must-know: Java spans desktop, enterprise, Android mobile, embedded/IoT, smart cards, robotics, games, web via domain modules sharing core classes.

⚠️ Top pitfall: Thinking Java is only Android; enterprise and embedded are equally central.

Self-check: Name three non-mobile domains where Java runs.

Connects to: 16.5, 16.13

Classes — The Blueprint Idea

Must-know: Class groups attributes and methods into one unit; same class yields many objects distinguished by attribute values.

⚠️ Top pitfall: Calling apple a class; apple is an object of class Fruit.

Self-check: Given class Fruit with name and color, why are apple and mango the same class but different objects?

Connects to: 16.6, 16.10

Objects and Instances — Concrete Values From a Blueprint

Must-know: Object is class filled with values via new; each instance has separate state and address, behavior is shared, accessed via reference and dot.

⚠️ Top pitfall: Thinking declaration creates an object or that assignment copies the object.

Self-check: What holds the address — the object or the reference variable?

Connects to: 16.5, 16.10

First Java Program — Structure and Syntax

Must-know: Smallest runnable program is class First with exactly public static void main(String args[]) calling System.out.println; file must be First.java.

⚠️ Top pitfall: Changing void to int for main or running java First.class.

Self-check: Why must main be public and static?

Connects to: 16.8, 16.9

Compiling, Running and Debugging From the Command Line

Must-know: javac First.java compiles to First.class then java First runs; PATH to JDK bin must include javac and java.

⚠️ Top pitfall: Saving as First.java.txt or passing extension to java launcher.

Self-check: What visible change in the folder proves compilation succeeded?

Connects to: 16.2, 16.9

Eclipse IDE — Integrated Development Environment

Must-know: Eclipse scaffolds package and class, compiles incrementally, shows yellow warnings and red errors with quick fixes; underlying steps remain javac then java.

⚠️ Top pitfall: Creating class in wrong package and confusing project name with class name.

Self-check: How does Eclipse differ from notepad in detecting println typo?

Connects to: 16.8, 16.13

Encapsulation — Binding Data With the Code That Manipulates It

Must-know: Encapsulation equals private fields accessed only via methods; omit setter for read-only, omit getter for write-only.

⚠️ Top pitfall: Using package visibility and calling it encapsulated, or mismatching getName return type.

Self-check: Does a public setter defeat private? Why or why not?

Connects to: 16.11, 16.5

Inheritance — One Class Acquiring Properties of Another

Must-know: Inheritance lets child acquire parent properties; shared fields like Person name age gender address and method Shape moveTo live once in parent.

⚠️ Top pitfall: Thinking subclass duplicates source text or can directly reach private parent fields.

Self-check: Why is fixing Shape.moveTo once better than fixing it in both Circle and Rectangle?

Connects to: 16.10, 16.12

Polymorphism — Many Forms

Must-know: Polymorphism many forms; overloading lets same name initialize dispatch by count types or order of arguments.

⚠️ Top pitfall: Expecting return type alone to distinguish overloads.

Self-check: For S1.initialize(k) versus S1.initialize(k,l), which body runs?

Connects to: 16.11, 16.13

Packages — Organizing Code With Folders and Import

Must-know: Package is directory; declare package name; import with * for all or single name; full name is package.Class.

⚠️ Top pitfall: Thinking import loads code at runtime or ignoring collisions when two star imports share a class name.

Self-check: When would you use import classroom.HelloWorld instead of import classOne.*?

Connects to: 16.9, 16.10

Exam Guidance Summary

Must-know: Rehearse full checklist: bytecode steps, JDK JRE JVM JIT, class versus object, encapsulation accessors, inheritance Person Shape, overloading initialize, packages import.

⚠️ Top pitfall: Memorizing definitions without writing Hello World and Student accessors from memory.

Self-check: List the seven checklist items for this lecture without notes.

Connects to: 16.7, 16.10

Key Industry Applications

Must-know: Same concepts power real services: portable JARs, JDK layers, class blueprints, encapsulated beans, reused superclasses, overloaded println, package namespaces.

⚠️ Top pitfall: Treating lecture examples as toy-only; they are the production pattern.

Self-check: Give a production example of inheritance reuse fixing one parent method.

Connects to: 16.11, 16.10

Was this lecture useful?

Loading comments…
🤖

BitsNotes AI Assistant

Subject Notes Assistant

Configure AI Chat

Choose how to access the chatbot
Have your own API key?

Switch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.

🔑 Enter API key above to fetch live models from provider, or enter model name manually.
OpenAI-Compatible API Support

Choose any provider preset (Gemini, DeepSeek, Kimi, GLM, MiniMax, Qwen, OpenAI, Groq, Ollama, etc.) or enter a custom endpoint URL.

Security & Privacy First

Your API key is sent directly from your browser to your specified provider. BitsNotes servers never store or see your key.