Java Arena
Step 2 of 5

One class, many types

Step 1's Box is one class, and every box chooses its own type. This step shows boxes of more types, a shorter way to create them, and the one kind of type that can't go in the angle brackets.

Parameter and argument

In public class Box<T>, T is the type parameter. In Box<String>, String is the type argument: the type that T stands for in that box. It's the same pair of words as for methods: a method has a parameter, and each call gives it an argument. A class has a type parameter, and each use of it gives a type argument.

The diamond

Box<String> pegs = new Box<String>("tent pegs"); names String twice. Java can work out the second one from the variable's type, so you can leave it out and keep only the angle brackets:

Box<String> pegs = new Box<>("tent pegs");

The empty <> is called the diamond, after its shape. You've written it since module 13, in new ArrayList<>(). It works wherever Java can see which type is needed: in a variable's declaration, as here, and also in return new Box<>(...) in a method whose return type is, say, Box<String>. From here on, this module writes the diamond.

Leave out the angle brackets completely, as in new Box("tent pegs"), and you get an old form from before Java had type parameters. javac compiles it, but it adds a note that the program "uses unchecked or unsafe operations", because it can no longer check the types. Write at least the <>.

Any class or interface will do

A type argument can be any class or interface: one of Java's own, one of yours, even a type with a type argument of its own:

Main.java
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        Box<Double> paint = new Box<>(2.5);
        Box<PowerTool> drill = new Box<>(new PowerTool("cordless drill", 1.8));
        Box<ArrayList<String>> camping = new Box<>(new ArrayList<>());
        camping.getContent().add("tent");
        camping.getContent().add("lantern");

        System.out.println(paint.getContent() * 2 + " liters of paint");
        System.out.println(drill.getContent().getName() + ", " + drill.getContent().getKilos() + " kg");
        System.out.println(camping.getContent().size() + " things: " + camping.getContent());
    }
}
Box.java
public class Box<T> {
    private T content;

    public Box(T content) {
        this.content = content;
    }

    public T getContent() {
        return this.content;
    }

    public void setContent(T content) {
        this.content = content;
    }
}
PowerTool.java
public class PowerTool {
    private String name;
    private double kilos;

    public PowerTool(String name, double kilos) {
        this.name = name;
        this.kilos = kilos;
    }

    public String getName() {
        return this.name;
    }

    public double getKilos() {
        return this.kilos;
    }
}
Output
5.0 liters of paint
cordless drill, 1.8 kg
2 things: [tent, lantern]
  • For drill, a Box<PowerTool>, getContent() returns a PowerTool, so the PowerTool's own methods can be called on it.
  • Box<ArrayList<String>> is a box whose T is ArrayList<String>. Its getContent() returns the list itself, not a copy, so add puts the tent and the lantern into the list in the box. Module 33's HashMap<String, ArrayList<String>> nested types the same way.
  • In new Box<>(new ArrayList<>()), both diamonds are worked out from the variable's type.

Integer, not int

Module 13 showed that a list can't hold ints. A type argument can't be a primitive type at all, for your classes or Java's:

Main.java
public class Main {
    public static void main(String[] args) {
        Box<int> chairs = new Box<>(12);
        System.out.println(chairs.getContent());
    }
}
Box.java
public class Box<T> {
    private T content;

    public Box(T content) {
        this.content = content;
    }

    public T getContent() {
        return this.content;
    }

    public void setContent(T content) {
        this.content = content;
    }
}
What javac prints
Main.java:3: error: unexpected type
        Box<int> chairs = new Box<>(12);
            ^
  required: reference
  found:    int
1 error

A type argument must be a reference type (module 22): a class, an interface, even an array type, never a primitive type. That's what javac's required: reference means. For a primitive type, use its object partner, its wrapper class:

primitive type type argument
int Integer
double Double
boolean Boolean
char Character

That's why it's List<Integer>, never List<int>. Java converts between the two by itself, as it does with lists: new Box<>(12) for a Box<Integer> turns 12 into an Integer, and int chairs = box.getContent(); turns it back into an int. It converts only between a primitive type and its own partner, though: a Box<Double> takes 2.0, but not 2.

Your task

Challenge 1 of 3

The storeroom's app keeps three boxes: the number of screws left, the liters of paint left, and whether the box of fuses is still sealed. Fill in the three type arguments. The program prints:

The fuses are still sealed
210 screws
1.75 liters of paint

Challenge 2

A scout troop packs for a camping trip. Box is the class from this module. Look at the types, and at which list each box holds. What does this program print?

Challenge 3

The storeroom keeps screws in several boxes, each a Box<Integer> holding how many screws it has. Box.java is ready. In Main.java, write two methods:

  • total(ArrayList<Box<Integer>> boxes), which returns the number of screws in all the boxes together
  • fullest(ArrayList<Box<Integer>> boxes), which returns the box with the most screws, the first of them if several have the most. The list has at least one box.

The check runs:

ArrayList<Box<Integer>> boxes = new ArrayList<>();
boxes.add(new Box<>(120));
boxes.add(new Box<>(450));
boxes.add(new Box<>(80));
System.out.println(total(boxes));
Box<Integer> most = fullest(boxes);
System.out.println(most.getContent());
most.setContent(0);
System.out.println(total(boxes));

and expects:

650
450
200