Student: OK professor we really need to talk about something. You keep accidentally saying
class when you mean record, or saying “class or record”, and you won’t tell me what a class is. Can we please get that defined?Prof: Hah! It’s time, you’re right. So a
class is the same thing as a record, but missing some stuff that we need to write ourselves if we want to program like we have with records.Student: What stuff?
Prof: Kind of a lot of things, actually. I’ll take some of them piece by piece, and it might take a few conversations to fill it all in. But we will be telling very few lies by the end.
Student: Very few, eh?
Prof: Let’s dive in. So, let’s take a record we know and love, the
Point. We’re going to slowly change it into a class. First we’ll just change the keyword from record to classStudent: Ummm that’s just an error.
Prof: Indeed. In
class declarations, we don’t put the field definitions in parentheses like that. We put them in the class body:Student: Why? That seems longer.
Prof: It’s just how classes work! Now let’s try to create a
Point:Student: Huh? Why an error? You made it correctly.
Prof: Actually, I didn’t! The default constructor for a
class takes no arguments, and all the fields are left as the placeholder or default value for their type:Student: Wait… so are you going to say we have to write a constructor?
Prof: That’s right! We have to write our own constructors in a class definition:
Student: That’s weird-looking. It uses
this? What’s the difference between this.x and x?Prof: Great question. Let’s look at a memory diagram during the call to the constructor:
Names (the stack)
new Point(4.0, 5.0) on @1001x = 4.0y = 5.0top level
Heap
@1001: Point[x=0.0 4.0, y=0.0]Prof: So we’ve got a freshly-created object,
@1001. It has x and y fields, they started as the placeholder values 0.0. The arguments to the constructor were 4.0 and 5.0 – that’s the parameters x and y. Then the body of the constructor changes the field values to hold the values of the parameters.Student: So
this.x = x changes a value on the heap?Prof: That’s right, this is a new operation we haven’t seen called field update. It lets us change the value of a field of an object stored on the heap, just as you said. So the constructor does two field updates, and then the object is in the state we are used to after using a
record canonical constructor. You can think of it as the record filling in this code for you, just based on the fields you put in parentheses after the record name.Student: Cool! Wait, so why bother using a class? Records just save typing, right?
Prof: Well, there’s more to learn here, this is just the first of the things records do for us, but also we will need to talk more to explore their restrictions.
Practice
This Point class has three constructors, and each one prints something.
class Point {
double x;
double y;
Point(double x, double y) {
System.out.println("two doubles");
this.x = x;
this.y = y;
}
Point(double both) {
this(both, both);
System.out.println("one double");
}
Point() {
System.out.println("nothing");
}
}What does each one print?
new Point(1.0, 2.0) prints new Point(3.0) prints new Point() prints new Point(3) prints After
Point c = new Point();, what is c.x?0.0Point()never setsx, so it keeps the placeholder value for adouble.3.0Point()doesn’t call another constructor, so no value is ever put inx.- It doesn’t compileIt compiles: a field that is never set keeps its placeholder value. (A
finalfield would be a different story.)