Default values and initialization in Java - java

Based on my reference, primitive types have default values and Objects are null. I tested a piece of code.
public class Main {
public static void main(String[] args) {
int a;
System.out.println(a);
}
}
The line System.out.println(a); will be an error pointing at the variable a that says variable a might not have been initialized whereas in the given reference, integer will have 0 as a default value. However, with the given code below, it will actually print 0.
public class Main {
static int a;
public static void main(String[] args) {
System.out.println(a);
}
}
What could possibly go wrong with the first code? Do class variables behave different from local variables?

In the first code sample, a is a main method local variable. Method local variables need to be initialized before using them.
In the second code sample, a is class member variable, hence it will be initialized to the default value.

Read your reference more carefully:
Default Values
It's not always necessary to assign a value when a field is declared.
Fields that are declared but not initialized will be set to a
reasonable default by the compiler. Generally speaking, this default
will be zero or null, depending on the data type. Relying on such
default values, however, is generally considered bad programming
style.
The following chart summarizes the default values for the above data
types.
. . .
Local variables are slightly different; the compiler never assigns a
default value to an uninitialized local variable. If you cannot
initialize your local variable where it is declared, make sure to
assign it a value before you attempt to use it. Accessing an
uninitialized local variable will result in a compile-time error.

These are the main factors involved:
member variable (default OK)
static variable (default OK)
final member variable (not initialized, must set on constructor)
final static variable (not initialized, must set on a static block {})
local variable (not initialized)
Note 1: you must initialize final member variables on every implemented constructor!
Note 2: you must initialize final member variables inside the block of the constructor itself, not calling another method that initializes them. For instance, this is not valid:
private final int memberVar;
public Foo() {
// Invalid initialization of a final member
init();
}
private void init() {
memberVar = 10;
}
Note 3: arrays are Objects in Java, even if they store primitives.
Note 4: when you initialize an array, all of its items are set to default, independently of being a member or a local array.
I am attaching a code example, presenting the aforementioned cases:
public class Foo {
// Static and member variables are initialized to default values
// Primitives
private int a; // Default 0
private static int b; // Default 0
// Objects
private Object c; // Default NULL
private static Object d; // Default NULL
// Arrays (note: they are objects too, even if they store primitives)
private int[] e; // Default NULL
private static int[] f; // Default NULL
// What if declared as final?
// Primitives
private final int g; // Not initialized. MUST set in the constructor
private final static int h; // Not initialized. MUST set in a static {}
// Objects
private final Object i; // Not initialized. MUST set in constructor
private final static Object j; // Not initialized. MUST set in a static {}
// Arrays
private final int[] k; // Not initialized. MUST set in constructor
private final static int[] l; // Not initialized. MUST set in a static {}
// Initialize final statics
static {
h = 5;
j = new Object();
l = new int[5]; // Elements of l are initialized to 0
}
// Initialize final member variables
public Foo() {
g = 10;
i = new Object();
k = new int[10]; // Elements of k are initialized to 0
}
// A second example constructor
// You have to initialize final member variables to every constructor!
public Foo(boolean aBoolean) {
g = 15;
i = new Object();
k = new int[15]; // Elements of k are initialized to 0
}
public static void main(String[] args) {
// Local variables are not initialized
int m; // Not initialized
Object n; // Not initialized
int[] o; // Not initialized
// We must initialize them before use
m = 20;
n = new Object();
o = new int[20]; // Elements of o are initialized to 0
}
}

There are a few things to keep in mind while declaring primitive type values.
They are:
Values declared inside a method will not be assigned a default value.
Values declared as instance variables or a static variable will have default values assigned which is 0.
So in your code:
public class Main {
int instanceVariable;
static int staticVariable;
public static void main(String[] args) {
Main mainInstance = new Main()
int localVariable;
int localVariableTwo = 2;
System.out.println(mainInstance.instanceVariable);
System.out.println(staticVariable);
// System.out.println(localVariable); // Will throw a compilation error
System.out.println(localVariableTwo);
}
}

Yes, an instance variable will be initialized to a default value. For a local variable, you need to initialize before use:
public class Main {
int instaceVariable; // An instance variable will be initialized to the default value
public static void main(String[] args) {
int localVariable = 0; // A local variable needs to be initialized before use
}
}

