Java 101: Object-oriented language basics, Part 2: Fields and methods

Learn how to declare and access fields and methods in Java

Delve into fields and methods with this second article in the Java 101 "Object-oriented language basics" series. Deepen your understanding of fields, parameters, and local variables and learn to declare and access fields and methods.

Ever hear the expression, "I can't see the forest for the trees?" That expression refers to specific details that cloud your understanding of the big picture. And what could be cloudier than a detailed examination of fields and methods during an introduction to Java's classes and objects? That is the reason I chose to minimize fields and methods while maximizing the big picture -- classes and objects -- in Part 1 of this object-oriented language series. However, because you eventually have to step back from the forest and focus on the trees, this month's article examines fields and methods in great detail.

Java's variables can be divided into three categories: fields, parameters, and local variables. I'll present fields here and leave an exploration of parameters and local variables for a later section that discusses methods.

Declaring fields

A field is a variable declared in a class body that holds either part of an object's state (an instance field) or part of a class's state (a class field). Use the following Java syntax to declare a field in source code:

[ ( 'public' | 'private' | 'protected' ) ] 
  [ ( 'final' | 'volatile' ) ] 
    [ 'static' ] [ 'transient' ]
      data_type field_name [ '=' expression ] ';'

A field declaration specifies the field's name, data type, optional expression (which initializes the field), access specifiers, and modifiers. Choose identifiers for the data type and name that are not reserved words. Consider this example:

class Employee
{
   String name;    // The employee's name.
   double salary;  // The employee's salary.
   int jobID;      // The employee's job identification code (e.g., accountant, payroll clerk, manager, and so on).
}

The Employee class declares three fields: name, salary, and jobID. When you create an Employee object, name eventually holds a reference to a String object that contains the employee's name. The salary field will hold the employee's salary, and jobID will hold an integer that identifies the employee's job category.

Access specifiers

You can optionally declare a field with an access specifier keyword: public, private, or protected. The access specifier determines how accessible the field is to code in other classes. Access ranges from totally accessible to totally inaccessible.

