﻿# Recap: classes, objects and a first window

> What the semester builds towards, how a Java project is laid out, and the object-oriented basics underneath everything: private state, references and parameter passing, a class around a list, and a first Swing calculator with a listener that validates its input.

Source: https://laszlonemes.com/university/programming-technology/oop-recap · Author: László Nemes

Session 1 · Programming Technology

What the semester builds towards, how a Java project is laid out, and the object-oriented basics underneath everything: private state, references and parameter passing, a class around a list, and a first Swing calculator with a listener that validates its input.

14 min read `The course and its three assignments` `Ant and Maven projects` `Encapsulation and this` `References vs primitives` `A Queue on an ArrayList` `A first Swing window`

This first session is a warm-up. We look at what the course is about, how a Java project is laid out in the IDE, and we refresh the object-oriented basics every later session builds on: a class with private state, objects and references, and what really happens when you pass an object to a method. At the end we build a small window – a calculator – because from the middle of the semester everything you write will have a GUI.

> **The one idea to take away:** a variable of a class type never holds an object, it holds a *reference* to one. Most surprises in Java – a list that changed "by itself", a method that changed the caller's object but not the caller's int – are this one fact.

After this session you can

- explain how the semester is built up and what each of the three assignments expects
- create a project in the IDE and find your way around an Ant and a Maven project layout
- write a class with private fields, a constructor, getters and setters, and use this correctly
- predict what a method can and cannot change in its caller, for objects and for primitives
- build a small Swing window with panels, layouts, buttons and a listener that validates input

## What this course is about

Programming Technology is about writing *whole programs* in Java, not single algorithms. The first third of the semester is a recap of object-oriented programming – classes, UML diagrams, collections, files and exceptions – and ends with the first assignment. The other two thirds are GUI programs: first board games built from Swing buttons, then animated games that draw their own graphics and keep a leaderboard in a database (Fig. 1).

> **Fig. 1** · Each part ends in an assignment (beadandó), and each assignment reuses everything before it: the GUI games still need classes, collections, files and exceptions.
>
> *Diagram:* The semester in three parts. Part 1 recaps Java and object-oriented programming and ends in the first assignment, a console program reading a data file. Part 2 is Swing GUI programming and ends in a board game. Part 3 adds graphics, animation and a database and ends in an animated game. A computer lab test closes the semester.

The order matters. A GUI program is an object-oriented program with a window on top – if the classes underneath are messy, the window only makes the mess visible. That is why we spend the first weeks on getting the model right, before a single button appears.

In your assignment

**Three assignments, presented in person**

Every assignment is presented in person: you run it and explain how its parts work. Code you can't explain doesn't count as yours. Plan for that from the first line: name things clearly, keep each class small enough to explain in a minute, and know why every class exists.

## Projects in the IDE

The examples are NetBeans projects; any Java IDE (NetBeans, IntelliJ IDEA, VS Code with the Java extensions) can open them. You will meet two layouts (Fig. 2). The first examples are NetBeans **Ant** projects – the build is described in `build.xml` and the IDE keeps its settings in `nbproject/`. Later examples are **Maven** projects – the build, the Java language level and the libraries (for example JUnit) are listed in `pom.xml`, and the project opens the same way in every IDE and builds from the command line.

> **Fig. 2** · In both layouts a package is a folder: the class people.Person lives in src/people/Person.java. Maven separates the program (src/main/java) from its tests (src/test/java).
>
> *Diagram:* Two project layouts. The early NetBeans examples are Ant projects: build.xml, an nbproject folder and the sources under src, one folder per package. Maven projects describe the build in pom.xml, keep the sources under src/main/java and the tests under src/test/java, and open the same way in any IDE.

Good to know

**Use a current LTS JDK**

Install a current long-term-support JDK and point the IDE at it. If the IDE complains that the project's source level is higher than your JDK, the fix is installing a newer JDK – not lowering the level in the project settings.

In your assignment

**Start the assignment as a Maven project**