Local variables do not get default values. Their initial values are undefined without assigning values by some means. Before you can use local variables they must be initialized.
There is a big difference when you declare a variable at class level (as a member, i.e., as a field) and at the method level.
If you declare a field at the class level they get default values according to their type. If you declare a variable at the method level or as a block (means any code inside {}) do not get any values and remain undefined until somehow they get some starting values, i.e., some values assigned to them.

All member variables have to load into the heap, so they have to be initialized with default values when an instance of class is created.
In case of local variables, they don't get loaded into the heap. They are stored on the stack until they are being used. This is before Java 7, so we need to explicitly initialize them.

In Java, the default initialization is applicable for only instance variable of class member.
It isn't applicable for local variables.

In the first case you are declaring "int a" as a local variable(as declared inside a method) and local varible do not get default value.
But instance variable are given default value both for static and non-static.
Default value for instance variable:
int = 0
float,double = 0.0
reference variable = null
char = 0 (space character)
boolean = false

I wrote following function to return a default representation 0 or false of a primitive or Number:
/**
* Retrieves the default value 0 / false for any primitive representative or
* {#link Number} type.
*
* #param type
*
* #return
*/
#SuppressWarnings("unchecked")
public static <T> T getDefault(final Class<T> type)
{
if (type.equals(Long.class) || type.equals(Long.TYPE))
return (T) new Long(0);
else if (type.equals(Integer.class) || type.equals(Integer.TYPE))
return (T) new Integer(0);
else if (type.equals(Double.class) || type.equals(Double.TYPE))
return (T) new Double(0);
else if (type.equals(Float.class) || type.equals(Float.TYPE))
return (T) new Float(0);
else if (type.equals(Short.class) || type.equals(Short.TYPE))
return (T) new Short((short) 0);
else if (type.equals(Byte.class) || type.equals(Byte.TYPE))
return (T) new Byte((byte) 0);
else if (type.equals(Character.class) || type.equals(Character.TYPE))
return (T) new Character((char) 0);
else if (type.equals(Boolean.class) || type.equals(Boolean.TYPE))
return (T) new Boolean(false);
else if (type.equals(BigDecimal.class))
return (T) BigDecimal.ZERO;
else if (type.equals(BigInteger.class))
return (T) BigInteger.ZERO;
else if (type.equals(AtomicInteger.class))
return (T) new AtomicInteger();
else if (type.equals(AtomicLong.class))
return (T) new AtomicLong();
else if (type.equals(DoubleAdder.class))
return (T) new DoubleAdder();
else
return null;
}
I use it in hibernate ORM projection queries when the underlying SQL query returns null instead of 0.
/**
* Retrieves the unique result or zero, <code>false</code> if it is
* <code>null</code> and represents a number
*
* #param criteria
*
* #return zero if result is <code>null</code>
*/
public static <T> T getUniqueResultDefault(final Class<T> type, final Criteria criteria)
{
final T result = (T) criteria.uniqueResult();
if (result != null)
return result;
else
return Utils.getDefault(type);
}
One of the many unnecessary complex things about Java making it unintuitive to use. Why instance variables are initialized with default 0 but local are not is not logical. Similar why enums dont have built in flag support and many more options. Java lambda is a nightmare compared to C# and not allowing class extension methods is also a big problem.
Java ecosystem comes up with excuses why its not possible but me as the user / developer i dont care about their excuses. I want easy approach and if they dont fix those things they will loose big in the future since C# and other languages are not waiting to make life of developers more simple. Its just sad to see the decline in the last 10 years since i work daily with Java.

I have commented between codes:
public class Main {
public static void main(String[] args) {
// This is local variable.
// Look! you have declared it within the "body of a method".
// Local variables must be initialized.
int a;
System.out.println(a);
}
}
Now the next one
public class Main {
//This is NOT a local variable. It is NOT in a method body!
//Look! you have defined it as class member ( or a property).
//Java is more generous with local variables and initiates them.
//(ex: int with 0, boolean with false, String(or any object) with null, ...)
static int a;
public static void main(String[] args) {
System.out.println(a);
}
}

Related

