Classes
Goals
- Understand the purpose of classes.
- Learn how to create classes and chain constructors.
- Know the difference between static and instance variables of a class.
Concepts
- allocate
- Application Programming Interface (API)
- arguments
- class
- constant value
- constructor
- constructor chaining
- default constructor
- deallocate
- delegate
- design pattern
- encapsulation
- garbage collector
- instance
- instance variable
- instantiate
- no-argument constructor
- object-oriented
- parameter
- package access
- static initializer block
- static variable
Language
class
new
this
static
Preview
Lesson
Objects
One of the central features of Java is that it is an object-oriented language. In Java, setting aside the primitive types such as int
and double
, all variables are references to objects. You don't care where in heap memory these objects are stored; you just care when they are created and how long they “live”.
Objects help to design a program by grouping together data (variables) and functionality (methods). This grouping of things together is called encapsulation.
Creating New Objects: new
All objects are associated with a class, which is like a template for creating objects. To create an object, you'll use the keyword new
along, followed by the name of the class of the object to create, which has a pair of parentheses attached. The object this creates is what we call an instance of the class. When you create a class instance, Java will allocate or set aside memory for it. You can create as many instances of a class as you wish, until you run out of memory or other resources. As the examples below illustrate, you can think of creating an instance of a class is like baking a new cookie, if you have a Cookie
class. You'll learn how to create a Cookie
class later on in this lesson.
All instances of a class are not equal; they can encapsulate different values, which is what makes objects useful. When you create an instance of a class, many times you can pass values to the class. For example, Java has an error class IllegalArgumentException
, which you can use to indicate an error related to a value you receive from a different area of the program. You'll learn how to use exceptions in another lesson, but the important thing to note here is that when you create an instance of this class, you may specify a message that explains the error. This value will be stored only with that one instance of IllegalArgumentException
, not with other instances of the class.
Destroying Objects
Most of the time (although not always) you will assign a reference to the newly created object to some variable so that you can use it later. You can afterwards assign the object reference to more than one variable, as you learned in a previous lesson.
You also learned that you never have to explicitly tell Java to destroy an object. The JRE has a garbage collector which will automatically destroy an object (and deallocate its memory, making it available for other objects) when there are no more references to that object. Remember that reference variables, like all other variables, disappear when they go out of scope. If a reference variable goes out of scope and it was the only variable references some object, that object will eventually be garbage-collected and destroyed.
Classes
To define your own custom class, you'll use the class
keyword, as you did in your “Hello World” program. Usually a class is defined in a separate file with the same name as the class, with a .java
extension. The directory of the .java
file must reflect the package indicated inside the file.
The class above does nothing; it does not encapsulate any data. It merely serves as a template for creating instances of Cookie
. In itself this may not appear very useful, but it is significant that you can now have several instances of objects that are different, yet still share a commonality in that they are instances of the same class with a particular name. How might you use a class that holds no data and defines no functionality?
Instance Variables
Once way an object can encapsulate data is by having its own variables. When a class declares variables in the body of the class, the variable storage is replicated each time you create an instance of the class. That is, each class instance will hold variables independently from each other.
To directly access an object's instance variable, use the .
character between the name of the variable referencing the instance and the name of the object's instance variable, such as myCookie.luckyNumber
.
Constructors
If you'd like to pass information to the object at the moment it is created or “constructed”, you'll need to define a constructor in the class. The constructor looks similar to a method, but does not indicate a return type—not even void. A constructor always has the same name as the class. Constructors are most often used for initializing instance variables of the new object, but can perform almost any function they wish. The JVM automatically calls a class' constructor when new
indicates that a new class instance should be created. You can declare an instance variable as final
without initializing it, as long as it is initialized in a constructor.
Like methods constructors allow a list of parameters. A constructor with no parameters is usually called no-argument constructor, because you do not have to pass any arguments when creating the object using that constructor. The JVM calls the appropriate constructor automatically based upon the arguments you pass when you instantiate the class using new
. Consider a class used to encapsulate the two-dimension coordinates in a single geometric point.
Instance variables can be references to objects, and you can initialize them using constructors as well. The FortuneCookie
class could itself encapsulate both a String
and a Point
.
The class may have several constructors to choose from, and you may find that you have very similar code that is repeated in several constructors in order to initialize the class. In order to minimize duplication, you can use constructor chaining, in which one constructor delegates to another constructor by passing control to it. Because it is one constructor rather than the JVM invoking another constructor, this does not result in the creation of multiple instances; it is merely a way to cut down on repetition and consolidate common functionality. To invoke another constructor, use the keyword this
along with the appropriate arguments in parentheses that match the parameters of the constructor being chained.
You can continue chaining constructors several times in turn if you want.
this
The keyword this
can also act like a variable that, when used inside the class, refers to the class instance itself. Remember that code outside a class can access an instance variable by using the form fortuneCooke.luckyNumber
. Inside the FortuneCookie
class, this
can be used in the same way. A constructor in the examples above, for instance, could use either luckyNumber
or this.luckyNumber
to access the instance variable of the same class. Most of the time the use of this
is optional and only makes for verbose code, although it might be useful in some cases to clarify what the program is doing.
Most often the this
reference is used when a local-scope variable is hiding an instance variable. If a local variable has the same name as a class' instance variable, normally the local variable “wins” and “hides” the instance variable. The keyword this
, which holds a reference to the current instance, can be used to “get around” the local variable and access the one at the class level.
One place you'll see local variables hiding instance variables is during initialization, when local variables are passed as parameters to a constructor. It is not uncommon to have initialization parameters as the same name as instance variables. If so, you'll need to use this
to distinguish between the two variables.
Class Variables
As you have seen, the instance variables of a class only exist after a class has been instantiated, and then they exist as a separate copy for each object instance. A class variable, on the other hand, exists as soon as the class itself is created by the JVM, and is shared among all object instances. Indeed a class variable exists even if no instances of the class has been created. A class variable is declared using the static
keyword.
An extremely common use of class variables or “static variables” is that, when they are combined with final
, they effectively make a constant value (sometimes referred to as just a “constant”) which can be accessed without creating an instance of a class. Constants can also be access before the class instance is completely initialized, such as in the middle of a constructor. For example, a constant value can define the default value for a constructor so that several constructors can use it through constructor chaining.
Some class variables require complicated initialization, making it difficult or impossible to set the variable at the same time you declare it. One should not use a constructor to initialize static variables, as a constructor will be called each time the class is instantiates—and indeed may never be called. Instead Java provides for a static initializer block, which might be considered analogous to a “class constructor”. A static initializer block is the keyword static
following by a set of braces {
and }
in the body of the class, and is executed when the JVM loads the class for the first time before it is accessed.
Review
Summary
The following example class encapsulates the x
and y
values of a two-dimensional geometric point. You can use an array of Point
instances to keep track of multiple points.
Gotchas
- There is no reliable way to be notified before an object is destroyed, so don't even try.
finalize()
is not guaranteed to work for this purpose. - If a constructor parameter has the same name as an instance variable, don't forget to use
this
to distinguish between the two.
In the Real World
- Sometimes classes are declared for the sole purpose of collecting a series of constant values as
static final
variables. Such classes may never have a reason to be instantiated.
Think About It
- Am I writing the same code over and over in several constructors? Maybe I should chain the constructors.
- If I am using constructor chaining, does it make sense for a particular parameter to have a “default”? Or is this parameter one that should be required to be given before the class instance can be valid?
- Is there a value I am using multiple times? If the value represents the same thing semantically, I may want to store it in a constant for reuse, perhaps even between classes.
Self Evaluation
- What does it mean to say that a class “encapsulates” data?
- What is garbage collection?
- When is an object destroyed and its memory deallocated?
- What is the difference between parameters and arguments?
- How can you simulate “default arguments” in a Java constructor?
- How might you store useful values such as default constructor parameters in a way they can be reused?
Task
Improve the Booker application to replace the parallel arrays with a single array of Book
class instances.
- Store the array of books as a constant array of the
Booker
application class.- Store the books in a static variable.
- Use a static initializer block to initialize the
Book
instances.
- Use constructor chaining at least once.
- Use at least one constructor default value.
- Make sure a default value “makes sense” for a particular parameter.
- Not all parameters will have a “default” value, and will require the developer to supply some value.
- Do not use visibility modifiers, even if you know what these are.
- Do not use class instance methods, even if you know what these are.
- Modify your static method for printing a book to accept a
Book
instance as a parameter.
Create a bundle of the Booker repository and send it to your teacher.
See Also
- Classes (Oracle - The Java™ Tutorials)
- Creating Objects (Oracle - The Java™ Tutorials)
- Understanding Class Members (Oracle - The Java™ Tutorials)