A Maven project opens on my machine exactly as on yours, whichever IDE either of us uses, and the JUnit tests have an obvious place in `src/test/java`. Pick a package name that says what the program is (`race`, `game.model`) – not the IDE default.

## Classes and objects

A **class** describes what its objects know (fields) and what they can do (methods). An **object** is one concrete instance, created with `new`, with its own copy of every field. The `People` example has one class, `Person`, and creates two people from it (Fig. 3).

> **Fig. 3** · One class, two objects. The objects live on the heap; p1 and p2 are small variables in main that only point at them.
>
> *Diagram:* The Person class is a blueprint with private fields name and age and public methods. Two Person objects live on the heap, one with name Doug and age 31, one with name Anne and age 42. The variables p1 and p2 in main do not contain the objects, they hold references to them.

Person.java – private state, public methods

```java
public class Person {

    private String name;   // state is private …
    private int age;

    public Person(String name, int age) {
        this.name = name;  // this.name = the field, name = the parameter
        this.age = age;
    }

    public String getName() {   // … and reachable only through methods
        return name;
    }
}
```

The fields are `private`: nothing outside the class can read or overwrite them directly. This is **encapsulation**, and it is what lets a class guarantee its own rules. If `age` must never be negative, the only place that can break this rule is the class itself – so it is the only place you have to check.

- **field** – A variable that belongs to an object (name, age). Each object has its own.
- **constructor** – Runs once, at new. Its job is to put the object into a valid starting state.
- **getter / setter** – Methods that read / change one field. Write only the ones you actually need.
- **`this`** – The object the method is running on. this.name is the field, plain name is the nearest variable.
- **static** – Belongs to the class, not to an object – main and helper methods such as changeName.

Common mistake

**The setter that does nothing**

When a parameter has the same name as a field, the parameter *shadows* the field. Without `this.` the assignment copies the parameter onto itself, compiles fine and changes nothing.

```java
public void setName(String name) {
    name = name;        // assigns the parameter to itself – the field never changes
}

public void setName(String name) {
    this.name = name;   // correct: this.name is the field
}
```

In your assignment

**Getters yes, setters only when the task needs them**

IDEs generate a getter and a setter for every field in two clicks, and then any code anywhere can put your object into a nonsense state. In the assignment, decide per field: is it fixed after construction (a name, a species) – then no setter, and make the field `final`. Does it change by the rules of the task (water, distance, position) – then a method named after the rule (`move()`, `drink()`) is better than a raw setter.

## References and parameter passing

Java passes every argument **by value**: the method gets a copy. What is copied depends on the type. For an `int`, the copy is the number. For a `Person`, the copy is the reference – so the method's parameter points at the very same object as the caller's variable (Fig. 4).

People.java – the three helper methods

```java
public static void changeName(Person p) {
    p.setName("Frank");      // changes the object p points to
}

public static void changeInt(int param) {
    param += 6;              // changes the local copy only
}

// in main:
changeName(p2);              // p2's name is now "Frank"
changeInt(i);                // i is still 5
i = increaseInt(i);          // the way to "change" an int: return the new value
```

> **Fig. 4** · Left: changeName gets a copy of the reference, so both point at Anne's object and the rename sticks. Right: changeInt gets a copy of 5 and changes the copy.
>
> *Diagram:* Java always passes a copy. For an object parameter the copy is a reference, so changeName's p and main's p2 point to the same Person and the rename is visible in main. For an int parameter the copy is the value itself, so changeInt changes its own param to 11 while main's i stays 5.

The same rule explains a lot of later surprises. Put a `Person` into two lists and rename it through one list – the other list "changes" too, because there was only ever one object. Assign `p = new Person(…)` inside a method – the caller's variable does not move, because only the copy was reassigned.

Common mistake

**Comparing objects with ==**

`==` on references asks "is this the same object?", not "do these look the same?". Two `String`s with the same letters can be different objects. Compare strings (and your own value classes) with `equals`; session 3 comes back to `equals` for your own classes.

## A class around a list: the Queue