Why this program does not give ambiguity error

I have a java program where a paramaterized constructor is used with the parameters names same as that of instance variables.
In such case we need to use this keyword. But when I do not use this keyword it does not gives any error instead it initializes instance variables with default values.
class Demo{
int a;
Demo(int a)
{
a = a;
}
public static void main(String args[])
{
Demo d = new Demo(5);
}
}
But when this program is executed the value of a becomes 0. How?
There's no ambiguity - in a = a;, both a's unambiguously refer to the parameter, because that is the "innermost" variable called a.
Because it is perfectly valid to assign the same value to same variable. So a = a is perfectly valid code.
But what you want to achieve is to assign value of a (method variable) to this.a (instance variable). So you need to use this keyword to refer to instance variable.
Demo(int a) {
this.a = a;
}
If you do not want to use this keyword then you need to rename method variable like
Demo(int b) {
a = b; // a will refer to instance variable in this case.
}
my question was how a's value become zero.
Refer : Primitive Data Types
Primitive datatype variable are initialized with default value. And for int 0 is default value.
You overwrite the local variable a in your code instead assigning it's value to the class variable. And the class variable is initialised with zero.
Do
Demo(int a) {
this.a = a;
}

Why is the output not changed in this code snippet when I use the object form of int?

Given this code snippet:
class Ex1{
public static void main(String args[]){
int x = 10;
int y = new Ex1().change(x);
System.out.println(x+y);
}
int change(int x){
x=12;
return x;
}
}
I understand that the x in main won't get changed by the change method and return the value 22 because Java primitives are call-by-value. However, if I change all the int to Integer, making them objects and therefore theoretically call-by-value-of-reference, why does the program still return 22?
Is it possible to modify the method change such that it also modifies the variable x in main?
EDIT: new snippet
class Ex1{
public static void main(String args[]){
Integer x = 10;
Integer y = new Ex1().change(x);
System.out.println(x+y);
}
Integer change(Integer x){
x=12;
return x;
}
}
Both value and reference types are passed by-value in Java (see the Java Tutorials). This means that the passed-in reference still points at the same object as before the call, even if the internals of a method change the reference assigned to a method's parameter variable.
The primitive wrappers are all reference types, so there is no difference between their behaviour and the behaviour of any other reference type when passed as an argument to a method.
However, you can change the values inside a reference object, and those changes will be reflected after the method call completes, in the calling method. You can't do this with the primitive wrappers though: they are immutable.
public static void main(String[] args){
Foo parentFoo = new Foo(1);
System.out.println(parentFoo); // prints "instance 1, data is now 1"
changeReferenceFail(parentFoo); // prints "instance 2, data is now 2"
System.out.println(parentFoo); // prints "instance 1, data is now 1"
mutateReference(parentFoo); // prints "instance 1, data is now 3"
System.out.println(parentFoo); // prints "instance 1, data is now 3"
}
private static void changeReferenceFail(Foo myFoo) {
myFoo = new Foo(2); // assigns a new object to the myFoo parameter variable
System.out.println(myFoo);
}
private static void mutateReference(Foo myFoo) {
myFoo.setData(3); // changes the reference variable internals
System.out.println(myFoo);
}
...
class Foo {
private static int iidSeed = 0;
private int iid = 0;
private int data;
public Foo(int data) {
this.data = data;
this.iid = ++iidSeed;
}
public void setData(int data) { this.data = data; }
public String toString() {
return String.format("instance %d, data is now %d", this.iid, this.data);
}
}
You asked: "Is it possible to modify the method change such that it also modifies the variable x in main?".
You can either pass a reference object, and modify an internal field (as per mutateReference above). Or you can return a new integer and assign it to your local variableexactly as you are doing already.
Integer change(Integer x){
x=12;
return x;
}
Because this does not change what is stored inside the object Integer x, but assigns a new value to the variable x. It is not the original argument object being changed, but a new Integer object is created assigned to the variable formerly holding the original object.
As you said, when passing an object to a function, you actually pass the value of its reference. Thus, statements like myParam = something have no effect on the object passed to the method, only method calls such as myParam.mutate() can change its state. Nevertheless, Integer is an immutable class so you will not be able by any mean, to change the value of the Integer in the main.
You are passing the value of x to your method, that applies that value to another variable x. You would need to modify the correct instance of x to change it in main. This snippet changes x, although I'm sure you knew how to do this already.
class Ex1{
int x = 10;
public static void main(String args[]){
System.out.println(x);
changeX(15);
System.out.println(x);
}
void changeX(int newVal){
x=newVal;
}
}

