A variable in a programming language is a way of referring to a value or multiple values stored in the memory. A Java variable cannot be declared without its type. The data type of a Java variable determines what kind of data can be stored in the memory location it points to. For example, an integer variable can hold whole numbers between -2e31 and 2e31 -1 and a character variable can hold only a single character. Object variables store multiple values in themselves.
A Java variable is declared as follows:
<data type> <variable name>;
For example,
int x;
String s;
When a Java variable is declared, the JVM calculates the amount of maximum memory that the variable is likely to use and allocates the memory that will hold the variable’s value. Following that, when the variable is assigned a value, the bits in the allocated memory are set. Leaving a declared variable without a value is allowed depending on the type of the variable. We will talk about the details when we discuss default values for Java variables.
The value of a variable is set using the assignment operator, =, using the following format.
<variable name> = <value>
x = 3;
s = “good”;
Most of the time declaration and value assignment are done together on one line.
int x = 3;
Every declaration and value assignment is a statement and they are followed by ;. Using ; tells the compiler that it is the end of the statement.
What is a Java literal?
The representation of a value in the source code is called a literal. For example, when we create an integer as follows
int x = 3;
x is an integer literal with value 3. Therefore, for x, data type is int and 3 is literal.
Data Types in Java
There are two variable data types in Java: primitive data types and object (non-primitive) data types.
Primitive data types:
Primitive data types come predefined with the Java programming language. They simply hold a value and unlike classes, they cannot be initialized. Java programming language has 8 primitive types and each data type’s name is a reserved Java keyword. Java primitive data types are:
- byte: 8 bit signed integer. Can have values between -128 and 127.
byte b = 16;
- int: 32 bit signed integer. Can have values between -2e31 and 2e31 – 1.
int x = 3;
- float: Single precision 32 bit IEEE 754 floating point.
float f = 2.3f;
A float’s value has a f or F as a suffix.
- short: 16 bit signed integer. Can have values between -32,768 and 32,767.
short s = 25;
- long: 64 bit signed integer. Can have value between -2e63 and 2e63-1.
long l = 5l;
A long has a l or L as a suffix.
- double: Double precision 64-bit IEEE 754 floating point.
double d = 2.5;
- Char: 16 bit unicode character. Can have values between ‘\u0000’ (0) and ‘\uffff’ (65,535)
char c = ‘a’;
char s = ‘u0061’; // This is the unicode for character ‘a’.
- boolean: 1 bit. Can be only true or false.
boolean b = true;
Let’s use the primitive types in an example.
public class PrimiveTypes {
public static void main(String [] args) {
byte b = 16;
System.out.println(“b: “ + b);
int x = 3;
System.out.println(“x: “ + x);
float f = 2.3f;
System.out.println(“f: “ + f);
short s = 25;
System.out.println(“s: “ + s);
long l = 5l;
System.out.println(“l: “ + l);
double d = 2.5;
System.out.println(“d: “ + d);
char c = ‘u0061’;
System.out.println(“c: “ + c);
boolean bo = true;
System.out.println(“bo: “ + b);
}
}
The output would be
b: 16
x: 3
f: 2.3
s: 25
l: 5
d: 2.5
c: a
bo: true
Reference (Non-primitive) types
Reference types or object types define references to Java objects. They use primitives and other objects to store data in memory. In Java, every object type, like String or any object defined by the users, is a non-primitive data type.
Person p = new Person();
In this statement, p is a variable of non-primitive type Person. Person type uses String and int primitive types while defining its properties and behavior.
Similarly, the following statement
String s = “beautiful”;
declares variable s as of non-primitive type String and initializes it with the value “beautiful”. This is equivalent to
String s = new String(“Beautiful”);
What is null?
null keyword is used to denote objects that are declared but do not point to a class instance. For example, the statement
Person p;
declares p to be an object reference of type Person but does not initialize it. Therefore, it does not point to a Person instance. In this case, value of p is null. null can be used as a value only for Java objects.
What is type-casting?
Java language allows conversion between data types. This is done using a mechanism named type-casting. Type-casting literally means assigning the value of a Java variable to another Java variable of a different type, potentially changing the value. In this section, we will only talk about type-casting for primitive types.
There are two types of type casting: widening (implicit) casting and narrowing (explicit) casting.
Widening (Implicit) type-casting:
In widening or implicit casting, the conversion is from a type that holds less number of bits to a type that holds more number of bits. Following this rule, the allowed conversions are:
1- From char to int, long, double, float
2- From byte to short, int, long, double, float
3- From short to int, long, double, float
4- From int to long, double, float
5- From long double, float
6- From float to double
In implicit conversions, information is not lost since all the bytes of the old type are transferred to the new type.
Let’s see implicit type casting in an example.
public class ImplicitConversion {
public static void main(String [] args) {
int i = 10;
long l = i;
System.out.println(“Value of l: “ + l);
}
}
The output is
Value of l: 10
Narrowing (explicit) type-casting:
In narrowing or explicit conversions, the new type is put, in parantheses, in front of the old type. The main rule to follow in narrowing type-casting is that only types that occupy more bits can be cast to types that occupy less bits but not the other way. For example, an int can be cast to a byte but not to a long. When type casting happens, the bytes of the original type that extend beyond the number of bytes that the new type can hold are discarded. Java uses two’s complement system for bitwise representation of primitive types. So, type casting may result in loss of information and change of sign. For a more detailed discussion of byte operations in Java language, refer to chapter 16.
double
to float
uses standard IEEE 754 rounding.
-
integer values have their most significant bits stripped to the available width of the target type. This may result in a sign bit appearing, e.g.
(byte)0xfff
;
== (byte)-1 -
If the source type is floating point and the target type is
long
, the value is converted by rounding towards zero. -
If the source type is floating point and the target type is integral but not
long
, the value is first converted toint
by rounding towards zero. Then the resultingint
is converted to the target type using integer conversion.
Now let’s see an example for explicit type conversions.
public class ExplicitConversion {
public static void main(String [] args) {
int x = 1000;
byte b = (byte) x;
System.out.println(“Value of b: “ + b);
}
}
The output is
Value of b: -24
As you can see in the example, both the value and the sign of the new type is different than the original one.
Explicit and implicit type-casting can be applied on object types as well. We will talk about how this is done when we discuss inheritance. Parent types can be explicitly cast to child types and this may result in loss of information. In a similar way, implicit casting happens when a parent type reference points to a child type reference.
Note: The following conversions are not allowed in Java.
-
From a primitive type to an object type
-
From other primitive types to boolean
-
From boolean to other primitive types
null can be used only in object type castings.
Default values for Java variables
When declared but uninitialized, Java variables take default values. These can be summarized as follows:
1- The default value for primitive integral types (int, short, long, byte) is 0.
2- The default value for primitive floating point types (double, float) is 0.0.
3- The default value for boolean type primitives is false.
4- The default value for char type primitives have default value ‘\u0000’.
5- The default value for object types is null.
If an instance variable is declared but not assigned a value, the JVM assigns the variable its default value. Declaring a variable inside a method does not cause a compilation problem but if the uninitialized variable is later accessed, this causes an error. Object references defined inside a method can be explicitly assigned the value null and then be accessed as local variables.
public void myMethod() {
int x; //Allowed, does not cause a compilation error.
Object object1; //Allowed, does not cause a compilation error.
Object object2 = null; //Allowed, does not cause a compilation error.
//The following statement causes a compilation error because x is not initialized.
//System.out.println(x);
//The following statement causes a compilation error because object1 is not initialized.
//System.out.println(object1);
//The following statement does not cause a compilation error because object2 is explicitly set to null.
System.out.println(object2);
}
public class Initialization {
public int a; // a’s value is 0
public byte b; //b’s value is 0
public double d; //b’s value is 0.0
public float f; //c’s value is 0.0
public long l; //d’s value is 0
public short s; //s’s value is 0
public boolean bo; //bo’s value is false
public char c; //c’s value is ‘\u0000’
public String str; //str’s value is null
public static void main(String [] args) {
Initialization i = new Initialization();
System.out.println(“value of a: ” + i.a);
System.out.println(“value of b: ” + i.b);
System.out.println(“value of d: ” + i.d);
System.out.println(“value of f: ” + i.f);
System.out.println(“value of l: ” + i.l);
System.out.println(“value of s: ” + i.s);
System.out.println(“value of bo: ” + i.bo);
System.out.println(“value of c: ” + i.c);
System.out.println(“value of str: ” + i.str);
}
}
When run, this class produces the output
value of a: 0
value of b: 0
value of d: 0.0
value of f: 0.0
value of l: 0
value of d: 0
value of bo: false
value of c:
Value of localStr inside the method: null
Now let’s add a new method to Initialization class.
public class Initialization {
public int a; // a’s value is 0
public byte b; //b’s value is 0
public double d; //b’s value is 0.0
public float f; //c’s value is 0.0
public long l; //d’s value is 0
public short s; //s’s value is 0
public boolean bo; //bo’s value is false
public char c; //c’s value is ‘\u0000’
public String str; //str’s value is null
public void printLocalVariables() {
int i;
String uninitializedStr;
String nullStr = null;
System.out.println(i + “ “ + uninitializedStr + “ “ + nullStr);
}
public static void main(String [] args) {
Initialization i = new Initialization();
System.out.println(“value of a: ” + i.a);
System.out.println(“value of b: ” + i.b);
System.out.println(“value of d: ” + i.d);
System.out.println(“value of f: ” + i.f);
System.out.println(“value of l: ” + i.l);
System.out.println(“value of s: ” + i.s);
System.out.println(“value of bo: ” + i.bo);
System.out.println(“value of c: ” + i.c);
System.out.println(“value of str: ” + i.str);
}
}
When we try to compile Initialization class again, the compiler gives the following errors:
^
Initialization.java:16: variable i might not have been initialized
System.out.println(i + ” ” + uninitializedStr + ” ” + nullStr);
^
Initialization.java:16: variable uninitializedStr might not have been initialized
System.out.println(i + ” ” + uninitializedStr + ” ” + nullStr);
^
3 errors
As we expected, local variables I and unitinializedStr are left uninitialized and then inside the method they are used. However, the compiler does not complain about nullStr since it is legal to assign null to an object variable and access it later.
Now let’s remove the last line in printLocalVariables method.
public void printLocalVariables() {
int i;
String uninitializedStr;
String nullStr = null;
}
This time the compiler doesn’t complain because even though the variables i and uninitializedStr are left uninitialized, they are not later used in the method.