The `Queue` example wraps an `ArrayList<String>` and exposes only queue operations: `push` at the back, `top` and `pop` at the front, `isEmpty`, `empty`. The list is private, so nobody can insert into the middle of the queue – the class decides what a queue may do (Fig. 5).

> **Fig. 5** · A queue on top of an ArrayList: in at the back with add, out at the front with remove(0).
>
> *Diagram:* The Queue class keeps its strings in a private ArrayList. push appends at the back with add, pop takes the element at index 0 with remove(0), and every remaining element moves one index to the front.

Queue.java – the core

```java
public class Queue {

    private final ArrayList<String> data = new ArrayList<>();

    public void push(String e) {
        data.add(e);                 // join at the back
    }

    public String pop() {
        if (data.isEmpty()) {
            return null;             // nothing to take
        }
        return data.remove(0);       // leave at the front
    }
}
```

A text menu drives it: a loop prints the options, reads a number and dispatches with a `switch`. The reading is done by `Console`, a small helper class that ships with the example (`readInt`, `readLine`, … wrapped around `System.in`). The loop runs until the user picks "exit" – a pattern you will use for any console program.

TestQueue.java – the menu loop (condensed)

```java
boolean exit = false;
while (!exit) {
    printMenu();
    int choice = Console.readInt("Pick one: ");
    switch (choice) {
        case 1 -> queue.push(Console.readLine("String to store: "));
        case 3 -> System.out.println("Removed: " + queue.pop());
        case 7 -> exit = true;
        default -> System.out.println("No such menu item.");
    }
}
```

Good to know

**Returning null is a design decision**

`pop()` on an empty queue returns `null`. The caller then has to remember to check, and if it doesn't, the program fails later with a `NullPointerException` far from the cause. In session 4 you will see the alternative: throw an exception right where the problem is.

## A first window: the calculator

The `Calc` example is a calculator with two operand fields, a result field and five buttons (+, −, *, /, ^), plus a menu with an Exit item. A Swing window is a tree: a `JFrame` contains panels, panels contain components, and each panel has a **layout manager** that decides where its children go (Fig. 6).

> **Fig. 6** · You never place components by pixel: you choose a layout per panel – a column of fields, a 5 × 1 grid of buttons – and nest the panels.
>
> *Diagram:* The calculator window is a tree of components. The JFrame holds a menu bar with the Calc menu and its Exit item, and a content pane with BorderLayout. The content pane holds numPanel on the WEST side, a vertical BoxLayout of three text fields, and buttonPanel on the EAST side, a 5 by 1 GridLayout of five buttons.

CalcGUI.java – building the tree

```java
frame = new JFrame("Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

numPanel = new JPanel();
numPanel.setLayout(new BoxLayout(numPanel, BoxLayout.Y_AXIS));   // a column
numPanel.add(operand1);
numPanel.add(operand2);
numPanel.add(result);

buttonPanel = new JPanel(new GridLayout(5, 1));                 // 5 rows, 1 column

frame.getContentPane().add(BorderLayout.WEST, numPanel);
frame.getContentPane().add(BorderLayout.EAST, buttonPanel);
frame.pack();             // size the window to its contents
frame.setVisible(true);   // only now does it appear
```

A button does nothing until something *listens* to it. Each button gets its own `CalcActionListener` object that knows which operation it stands for. When the button is clicked, Swing calls the listener's `actionPerformed` (Fig. 7).

> **Fig. 7** · One click, start to end. The error path is part of the design: invalid input becomes a dialog, and the program keeps running.
>
> *Diagram:* A click on the plus button makes the JButton fire an ActionEvent. Swing calls actionPerformed on the CalcActionListener registered for that button, which parses both operand fields and writes the sum into the result field. If a field does not hold a number, Double.valueOf throws NumberFormatException, which the listener catches and shows in an error dialog.

CalcGUI.java – the listener, an inner class

```java
class CalcActionListener implements ActionListener {   // inner class of CalcGUI

    private final String operation;

    CalcActionListener(String operation) {
        this.operation = operation;
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        try {
            double op1 = Double.valueOf(operand1.getText());   // fields of the outer CalcGUI
            double op2 = Double.valueOf(operand2.getText());
            result.setText(String.valueOf(compute(op1, op2)));
        } catch (NumberFormatException e) {
            JOptionPane.showMessageDialog(frame, "Invalid number!", "Error",
                    JOptionPane.ERROR_MESSAGE);
        }
    }
}
```

