Session 1 · Programming Technology

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.

14 min readThe course and its three assignmentsAnt and Maven projectsEncapsulation and thisReferences vs primitivesA Queue on an ArrayListA 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.

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).

Part 1 · Java and OOP recapclasses and objectsUML relationshipscollections, genericsfiles, exceptionsAssignment 1classes + a data filePart 2 · GUI programsSwing basicsmodel–view separationboard gamesAssignment 2a board game in SwingPart 3 · graphics and datagraphics, animationdatabases (JDBC)sprite games, level filesAssignment 3animated game + databaseComputer lab test at the end of the semester
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.

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.

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.

NetBeans Ant project – People, Queue, CalcPeople/build.xmlthe buildnbproject/IDE settingssrc/people/← packagePeople.javamain()Person.javaMaven project – Grades, and later projectsGrades/pom.xmlthe buildsrc/main/java/com/mycompany/grades/← packageGrades.javamain()Student.javasrc/test/java/JUnit tests
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).

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).

Person- name : String- age : int+ Person(name, age)+ getName() : String+ setName(name)class – the blueprintheap – the objectsPerson objectname "Doug" · age 31Person objectname "Anne" · age 42instance ofstack – main()p1a referencep2a reference
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.

Person.java – private state, public methods

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.

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

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
changeName(p2) – a reference is copiedp2in mainpin changeNamePersonname "Anne" → "Frank"Two references, one object:main sees the new name.changeInt(i) – a value is copiedi = 5in mainparam = 11in changeIntcopy of 5param += 6 changesthe copy onlyTwo separate ints: main's i stays 5.To change it, 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.

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.

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).

0"a"1"b"2"c"3"d"4"e"pop()data.remove(0)push("e")data.add(e)frontbackafter remove(0) every element shifts one index to the front
Fig. 5 · A queue on top of an ArrayList: in at the back with add, out at the front with remove(0).

Queue.java – the core

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)

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.");
    }
}

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).

JFrame"Calculator"JMenuBarcontent paneBorderLayoutsetJMenuBargetContentPaneJMenu "Calc"numPanel · WESTBoxLayout, Y_AXISbuttonPanel · EASTGridLayout(5, 1)JMenuItem "Exit"3 × JTextFieldoperand1, operand2, result5 × JButton+ − * / ^
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.

CalcGUI.java – building the tree

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).

click on +the userJButtonfires ActionEventCalcActionListeneroperation = "add"parse bothDouble.valueOfsetTextresult fieldactionPerformed(e)not a numberNumberFormatExceptioncaught → JOptionPane error dialogThe window stays usable:bad input is a message, not a crash.
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.

CalcGUI.java – the listener, an inner class

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

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));

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.

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.

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.

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.
ExampleWhat it shows
Peopleobjects and references, passing objects vs ints
Queuea class wrapping an ArrayList, a text menu loop
CalcJFrame, panels and layouts, an inner-class listener, input validation
Gradesa Maven project; maximum selection and filtering over a list