Class fields in Java are variables that belong to a class rather than an instance of the class. They are sometimes called “static variables” because they are shared by all instances of the class. To define a class field, the “static” keyword is used before the variable declaration. This means that the variable will be allocated only once in memory and can be accessed by all instances of the class. Class fields are useful for storing data that is shared by all instances of a class, such as constants or configuration data. They are also useful for implementing singleton patterns, where there is only one instance of a class that is shared across the entire application. However, it is important to use class fields carefully, as they can make code more difficult to maintain and can create unintended side effects if not used properly.
Although the discussion of objects and classes introduced you to fields, you may still have some questions, such as:
What are the rules and conventions for naming a field?
What other data types exist besides int, String, double?
Is it necessary to initialize fields when they are declared?
If fields are not explicitly initialized, are they assigned a default value?
In this tutorial, we’ll look at the answers to such questions, but first there are a few technical distinctions to be aware of.
The terms “field” and “variable” are both used in the Java programming language; this is a common source of confusion among new developers, because both often appear to refer to the same thing. Variables in the Java programming language are classified as follows:
Instance Variables (Non-Static Fields)
Objects store their individual states in “non-static fields,” which are fields declared without the static keyword. Non-static fields are also known as instance variables, because their values are unique to each instance of a class (or, in other words, to each object; for example, the seriesName of one Series is independent of the seriesName of another.
Class Variables (Static Fields)
Any field declared with the static modifier is a class variable, because it informs the compiler that there is only one copy of that field, regardless of how many times the class has been instantiated. We will discuss static fields in due time.
A method will often store its temporary state in local variables, much like how an object saves its state in fields. Similar to defining a field, local variables are declared using the same syntax (for instance, int count = 0;). There is no specific keyword that indicates a variable is local; rather, the location in which the variable is declared—between the opening and closing braces of a method—determines whether it is local or not. Since they are not accessible from other methods of the class, local variables are only available to the methods in which they are declared.
You have already come across the examples of parameters. Parameter examples can be found in both the Button class and the main method of the “Hello World!” application. Remember that the main method’s signature is public static void main (String args). This method’s parameter is the args variable. The important thing to remember is that parameters are always referred to as “variables” rather than “fields.” This also applies to other parameter-accepting constructs (such as constructors and exception handlers) covered later.
From our previous tutorial you know that an object’s state is stored in fields. Fields are also known as instance variables.
Take the Series class, as an example,
Field declarations are made up of three parts, in this order:
- There can be zero or more modifiers, such as public or private.
- The type of field.
- The name of the field.
Modifiers are used to support the core concepts of encapsulation, also known as ‘data hiding’ in object-oriented development. We will discuss encapsulation in great detail in a later tutorial. But here we want to give you a taste of access modifiers. If you are OOP savvy then you know what they are and why they are important. The following analogy is for the beginners, who are confused right now.
There are few doors for outside access in a house, but many for internal commute. Why ?
You don't want your visitors to be confused by so many doors because they don't know much about your house.
Moreover, you want to protect your home, so you installed security checks on only one door. You can do it on any door, but why spend so much money on security?
You can keep a few doors open for internal commuting because You've already laid out a map inside once they're in.
Modifiers are Java keywords that are used in applications to declare features. They have an impact on either the lifespan or the accessibility of a feature. A class, method, or variable can all be considered features. Access modifiers and visibility modifiers are modifiers that affect the visibility of a feature. In Java, access modifiers change the scope of a class, constructor, variable, method, or data member. The remaining modifiers are not clearly classified and may be referred to as storage and lifetime modifiers.
When no access modifier is specified, the default access modifier is used. Data members, classes, or methods are only accessible within the same package. We will discuss package later. In our Series class we have not specified any access modifier for the fields, so the default access modifier is used for them.
Data members, classes, and methods are only accessible within the class in which they are declared. They are inaccessible to any other class in the same package.
The public access modifier has the broadest scope of any access modifier. Declared public classes, methods, or data members are accessible from anywhere in the program. The scope of a public data member is unrestricted.
Types of Fields
As the Java programming language is statically typed, all variables must be declared before they can be used. As you’ve seen, this entails stating the variable’s type and name:
This tells your program that there is a field named “numberOfSeasons” that holds numerical data. The data type of a variable determines the values it can hold as well as the operations that can be performed on it.
Java is concerned with type. It won’t let you do something strange and dangerous like put a floating point number into an integer variable unless you acknowledge to the compiler that you are aware that precision (everything after the decimal point) may be lost. You must declare the type of your variable for all of this type-safety to work. Is it a number? a Series? Only one character?
Variables are classified into two types: primitive and object reference. Integers, booleans, and floating point numbers are examples of primitive values (think: simple bit patterns). Object references are, well, references to objects.
We’ll start with primitives and work our way up.
The Java programming language supports seven other primitive data types in addition to int. The language defines primitive types, which are identified by a reserved keyword. Primitive values do not share state with other primitive values. The Java programming language supports the following eight primitive data types:
We have discussed them in great detail in one of our all about data types tutorial. So, we will not repeat it here.
But we want to add something to that tutorial. The Java programming language offers additional support for character strings via the java.lang.String class in addition to the eight primitive data types mentioned above. Double quotes around your character string cause it to be automatically converted into a new String object, as in String s = “this is a string”;. Since string objects are immutable, their values cannot be modified after they have been created. The String class is not technically a primitive data type, but given the language’s special support, you’ll probably think of it as one.
Note: When you see a statement like "an object of type X," consider type and class to be synonyms.
(This will be refined further in later tutorials.)
When declaring a field, it is not always necessary to assign a value. The compiler will set a reasonable default for fields that are declared but not initialized. In general, depending on the data type, this default will be zero or null. However, relying on such default values is generally regarded as bad programming practice.
The chart below summarizes the default values for the aforementioned data types.
Local variables(method variables) are slightly different; an uninitialized local variable is never assigned a default value by the compiler. If you are unable to initialize your local variable where it is declared, make sure to assign it a value before using it. A compile-time error will occur if you access an uninitialized local variable.
You can assign a value to a variable in a variety of ways, including:
typing a literal value after the equals sign (releasedYear=2012, isGood = true, and so on). assign one variable's value to another (x = y) use an expression that combines the two (x = y + 43)
In the examples below, the literal values are in bold italics:
String seriesName = "The Expanse"; //declare a String named seriesName, assign it the value "The Expanse" int releasedYear = "2012"; //declare an int named releasedYear, assign it the value 2012 String genre = "sci-fi"; //declare a String named genre, assign it the value "sci-fi" int numberOfSeasons = "6"; //declare an int named numberOfSeasons, assign it the value 6 double IMDBRating = "8.5"; //declare a double named IMDBRating, assign it the value 8.5 int rottenTomatoesRating = "95"; //declare an int named rottenTomatoesRating, assign it the value 95 char initial = ‘O’; //declare a char named initial, assign it the value ‘O’ boolean isCrazy; //declare a boolean named isCrazy (no assignment) isCrazy = true; //assign the value true to the previously-declared isCrazy int y = x + 456; //declare an int named y, assign it the value that is the sum of whatever x is now plus 456
All variables, whether fields, local variables, or parameters, adhere to the same naming rules and conventions as discussed in the variables in Java tutorial.
Be aware that the same naming rules and conventions are used for method and class names in this tutorial, with the exception that:
A class name’s first letter should be capitalized, and the first (or only) word in a method name should be a verb. This will be clear in a few tutorials.
Now it’s time to discuss reference types. You understand how to declare and assign a primitive variable a value. What about non-primitive variables, though? Or to put it another way, how about objects?
If you declare a variable of type primitive you do something like this:
int num = 23;
In the case of primitive types, the value is stored in the variable. If we look under the hood, the num will contain a “bit pattern” that represents 23.
But, in the case of objects it is a little different. Suppose we want to declare an object type field. We could do something like this:
Human human = new Human();
Unlike primitive type, the Human type object is not stored in the human variable. If we look under the hood, the human will contain a bit pattern – but it will not represent a Human type object. Instead the value of the human is an address where the actual Human object is stored. As this variable refers to an address where the object is stored, not the actual object, it is called a reference type. Apart from this, you would declare a variable of reference type exactly like you would declare a variable of primitive type.
Remember what we told you about variables? They are like containers. They hold something. We stuff data in a variable. This is true for primitive data types. Our further understanding of reference type variables would be on this.
You can’t stuff an object into a variable. We often think of it that way… we say things like, “I passed the String to the System.out. println() method.” Or, “The method returns a Dog”, or, “I put a new Foo object into the variable named myFoo.”
But that is not the case. There are no giant expandable containers or jars that can expand to any size. Objects can only be found in one place: the garbage collectible heap! While a primitive variable is full of bits representing the variable’s actual value, an object reference variable is full of bits representing a path to the object. On a reference variable, you use the dot operator (.) to say, “use the thing before the dot to get me the thing after the dot.”
Consider the following example,
Human human=new Human(); //we are creating a new object and the path to get to that object is saved in human variable human.go();
means “invoke the go() method on the object referenced by the variable human.” Consider using the dot operator on an object reference variable as if you were pressing a button on the object’s remote control.
An object reference is just another variable value. Something that goes in a jar. Only this time, the value is a remote control.
The following example may make this concept more clear to you.
byte num = 7;
The bits representing 7(00000111) go into the variable.
Human human = new Human();
The bits representing a way to get to the Human object go into the variable. The Human object itself does not go into the variable!
With primitive variables, the value of the variable is… the value (5, -26.7, ‘a’). With reference variables, the value of the variable is… bits representing a way to get to a specific object. You don’t know (or care) how any particular JVM implements object references. Sure, they might be a pointer to a pointer to… but even if you know, you still can’t use the bits for anything other than accessing an object.
The 3 steps of object declaration, creation and assignment
- Declare a reference variable
Tells the JVM to allocate space for a reference variable, and names that variable human. The reference variable is, forever, of type Human. In other words, a remote control that has buttons to control a Human, but not a Cat or a Button or a Socket.
- Create an Object
Tells the JVM to allocate space for a new Human object on the heap.
- Link the object and the reference
Assign the new Human to the variable human
In short you can use the reference types in java as fields like you use the primitive types. There are some subtle differences though. But you do not have to worry about them for now. Just keep in mind what the bit pattern of that variable represents.
For all reference types the default value is null .