`CalcActionListener` is an **inner class**: it is declared inside `CalcGUI`, and its objects can use the fields of the `CalcGUI` object that created them – that is how it reaches `operand1` and `result`. For a one-line reaction, such as Exit, a lambda is shorter than a named class.

Wiring the listeners

```java
JButton addButton = new JButton("+");
addButton.addActionListener(new CalcActionListener("add"));   // one listener object per button
buttonPanel.add(addButton);

// a one-off listener does not need a named class – a lambda is enough
exitMenuItem.addActionListener(e -> System.exit(0));
```

Common mistake

**Calculating in the window class**

In this first version the arithmetic lives inside the GUI class. For four operations that is readable, but the calculation can't be tested without clicking, and the class mixes two jobs. Session 5 moves the arithmetic into a separate model class, and from then on that is the expected structure.

## Practice

Build these three steps in one new project. They are small on purpose – the goal is to write a clean class and the two standard loop patterns without looking anything up.

Task 1

**A Student class**

A student has a name, a nationality and a grade average. Create a new project and write the `Student` class with a constructor, getters and setters.

**Shape of the class:**

Three private fields, one constructor that sets all three, then the accessors.

```java
public class Student {
    private String name;
    private String nationality;
    private double gradeAverage;

    public Student(String name, String nationality, double gradeAverage) { … }

    public double getGradeAverage() { return gradeAverage; }
    // … the other getters and setters follow the same pattern
}
```

Task 2

**Best and worst average**

Keep several students in an `ArrayList<Student>`, then print the student with the best and the one with the worst grade average. Use the maximum-selection pattern (maximumkiválasztás), not a sort.

**Maximum selection:**

Start from the first element and walk the list once, keeping the best so far. The minimum is the same loop with the comparison flipped – both fit in the same loop.

```java
Student best = students.get(0);          // assume the first one is the best …
for (Student s : students) {
    if (s.getGradeAverage() > best.getGradeAverage()) {
        best = s;                            // … and correct the assumption
    }
}
```

**What if the list is empty?:**

`students.get(0)` throws on an empty list. Check `isEmpty()` first and print a message instead.

Task 3

**Who gets a scholarship?**

A student gets a scholarship if their average is at least 4.0. List those students.

**Filtering:**

One loop, one condition. Name the limit as a constant so the rule is readable and changes in one place.

```java
for (Student s : students) {
    if (s.getGradeAverage() >= SCHOLARSHIP_LIMIT) {   // a named constant, not a magic 4.0
        System.out.println(s.getName());
    }
}
```

Task 4

**Extend the calculator**

Add a sixth operation to `Calc` – the remainder (%) – and make division by zero show an error dialog instead of printing `Infinity`.

**Where the changes go:**

The grid needs one more row, one more button with its own listener, and one more case in the `switch`. For division by zero, check `op2 == 0` before dividing and show the same kind of dialog the `NumberFormatException` branch shows.

## Summary

- The semester goes from an OOP recap (assignment 1) through Swing board games (assignment 2) to animated games with a database (assignment 3).
- A class keeps its state private and offers methods; the constructor makes a valid object; this.field disambiguates a shadowed field.
- Variables of class type hold references. Java passes a copy of the reference – the method can change the object, never the caller’s variable.
- Wrap a collection in a class to expose only the operations that make sense (Queue: push, top, pop).
- A Swing window is a tree of components with a layout per panel; buttons do work through listeners, and invalid input becomes a dialog, not a crash.

| Example | What it shows |
| --- | --- |
| People | objects and references, passing objects vs ints |
| Queue | a class wrapping an ArrayList, a text menu loop |
| Calc | JFrame, panels and layouts, an inner-class listener, input validation |
| Grades | a Maven project; maximum selection and filtering over a list |
