Constructors, UML class diagrams, arrays of objects
Constructors that prepare the object the moment it is born, the default constructor rule, constructor overloading, reading and drawing a UML class diagram, keeping objects in an array and in an ArrayList. The skeleton of the final writing questions.
Last week you first created an empty object with new and then filled it with set methods. That means a few lines for every object, and if you forget to set one field the object is left half-done. A constructor does this job at the moment the object is born. This week you will also learn the standard way of drawing classes on paper (the UML class diagram) and keeping many objects in an array or an ArrayList.
Golden rules:
- The name of a constructor is the name of the class, and it has no return type.
- If you write no constructor, Java adds a no-argument one; if you write one, it does not.
- Constructors can be overloaded too. The arguments decide which one runs.
- In UML,
-is private,+is public; the type comes after the name. - Creating an array of objects does not create objects. A separate
newfor each element.
Constructor
class Student {
private String name;
private double gpa;
public Student(String n, double g) { // no return type
name = n;
setGpa(g); // the validation is in the setter
}
public Student(String n) { // second constructor (overloading)
name = n;
}
public String getName() { return name; }
public double getGpa() { return gpa; }
public void setGpa(double g) {
if (g >= 0.0 && g <= 4.0) gpa = g;
}
}
Student s1 = new Student("Deniz", 3.2);
Student s2 = new Student("Ece");
System.out.println(s1.getName() + " " + s1.getGpa());
System.out.println(s2.getName() + " " + s2.getGpa());
Student s3 = new Student("Can", 5.7);
System.out.println(s3.getName() + " " + s3.getGpa());
Deniz 3.2
Ece 0.0
Can 0.0
new Student("Deniz", 3.2)first makes room for the object, puts the fields at their defaults, then runs the two-parameter constructor.- s2 was created with the one-parameter constructor; since gpa was not touched, it is 0.0.
- In s3, 5.7 is out of range; it was rejected because the constructor calls the setter. If you had written
gpa = g;directly in the constructor, an invalid value would have gotten in.
Order of execution
class Book {
private String title;
private int pages = 100; // field initial value
public Book(String t) {
System.out.println("constructor: pages=" + pages);
title = t;
pages = 250;
}
public String describe() { return title + " " + pages; }
}
// main: Book bk = new Book("Java"); System.out.println(bk.describe());
constructor: pages=100
Java 250
The order: fields get their default value → the initial values in the field declarations are assigned (pages = 100) → the body of the constructor runs.
The default constructor rule
If you wrote no constructor in the class, Java adds an invisible, empty, no-argument default constructor. That is why new Account() worked last week. But the moment you write a single constructor, this addition is not made:
class Car {
private String model;
public Car(String m) { model = m; }
}
// main: Car c = new Car();
Main.java:7: error: constructor Car in class Car cannot be applied to given types;
Car c = new Car();
^
required: String
If you want both new Car() and new Car("Egea"), you write both constructors yourself.
PITFALL · writing void on a constructor.
public void Pen(String c)is not a constructor, it is an ordinary method whose name is the same as the class. Since the class has no real constructor left,new Pen("red")does not compile (required: no arguments), whilenew Pen()compiles but color stays null.
UML class diagram
UML (Unified Modeling Language) is the standard way to show a class on paper before turning it into code. In the exam it is asked in two directions: “Write the Java code of this diagram” or “Draw the diagram of this class”.
+--------------------------------------------+
| Student | ← class name
+--------------------------------------------+
| - name : String | ← fields (attributes)
| - gpa : double |
+--------------------------------------------+
| + Student(n : String, g : double) | ← constructors
| + Student(n : String) |
| + getName() : String | ← methods (operations)
| + getGpa() : double |
| + setGpa(g : double) : void |
+--------------------------------------------+
| UML | Java | Meaning |
|---|---|---|
- name : String | private String name; | private field |
+ getName() : String | public String getName() | public method, returns String |
+ setGpa(g : double) : void | public void setGpa(double g) | parameter name : type |
+ Student(n : String) | public Student(String n) | constructor, no return type written |
When writing code from a diagram, go in order: first the class header, then a private field for each - line, then a public method header and body for each + line. When turning code into a diagram, go in the opposite direction: put the fields in the top compartment, the constructors and methods in the bottom one. Do not skip the getters and setters; they need to appear in the diagram.
Watch two things when converting: in UML the type comes after the name (name : String), in Java before (String name). The return type of a method is at the very end in UML, and before the name in Java.
Arrays of objects
Student[] group = new Student[3];
System.out.println(group[0]);
group[0] = new Student("Ali", 2.8);
group[1] = new Student("Bora", 3.6);
group[2] = new Student("Cem", 3.1);
double sum = 0;
for (Student s : group) sum += s.getGpa();
System.out.printf("%.2f%n", sum / group.length);
System.out.println(best(group).getName());
null
3.17
Bora
group ──► [ ref | ref | ref ]
│ │ │
▼ ▼ ▼
Ali Bora Cem (each one is a separate new)
new Student[3] creates an array but puts no Student in it: three null references. A separate new Student(...) is needed for each element. If you call a method on an element that is not filled:
Student[] partial = new Student[2];
partial[0] = new Student("Z", 1.0);
for (Student s : partial) System.out.println(s.getName());
Z
NullPointerException
It crashed in the second iteration because the second element is null. If the array is not completely full, do an if (s != null) check in the loop.
The best method is the object version of the max pattern; its full code is in the question bank. The difference is this: we keep not the largest value but the object that has that value, and we return it.
Objects with ArrayList
If you do not know how many objects there will be, ArrayList is more convenient:
class Product {
private String name;
private double price;
private int quantity;
public Product(String n, double p, int q) { name = n; price = p; quantity = q; }
public String getName() { return name; }
public double getPrice() { return price; }
public int getQuantity() { return quantity; }
public void setQuantity(int q) { if (q >= 0) quantity = q; }
public double subtotal() { return price * quantity; }
}
public static Product findByName(ArrayList<Product> items, String name) {
for (Product p : items) {
if (p.getName().equals(name)) return p;
}
return null; // not found
}
// in main:
ArrayList<Product> cart = new ArrayList<>();
cart.add(new Product("Kalem", 12.5, 4));
cart.add(new Product("Defter", 40.0, 2));
cart.add(new Product("Silgi", 7.5, 3));
double total = 0;
for (Product p : cart) total += p.subtotal();
System.out.println(total);
System.out.println(findByName(cart, "Defter").getPrice());
System.out.println(findByName(cart, "Cetvel"));
cart.remove(0);
System.out.println(cart.size() + " " + cart.get(0).getName());
152.5
40.0
null
2 Defter
When searching for objects, names are compared with equals. When nothing is found, the counterpart of -1 in int arrays is returning null. The calling side must know that null may come back and check for it.
Common mistakes
| Wrong idea | The truth |
|---|---|
| The return type of a constructor is void | No return type is written |
Even if I write a constructor, new X() always works | It does not work if you did not write the no-argument constructor |
A constructor is called as obj.Student(...) | Only with new Student(...) |
| Validation in a constructor is unnecessary | Validate by calling the setter |
UML name : String → Java name String | String name |
In UML + is private | + is public, - is private |
new Student[3] creates three students | Three null references |
| In an array of objects every element is filled | Check: if (s != null) |
Search with p.getName() == name | equals |
| If a search finds nothing, return -1 (with objects) | Return null |
Test yourself
Exam-style questions. Solve them on paper first, then reveal the answer.
Point has two constructors: Point() sets x and y to 0, Point(int x0, int y0) stores the given values. What is printed?
Point pt = new Point(3, 4);
Point pt2 = new Point();
System.out.println(pt.getX() + pt.getY() + " " + pt2.getX());Show answer
The constructor is chosen by the number of arguments (overloading). pt.getX() + pt.getY() is two ints: 3 + 4 = 7, then String concatenation. pt2 uses the no-argument constructor, so 0.
The Student(String n, double g) constructor calls setGpa(g), which accepts only values from 0.0 to 4.0. What is printed?
Student s = new Student("Mert", -1.0);
System.out.println(s.getGpa());Show answer
The constructor leaves the validation to the setter: -1.0 is rejected, gpa stays at the default 0.0. Writing the validation in one place (the setter) and calling it from the constructor is a good habit.
What is printed?
class Tracer {
private int value;
public Tracer(int v) {
value = v * 2;
System.out.println("built " + value);
value++;
}
public int getValue() { return value; }
}
// in main:
Tracer tr = new Tracer(5);
System.out.println(tr.getValue());Show answer
11
new Tracer(5) runs the constructor: value = 10, built 10 is printed, value becomes 11. Then getValue returns 11. A constructor runs line by line like an ordinary method.
What is printed?
Student[] arr = new Student[4];
arr[1] = new Student("A", 2.0);
arr[3] = new Student("B", 3.0);
int created = 0;
for (Student s : arr) if (s != null) created++;
System.out.println(created + " " + arr.length);Show answer
new Student[4] opens four reference slots, all null; it creates no Student object. Only two of them were given objects with new. The length of the array is still 4.
What is printed?
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("X", 2.5));
list.add(new Student("Y", 3.5));
list.add(new Student("Z", 3.0));
int count = 0;
for (Student s : list) if (s.getGpa() >= 3.0) count++;
System.out.println(count + " " + list.get(1).getName());Show answer
Those with a GPA of 3.0 and above are Y (3.5) and Z (3.0): 2. list.get(1) returns a Student; you can call .getName() directly on it: Y.
Product(String n, double p, int q) stores name, price and quantity; subtotal() returns price * quantity. What is printed?
Product pr = new Product("Su", 5.0, 3);
pr.setQuantity(pr.getQuantity() + 2);
System.out.println(pr.subtotal());Show answer
The quantity becomes 3 + 2 = 5. 5.0 * 5 = 25.0 (the result is a double because price is a double).
What is printed?
Student a = new Student("Tan", 2.0);
Student[] two = {a, a};
two[0].setGpa(3.9);
System.out.println(two[1].getGpa() + " " + a.getGpa());Show answer
Both elements of the array are references to the same object. However you change it, there is a single object: all three see 3.9.
Account2(String o, double b) sets the balance; withdraw subtracts only if amount > 0 && amount <= balance, otherwise prints Insufficient funds. What is printed?
Account2 acc = new Account2("Deniz", 100);
acc.withdraw(-50);
acc.withdraw(30);
acc.withdraw(500);
System.out.println(acc.getBalance());Show answer
Insufficient funds
70.0
-50 is not positive → message. 30 is valid → 70. 500 > 70 → message. The int 100 was given to the constructor but widened because the parameter is a double; the balance is printed as 70.0.
Class Car has only the constructor public Car(String m). Does Car c = new Car(); compile?
Show answer
Java adds the no-argument default constructor itself only if the class has no constructor at all. The moment you write a constructor, this gift is gone. For new Car() you must write the no-argument constructor yourself.
What is wrong with this class? What happens with new Pen("red")?
class Pen {
private String color;
public void Pen(String c) { color = c; }
}Show answer
void makes it a method, not a constructor; new Pen("red") does not compileA constructor has no return type, not even void. void Pen(...) becomes an ordinary method with the same name as the class. Since the class has no real constructor left, Java adds the no-argument default constructor; the error for new Pen("red") is: required: no arguments.
Read the UML class diagram and write the class header, the fields and the constructor in Java.
+----------------------------------------+
| Course |
+----------------------------------------+
| - code : String |
| - credits : int |
+----------------------------------------+
| + Course(code : String, credits : int) |
| + getCode() : String |
| + getCredits() : int |
+----------------------------------------+Show answer
- is private, + is public. In UML the type is written after the name with a colon; in Java it is written first. The return type comes after the parentheses.public class Course { private String code; private int credits; public Course(String c, int cr) { code = c; credits = cr; } public String getCode() { return code; } public int getCredits() { return credits; }}
Write a static method best(Student[] list) that returns the student with the highest GPA (assume the array is full and not empty).
Show answer
The object version of the max pattern: we keep not the largest value but the object that has the largest value. The return type is Student.public static Student best(Student[] list) { Student top = list[0]; for (Student s : list) { if (s.getGpa() > top.getGpa()) top = s; } return top;}Test: Ali 2.8, Bora 3.6, Cem 3.1 → best(group).getName() = Bora.
Verification: All outputs were run with JDK 26 (verify/SEN1001/W11.java and W11b.java; the classes Student, Book, Product, Point, Tracer, Account2, Course and Pen). The constructor errors were obtained with javac under verify/SEN1001/err/ctor/.