If you do not declare a field with an access specifier keyword, Java assigns the field a default access level, which makes the field accessible within its class and to all classes within the same package. (Think of packages as libraries of classes -- a concept I'll explore in a future article.) Any class not declared in the same package as the class that contains the field cannot access the field. Take a look at the following example:

class MyClass
{
   int fred;
}

Only code contained in MyClass and other classes declared in the same package as MyClass can access fred.

If you declare a field private, only code contained in its class can access the field. That field becomes inaccessible to every other class in every other package. Examine the code below:

class Employee
{
   private double salary;
}

Only code contained in Employee can access salary.

If you declare a field public, code contained in its class and all other packages' classes can access the field. Refer to the code below:

public class Employee
{
   public String name;
}

Code contained in Employee and all other packages' classes can access name. (Employee must also be declared public before code in other packages can access name.)

Declaring every field in a given class public defeats the concept of information hiding. Suppose you create a Body class to model the human body and Eye, Heart, and Lung classes to model an eye, the heart, and a lung. The Body class declares Eye, Heart, and Lung reference fields, as demonstrated by the following example:

public class Body
{
   public Eye leftEye, rightEye;
   private Heart heart;
   private Lung leftLung, rightLung;
}

The leftEye and rightEye field declarations are public because a body's eyes are visible to an observer. However, the heart, leftLung, and rightLung declarations are private because the organs they represent are hidden inside the body. Suppose heart, leftLung, and rightLung were declared public. Wouldn't that be the equivalent to having a body with its heart and lungs exposed?

Finally, a field declared protected resembles a field with the default access level. The only difference between the two access specifiers is that subclasses in any package can access the protected field. The following example demonstrates that:

public class Employee
{
   protected String name;
}

Only code contained in Employee, other classes declared in the same package as Employee, and all Employee's subclasses (declared in any package) can access name.

Modifiers

You can optionally declare a field with a modifier keyword: final or volatile and/or static and/or transient.

If you declare a field final, the compiler ensures that the field is initialized and subsequently treats the field as a constant -- a read-only variable. The compiler can now perform internal optimizations on a program's byte codes because it knows the constant will not change. Consider the example below:

class Employee
{
   final int ACCOUNTANT = 1;
   final int PAYROLL_CLERK = 2;
   final int MANAGER = 3;
   int jobID = ACCOUNTANT;
}

The example above declares three final int fields: ACCOUNTANT, PAYROLL_CLERK, and MANAGER.

Note: It is customary to use all capital letters and separate multiple words with underscores when declaring constants. That helps distinguish constants from read/write variables when analyzing source code.

If you declare a field volatile, multiple threads can access the field, and certain compiler optimizations are prevented so that the field is accessed appropriately. (You'll learn about volatile fields when I discuss threads in a future article.)

If you declare a field static, all objects share one copy of the field. When you assign a new value to that field, all objects can see the new value. If static is not specified, the field is known as an instance field, and each object receives its own copy.

Finally, the value of a field declared transient will not be saved during object serialization. (I explore the topics of transient fields and object serialization in a future article.)

Instance fields

An instance field is a field declared without the static keyword modifier. Instance fields are associated with objects -- not classes. When modified by an object's code, only the associated class instance -- the object -- sees the change. An instance field is created when an object is created and destroyed when its object is destroyed.

The following example demonstrates an instance field:

class SomeClass1
{
   int i = 5;
   void print ()
   {
      System.out.println (i);
   }
   public static void main (String [] args)
   {
      SomeClass1 sc1 = new SomeClass1 ();
      System.out.println (sc1.i);
   }
}

SomeClass1 declares an instance field named i and demonstrates two common ways to access that instance field -- from an instance method or from a class method. Both methods are in the same class as the instance field.

To access an instance field from an instance method in the same class, you only specify the field's name. To access an instance field from another class's instance method, you must have an object reference variable that contains the address of an object created from the class that declares the instance field you want to access. Prefix the object reference variable -- along with the dot operator -- to the instance field's name. (You'll explore instance methods later in this article.)

To access an instance field from a class method in the same class, create an object from the class, assign its reference to an object reference variable, and prefix that variable to the instance field's name. To access an instance field from another class's class method, complete the same steps as when you accessed that field from a class method in the same class. (I'll present class methods later in this article.)

When the JVM creates an object, it allocates memory for each instance field and subsequently zeroes the field's memory, which establishes an instance field's default value. The way you interpret a default value depends on the field's data type. Interpret a reference field's default value as null, a numeric field's default value as 0 or 0.0, a Boolean field's default value as false, and a character field's default value as \u0000.

Class fields

A class field is a field declared with the static keyword modifier. Class fields are associated with classes -- not objects. When modified by a class's code, the class (as well as any created objects) sees the change. A class field is created when a class is loaded and destroyed if and when a class is unloaded. (I believe some JVMs unload classes whereas other JVMs do not.)

The example below illustrates a class field:

class SomeClass2
{
   static int i = 5;
   void print ()
   {
      System.out.println (i);
   }
   public static void main (String [] args)
   {
      System.out.println (i);
   }
}

SomeClass2 declares a class field i and demonstrates two common ways to access i -- from an instance or class method (both methods are in the same class as the class field).

To access a class field from an instance method in the same class, you only specify the field's name. To access a class field from another class's instance method, prefix the class field with the name of the class in which the class field is declared. For example, specify SomeClass2.i to access i from an instance method in another class -- which is in the same package as SomeClass2, because SomeClass2 isn't declared public.

To access a class field from a class method in the same class, you only specify the field's name. To access a class field from another class's class method, follow the same procedure as you did when accessing the class field from an instance method in another class.

Once a class loads, the JVM allocates memory for each class field and establishes a class field's default value. Interpret a class field's default value just as you would interpret an instance field's default value.

Class fields are the closest things to global variables in Java. Check out the example below:

class Global
{
   static String name;
}
class UseGlobal
{
   public static void main (String [] args)
   {
      Global.name = "UseGlobal";
      System.out.println (Global.name);
   }
}

The above example declares a pair of classes in a single source file: Global and UseGlobal. If you compile and then run the application, the JVM loads UseGlobal and then begins executing the main() method's byte codes. After seeing Global.name, the JVM searches for, loads, and then verifies the Global class. Once Global is verified, the JVM allocates memory for name and initializes that memory to null. Behind the scenes, the JVM creates a String object and initializes that object to all characters between the pair of double quote characters -- UseGlobal. That reference assigns to name. Then, the program accesses Global.name and retrieves the String object's reference, which subsequently passes to System.out.println(). Finally, the contents of the String object appear on the standard output device.

Because neither Global nor UseGlobal are explicitly marked public, you can choose any name for the source file. Compiling that source file results in a pair of class files: Global.class and UseGlobal.class. Because UseGlobal contains the main() method, use that class to run the program. Type java UseGlobal to run the program at the command line.

If you type java Global instead, you would receive the following error message:

Exception in thread "main" java.lang.NoSuchMethodError: main

The word main at the end of the error message indicates that java couldn't find a main() method in class Global.

Constants

A constant is a read-only variable; once the JVM initializes that variable, the variable's value cannot change.

Declare constants with the final keyword. Just as there are two kinds of fields, instance and class, constants come in two flavors -- instance and class. For efficiency, create class constants, or final static fields. Consider this example:

class Constants
{
   final int FIRST = 1;
   final static int SECOND = 2;
   public static void main (String [] args)
   {
      int iteration = SECOND;
      if (iteration == FIRST) // Compiler error.
          System.out.println ("first iteration");
      else
      if (iteration == SECOND)
          System.out.println ("second iteration");
   }
}

The above example's Constants class declares a pair of constants -- FIRST and SECOND. FIRST is an instance constant because the JVM creates a separate copy of FIRST for each Constants object. In contrast, because the JVM creates a single copy of SECOND after loading Constants, SECOND is a class constant.

1 2 3 4 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more