OCP Oracle Certified Professional Java SE 17 Developer Study Guide. Jeanne Boyarsky
class Chick { public void Chick() { } // NOT A CONSTRUCTOR }
When you see a method name beginning with a capital letter and having a return type, pay special attention to it. It is not a constructor since there's a return type. It's a regular method that does compile but will not be called when you write new Chick()
.
The purpose of a constructor is to initialize fields, although you can put any code in there. Another way to initialize fields is to do so directly on the line on which they're declared. This example shows both approaches:
public class Chicken { int numEggs = 12; // initialize on line String name; public Chicken() { name = "Duke"; // initialize in constructor } }
For most classes, you don't have to code a constructor—the compiler will supply a “do nothing” default constructor for you. There are some scenarios that do require you to declare a constructor. You learn all about them in Chapter 6.
Reading and Writing Member Fields
It's possible to read and write instance variables directly from the caller. In this example, a mother swan lays eggs:
public class Swan { int numberEggs; // instance variable public static void main(String[] args) { Swan mother = new Swan(); mother.numberEggs = 1; // set variable System.out.println(mother.numberEggs); // read variable } }
The “caller” in this case is the main()
method, which could be in the same class or in another class. This class sets numberEggs
to 1
and then reads numberEggs
directly to print it out. In Chapter 5, you learn how to use encapsulation to protect the Swan
class from having someone set a negative number of eggs.
You can even read values of already initialized fields on a line initializing a new field:
1: public class Name { 2: String first = "Theodore"; 3: String last = "Moose"; 4: String full = first + last; 5: }
Lines 2 and 3 both write to fields. Line 4 both reads and writes data. It reads the fields first
and last
. It then writes the field full
.
Executing Instance Initializer Blocks
When you learned about methods, you saw braces ({}
). The code between the braces (sometimes called “inside the braces”) is called a code block. Anywhere you see braces is a code block.
Sometimes code blocks are inside a method. These are run when the method is called. Other times, code blocks appear outside a method. These are called instance initializers. In Chapter 6, you learn how to use a static
initializer.
How many blocks do you see in the following example? How many instance initializers do you see?
1: public class Bird { 2: public static void main(String[] args) { 3: { System.out.println("Feathers"); } 4: } 5: { System.out.println("Snowy"); } 6: }
There are four code blocks in this example: a class definition, a method declaration, an inner block, and an instance initializer. Counting code blocks is easy: you just count the number of pairs of braces. If there aren't the same number of open ({
) and close (}
) braces or they aren't defined in the proper order, the code doesn't compile. For example, you cannot use a closed brace (}
) if there's no corresponding open brace ({
) that it matches written earlier in the code. In programming, this is referred to as the balanced parentheses problem, and it often comes up in job interview questions.
When you're counting instance initializers, keep in mind that they cannot exist inside of a method. Line 5 is an instance initializer, with its braces outside a method. On the other hand, line 3 is not an instance initializer, as it is only called when the main()
method is executed. There is one additional set of braces on lines 1 and 6 that constitute the class declaration.
Following the Order of Initialization
When writing code that initializes fields in multiple places, you have to keep track of the order of initialization. This is simply the order in which different methods, constructors, or blocks are called when an instance of the class is created. We add some more rules to the order of initialization in Chapter 6. In the meantime, you need to remember:
Fields and instance initializer blocks are run in the order in which they appear in the file.
The constructor runs after all fields and instance initializer blocks have run.
Let's look at an example:
1: public class Chick { 2: private String name = "Fluffy"; 3: { System.out.println("setting field"); } 4: public Chick() { 5: name = "Tiny"; 6: System.out.println("setting constructor"); 7: } 8: public static void main(String[] args) { 9: Chick chick = new Chick(); 10: System.out.println(chick.name); } }
Running this example prints this:
setting field setting constructor Tiny
Let's look at what's happening here. We start with the main()
method because that's where Java starts execution. On line 9, we call the constructor of Chick
. Java creates a new object. First it initializes name
to "Fluffy"
on line 2. Next it executes the println()
statement in the instance initializer on line 3. Once all the fields and instance initializers have run, Java returns to the constructor. Line 5 changes the value of name
to "Tiny"
, and line 6 prints another statement. At this point, the constructor is done, and then the execution goes back to the println()
statement on line 10.
Order matters for the fields and blocks of code. You can't refer to a variable before it has been defined:
{ System.out.println(name); } // DOES NOT COMPILE private String name = "Fluffy";
You should expect to see a question about initialization on the exam. Let's try one more. What do you think this code prints out?
public class Egg { public Egg() { number = 5; } public static void main(String[] args) { Egg egg = new Egg(); System.out.println(egg.number); } private int number = 3; { number = 4; } }
If you answered 5
, you got it right. Fields and blocks are run first in order, setting number
to 3
and then 4
. Then the constructor runs, setting number
to 5
. You see a lot more rules and examples covering order of initialization in Chapter 6. We only cover the basics here so you can follow the order of initialization for simple programs.
Understanding Data Types
Java applications contain two types of data: primitive types and reference types. In this section, we discuss the differences between a primitive type and a reference type.
Using Primitive Types
Java has eight built-in data types, referred to as the Java primitive types. These eight data types represent the building blocks for Java objects, because all Java objects are just a complex collection of these primitive data types. That said, a primitive is not an object in Java, nor does it represent an object. A primitive is just a single value in memory, such as a number or character.
The Primitive Types
The