Java Constructor variables being ignored

I am trying to create a instance of the object Iset. When the person makes the object they have to give an int which will be the size of a boolean array that will store a set of integers e.g 1 will be Iset[1] = true etc etc. But I keep getting index out of range error. The rest of the program is obviously ignoring the values I set in the constructor so how do I make sure that the values I use in the constructor are used in all of my methods?
First part of the code:
public class Iset {
public int size;
boolean[] Iset;
ISet(int a) {
int size = a;
seti = new boolean[size];
Lets have a look at your code :
public class Iset {
public int size;// Declares a Member of a class and all the objects will have a copy of this member
boolean[] Iset;
.....
}
ISet(int a) {
int size = a; //This line is declaring a **local variable** called size
seti = new boolean[size];
...
}
See in your constructor you've created a local variable size but you also have a class member called size in your class. So in this scenario whenever we try to set size variable within constructor, there arises a conflict to the compiler whether to set the local variable or the class member ( this conflict is because of the fact that both the local variable and class member has same name ) . In such scenarios the compiler chooses local variable size over the class member size. But for you to make sure that the values you use in the constructor are used in all of my methods, you have to set the class member. To set the class member we use following code:
this.size = a;//Says set the object member size to value present in a.
Here we refer the size using this pointer because we need to set the object's size variable and not the local variable size.
You are creating a new variable inside your constructor and this is called shadowing. Use this to set the attributes of the current object:
this.size = a;
You're creating a new int variable inside the constructor. Instead, you just need to do this.size = a; in the constructor.
Try this:
public class Iset {
public int size;
boolean[] seti;
ISet(int a) {
this.size = a; // This will make methods access the value
this.seti = new boolean[size];
size variable in your constructor is a local variable, that's why other member methods doesn't get the right size to check.
Assign the value to this.size, then it will work:
ISet(int a) {
this.size = a;
seti = new boolean[size];
You should use the this keyword, an make the constructor public if you want to instantiate it in another class:
public class ISet {
public int size;
boolean[] iSet;
public ISet(int a) {
this.size = a;
this.iSet = new boolean[a];
}
You are not initializing the size instance variable properly, instead you are initializing a local variable size. Therefore your size instance variable remained initialized with 0 and your seti instance variable is an empty array causing the out of range error.
As pointed out by others, you don't need the instance variable size.
There is also no need for another local variable size inside your constructor, Just use seti.length to determine the size of the array. To simplify, your code should be:
public class Iset {
boolean[] seti;
ISet(int a) {
seti = new boolean[a];
I would recommend you use static analysis tools like checkstyle to eliminate bug like this in your codes.

initializing variables before using in java

I have been playing with this piece of code for sometime and it puzzles me why this method call seems to be returning a number although it was not initially set to 0
public class MainProg {
public static void main(String[] args) {
FixedCapacitySizeOfStrings s = new FixedCapacitySizeOfStrings(3);
System.out.println("(" + s.size() + " left on stack)");
}
}
This is the API code
public class FixedCapacitySizeOfStrings {
private String[] a;
private int N;
public FixedCapacitySizeOfStrings(int cap) {
a = new String[cap];
}
public boolean isEmpty() {
return N == 0;
}
public int size() {
return N; //why is this line doing the right thing?? N was never initialized to 0
}
public void push(String item) {
a[N++] = item;
}
public String pop() {
return a[--N];
}
}
Primitive instance variables are by default initialized to 0. This includes int, long, double, float, short, byte and char. (And all non-primitive instance variables are initialized to null)
Note that it's only about instance variables (fields) - local variables are not initialized.
Instance variables are initialized to default value by the compiler,if you don't provide any initialization
These are the default values for different types of instance variables.
data type Default value
boolean false
char \u0000
int,short,byte / long 0 / 0L
float /double 0.0f / 0.0d
any reference type null
For more details on default initialization.
When you are inside of methods, variables must be initialized explicitly. Outside of methods 0 is implicitly the default value integers are initialized to.
So, even though your integer N is not being assigned within FixedCapacitySizeOfStrings its value is implicitly zero as it's declared as an instance variable (class variable.)
However, your test case complains because the integer s wasn't explicitly set to any value, and is being declared within a method.
FixedCapacitySizeOfStrings s = new FixedCapacitySizeOfStrings(3);
it will call the constructor, but before constructor it is called the initialisation code part, which is now empty and private int N; takes the 0 value. Than System.out.println("(" + s.size() + " left on stack)"); will return the 0 value.
it gives s.size()=0 because N is Instance variable and as you know it has default value if you want to correct value then write as
public int size() {
return N=a.length;
}
above give the correct result...

Do final variables need to be given a value immediately after declaring them

Is it possible to assign a value to a final variable anywhere else in the program? Or is it mandatory that they be assigned a value upon creation?
class TestClass() {
//this won't compile but is it possible to assign str a value anywhere else in the program?
public static final String str;
}
You need to assign a value when it's declared - in the constructor if it's not static, in the static initializer block if it is. Once you set the value, it can't be modified.
Do it like this:
public class FinalTest {
private static final String CONSTANT;
private final String value;
static {
CONSTANT = "Hello";
}
public static void main(String [] args) {
FinalTest ft = ((args.length > 0) ? new FinalTest(args[0]) : new FinalTest(CONSTANT));
System.out.println(ft);
}
public FinalTest(String value) {
this.value = value;
}
public String toString() { return this.value; }
}
Local variables
A final variable needs to be assigned a value exactly once before it is accessed. This means that if it's never assigned a value and never accessed, the compiler won't complain.
void foo() {
final int a; // Never assigned, but never accessed either, so no problem
final int b = 7;
System.out.println("b is " + b);
// System.out.println("a is " + a);
// Uncommenting the above line would cause a compile error
}
Static fields
A similar logic applies to final static fields, except it's assumed that they will be accessed at some point, so they must be initialized either on the definition line or in a static initializer block.
Here's what the Java tutorial has to say about static initialization blocks:
This works well when the initialization value is available and the initialization can be put on one line. However, this form of initialization has limitations because of its simplicity. If initialization requires some logic (for example, error handling or a for loop to fill a complex array), simple assignment is inadequate. Instance variables can be initialized in constructors, where error handling or other logic can be used. To provide the same capability for class variables, the Java programming language includes static initialization blocks.
Note: It is not necessary to declare fields at the beginning of the class definition, although this is the most common practice. It is only necessary that they be declared and initialized before they are used.
Instance fields
While we're at it, a final instance (non-static) field must be assigned a value exactly once by the time the instance initialization is complete. This means there are three places where you can initialize one (but you must pick one):
1. Definition line:
// For when you know the answer
class Foo {
final int theAnswer = 42;
}
2. Constructor:
// For when you need to have the answer passed in
class Foo {
final int theAnswer;
Foo(int answer) {
theAnswer = answer;
}
}
// Or for when you need to do some computation
class Bar {
static final int ANSWER_COUNT = 10;
final int[] answers;
Foo() {
answers = new int[ANSWER_COUNT];
for (int i = 0; i < ANSWER_COUNT; i++) {
answers[i] = i;
}
}
3. Initializer block:
// For when you need to do some computation and have many constructors
class Bar {
static final int ANSWER_COUNT = 10;
final int[] answers;
{
answers = new int[ANSWER_COUNT];
for (int i = 0; i < ANSWER_COUNT; i++) {
answers[i] = i;
}
}
// I have many constructors and don't want to copy-paste
// the initialization logic above to all of them
Bar() { ... }
Bar(int i) { ... }
Bar(String blah) { ... }
}
From the same page in the tutorial, regarding initializer blocks:
The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.
In the code you posted, the field is static so it could be given a value from within a static initialization block:
static {
str = "my string";
}
For non-static fields, they can either be initialized in the constructor, or in an instance initializer block:
class TestClass {
private final String str;
{
str = "my string";
}
TestClass() {
}
}

Categories