Creating classes and objects
Writing your first class with fields, making objects with new, and reading and writing their state.
Finished reading?
Mark this session so you can track where you are.
Writing your first class with fields, making objects with new, and reading and writing their state.
Finished reading?
Mark this session so you can track where you are.
Last session we drew the blueprint and talked about cookies. This session we actually pick up the cutter and press out the cookies. You will write your own class from a blank file, build real objects from it, and watch their fields fill in one by one.
new, and read and write their fields with the dot.new. You also have variables, types, and arrays. That is all you need. We will not write any behavior heavier than reading and setting fields yet.Pick something concrete. We will model a student. A student hasa name, an age, and a grade-point average. Those three things are the student's state, the data that belongs to it. In a class, each piece of state is written as a field: a variable that lives inside the object instead of inside a method.
public class Main { public static void main(String[] args) { System.out.println("The Student class is defined below."); }} class Student { String name; int age; double gpa;}The Student class is defined below.
Read the Student block carefully, because the shape is the whole point. The keyword class says “I am about to describe a kind of thing”. Then a name, Student, with a capital letter by convention. Then, inside the braces, three field declarations. Each one is a type followed by a name, just like declaring a variable, but with no value attached and no method around it. That is a field.
A field is a variable that belongs to the object. Every
Studentobject you build will carry its ownname, its ownage, and its owngpa.
The class on its own builds nothing. It is a description sitting there, waiting. To get a real student you use new, exactly as you saw last session. Then you reach into the fresh object with the dot and set each field.
public class Main { public static void main(String[] args) { Student s1 = new Student(); s1.name = "Mara"; s1.age = 19; s1.gpa = 3.6; Student s2 = new Student(); s2.name = "Theo"; s2.age = 21; s2.gpa = 3.9; System.out.println(s1.name + ", age " + s1.age + ", gpa " + s1.gpa); System.out.println(s2.name + ", age " + s2.age + ", gpa " + s2.gpa); }} class Student { String name; int age; double gpa;}Mara, age 19, gpa 3.6 Theo, age 21, gpa 3.9
Press Run and step through it slowly. Watch the object panel. The first new Student() makes an object whose fields are empty placeholders. Then s1.name = "Mara" fills one in, s1.age = 19 the next, and so on, and you can see each field light up as it is written. The second new Student() makes a completely separate object, and filling its fields never touches the first one. Two cookies from one cutter.
That dot is doing two different jobs depending on which side of the = it sits on. On the left, s1.age = 19 writes into the object: it sets the age field belonging to s1. On the right, inside the println, s1.age reads the same field back out. Write to set, read to use. The dot always means the same thing underneath: reach into this one object and point at one field inside it.
new Student()Student object and hand it back.s1.name = "Mara"name field of the object s1 points at.s1.name (in an expression)name field of that object.s2 after its own news1 never changes it.Student starts with a capital and s1 does not. Java does not force this, but everyone follows it: class names are Capitalized, variables holding objects are lowercase. When you read code later, the capital letter is your instant signal “this is a type, a blueprint” rather than “this is one thing”.Here is a question that catches people. The instant new Student() runs, but before you have assigned anything, what is in name? What is in age? They are not garbage, and they are not undefined. Java gives every field a fixed default value the moment the object is born. Run this and read each line of output.
public class Main { public static void main(String[] args) { Student s = new Student(); System.out.println("name: " + s.name); System.out.println("age: " + s.age); System.out.println("gpa: " + s.gpa); System.out.println("enrolled: " + s.enrolled); }} class Student { String name; int age; double gpa; boolean enrolled;}name: null age: 0 gpa: 0.0 enrolled: false
Step through and watch the object panel before any printing happens: the fields already have values sitting in them. The whole-number type age starts at 0. The decimal type gpa starts at 0.0. The boolean enrolled starts at false. And name, which is a String, starts at null.
That last one deserves a moment. nullis a special value that means “points at no object at all”. A Stringfield is not a number or a true/false, it is a reference to a text object somewhere, and until you give it one, it points at nothing. So its default is the “nothing here yet” value, null, and printing it shows the word null.
name that is null looks harmless until you try to use it as if it were real text. Asking a null for its length or its letters fails at runtime with a complaint that you used an object that is null. The cure is simple: set your fields to real values before you lean on them. We will meet a clean, automatic way to do that in a moment.s.name, s.age, s.gpa one line at a time works, but it is easy to forget one and leave a null or a 0 behind. Constructors let you fill every field at the moment of new, in one step, so an object is never born half-built. And encapsulation will later stop outsiders from writing nonsense like a negative age into your fields at all. You do not need either yet. Just notice the rough edge; we smooth it next.Now the idea that quietly runs underneath everything above. When you write Student s1 = new Student(), it is tempting to picture the whole student living inside s1, the way an int lives inside an int variable. That picture is wrong, and getting it right now saves you real confusion later.
The object, with its name and age and gpa, lives off in memory on its own. The variable s1 does not contain it. s1 holds a referenceto it, which you can think of as the object's home address. The variable holds the address; the object lives at that address. When you write s1.age, Java follows the address to the object and then reads the field there.
This sounds like hair-splitting until you copy one variable into another. Watch what happens when we do exactly that.
public class Main { public static void main(String[] args) { Student a = new Student(); a.name = "Mara"; a.age = 19; Student b = a; b.age = 20; System.out.println(a.name + " is " + a.age); System.out.println(b.name + " is " + b.age); }} class Student { String name; int age;}Mara is 20 Mara is 20
Look hard at the object panel as you step. The line Student b = a does not build a second student. There is only ever one object on the heap. It copies the address in a into b, so now a and b both point at the same object. They are two names for one thing. So when b.age = 20 runs and you then read a.age, you get 20 as well. Both lines print Mara is 20, because both variables are looking at the very same student.
A variable of a class type holds a reference, an address, not the object. Copy the variable and you copy the address, so both names now reach the one object behind it.
int x = 19; int y = x; y = 20; leaves x at 19, because y got its own copy of the number. Objects are different: the value being copied is the address, not the student, so both variables end up at the same student. This is the single biggest surprise for newcomers, and now you have seen it before it bit you.Try each one yourself first, then open the answer.
Book class that has a title, a number of pages, and a price. Use sensible Java types.Student class with String name; int age; double gpa;, a fresh object is made with Student s = new Student(); and nothing else. What do s.name, s.age, and s.gpa hold right now?s1.gpa = 3.6; and then later System.out.println(s1.gpa);, the same text s1.gpa appears twice. Is it doing the same job both times?Student b = a; and b.age = 20;, why does a.age also read 20?Take these away. They continue exactly what we just did.
Car class with fields String make;, String model;, and int year;. In main, build two different cars with new, set all three fields on each, and print a line describing each car. Confirm the two cars are independent.boolean electric; field to your Car but do not set it on one of the cars. Print that car's electric field. Before you run it, write down what you expect, then check whether you were right and say why.a, set its fields, then write Car b = a; and change b.year. Print a.year and b.year. Then, separately, build a truly second car with its own new Car() and show that changing one of those does not affect the other. In one or two sentences, explain the difference between the two situations.