Understanding static variable initialization in Java - java

public class InstanceBuilder {
private static final InstanceBuilder INSTANCE = new InstanceBuilder();
private static String name = null;
private InstanceBuilder() {
System.out.println("Setting cons()");
name = "Testing";
}
public static String getName() {
return name;
}
}
public class Driver {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("value is " + InstanceBuilder.getName());
}
}
Output:
Setting cons()
value is null
Why does it print value as null even though I have set the static variable in constructor and it is called as expected. If I try to print in constructor, it is printing Testing, but if I call from public static method, it is null. I know if I change it to INSTANCE.name, it works.
But I want to understand why it is not working if I directly access static variable since same copy should be shared.
What I am missing here?

Because the value of name is getting modified after the constructor invocation as per the declaration order.
Lets see what is happening:
1) When you call InstanceBuilder.getName(), InstanceBuilder class is getting loaded. As part of that process INSTANCE and name instance variables are getting initialized.
2) While initializing INSTANCE,
private static final InstanceBuilder INSTANCE = new InstanceBuilder();
constructor of InstanceBuilder class is getting invoked & Setting cons() statement is getting printed and name variable is initialized with Testing.
3) Next name is again getting re-initialized with null due to the below statement
private static String name = null;
so when the method call returns to Driver class, value of name is null and null is getting printed. So even though name is declared as static, static has no role in that context.
Note:
Check the below link on the order of which class members should be declared
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-141855.html#1852

Here value is null because static initialization occurs as its declare in order,
So First your
`private static final InstanceBuilder INSTANCE = new InstanceBuilder();`
code execute and assign value to "testing", then your
`private static String name = null;`
code exceute and override value to null(as static variable have coppy per class only), so final value will be null.
So here this behavior is just beacuse of order of execution of static variable

Related

How to access global non static variable from static method

I have main method in my java program, I want to store values in global variable because i want to access that values from different methods of the class, however I am not convinced to use static global variable, as the values in the variable keep on changing, so am afraid values which are declared as static may not change as it is defined on the class level, so I am looking for non static global variable. Can someone give an idea, how to achieve this.
I suggest you make a separate class with with variables you want to store, with proper getter and setter methods. That way you keep the code more clean and maintainable and you follow the Separation of concerns principle, which tells us that every class should have it's own purpose.
EG:
public class Person {
private String name; // private = restricted access
// Getter
public String getName() {
return name;
}
// Setter
public void setName(String newName) {
this.name = newName;
}
}
public class MyClass {
public static void main(String[] args) {
Person myObj = new Person();
myObj.setName("John"); // Set the value of the name variable to "John"
System.out.println(myObj.getName()); //Prints out name value
}
}
Since Java promotes the use of classes rather than global variables, I would highly recommend you to use a class for storing the data. That way, you do not need to use static methods or static variables.
One example of this is shown below:
import java.util.*;
public class Main{
public static void main(String[] args) {
int initialValue = 1;
Holder holder = new Holder(initialValue);
int currentValue = holder.getValue();
System.out.println("Value after initial creation: " + currentValue);
System.out.println("Set value to 10");
holder.setValue(10);
currentValue = holder.getValue();
System.out.println("New value is " + currentValue);
}
}
Holder class:
public class Holder {
private int val;
public Holder(int value){
setValue(value);
}
public void setValue(int value){
this.val=value;
}
public int getValue(){
return this.val;
}
}
To start a java class uses the "main" static method present in all normal java programs.
HOWEVER, the "constructor" method (really just "constructor") is named after the "main class" name and is where you initialise variables whether you call a declared method in the class or retrieve a static variable from the starter method "main".
The main method does not require any passer method to obtain a static variable from it to either set a global static variable in the class because it is only 1 step in hierarchy "scope" in the class (this is why some frameworks pass variables to global without typing of the method but rather instead using "void" on the method declaration) BUT you cannot put a non static method call in a static section of code such as the main method.
The way you remove static context from a variable is to make another variable with the same name in a non static context and cast the static variable to the non static instance.
e.g. for a global String primitive type variable from main method at construction time globally declare
static String uselessRef1 = ""; // declared globally initialised
// following is declared inside the static method main
uselessRef1 = args[1]; // static argument 1 from the main method args[] array
// following is declared in global scope code or in the constructor code
String uselessRef1b = (String)uselessRef1; // (String) cast removes the static context of the String type and copies to non static version of the type
While committed inline in the global declarations not in the constructor they are deemed to be loaded in the class constructor in sequence.
NB: You can put or make a static method in a non-static class but not the make a non static method in a static class.
import.javax.swing.*;
public class ExampleStaticRemoval{
static String uselessRef1 = ""; // declared globally initialised
String uselessRef1b = "";
ExampleStaticRemoval(){
// following is declared in global scope code or in the constructor code
uselessRef1b = (String)uselessRef1; // (String) cast removes the static context of the String type and copies to non static version of the type
printOut();
}// end constructor
// program start method
public static void Main(String[] args){
new ExampleStaticRemoval();
// static global class variable uselessRef1 is assigned the local method value
// MUST BE OUTSIDE AT TOP TO BE GLOBAL
uselessRef1 = args[0] +" "+args[1]; // join static arguments 0 and 1 from the main method args[] array
}// end main
public void printOut(){
JOptionPane.showConfirmDialog(null,uselessRef1b, uselessRef1b, 0);
}//end method
} // end class

How to create a Variable with scope global and but should not be a STATIC

Need a variable to hold a value which will be assigned once and will be used by every method of a class
if I specify it as non static variable it is not holding the value
Class Test{
private String test;
public void method1(){
test = "String1";
}
public void method2(){
System.out.println(test.length());
}
}
Getting Null Pointer exception. the value of the test will be used in every method.
Could anyone help me, how to fix the issue.
The NullPointerException will be thrown whenever the test variable is null and you try to invoke methods on that variable. In your case, when you invoke method2() before method1(). That has nothing to do with global, local or whatever, as Long Vu already mentioned.
So first you should make sure, you don't access an uninitialized variable. Then, if you need a class with a single instance, which should be accessible application wide, you can implement this using the singleton pattern. For more about it, have a look at this Wikipedia page: https://en.wikipedia.org/wiki/Singleton_pattern
Maybe your problem is that you are creating multiple objects of class Test.
For example this should work:
Test test1=new Test();
test1.method1(); //call this first then other methods
test1.method2();
You should use this object "test1" as a parameter wherever you need it.
If you want to access the variable globally then create a Singletone class:
class Test{
private static Test single_instance = null;
private String test;
// private constructor restricted to this class itself
private Test(){
}
// static method to create instance of Singleton class
public static Test getInstance(){
if (single_instance == null)
single_instance = new Test();
return single_instance;
}
public void setTest(String value){
test = value;
}
public String getTest(){
return test;
}
public static void main(String args[]){
Test test = Test.getInstance();
test.setTest("String1");
test.getTest();
}
}

During field initialization, why "this" is not null and all methods can be called?What does "this" refer to?

My code is like this:
public class HelloWorld{
{
System.out.println("field init " + this.getName());
}
private String name = null;
private InnerClass inner = new InnerClass(this);
private String getName() {
return name;
}
public HelloWorld() {
name = "hello world";
System.out.println("class init");
}
private class InnerClass {
public InnerClass(HelloWorld hello) {
System.out.println((hello == null));
}
}
public static void main(String []args){
HelloWorld hello = new HelloWorld();
System.out.println("Hello World.");
}
}
As far as I know, field initialization is before constructor, so why "this.getName()" can be called and "this == null" is false?
There'd be little point to calling an instance initializer block if the instance hadn't been created yet, as the purpose of an instance initializer block is to initialize (set the initial information for) the instance (this).
So the JVM creates the instance with all fields set to the "all bits off" default, sets this to refer to that instance, then does any instance initialization you've specified.
More in JLS§12.5: Creation of New Class Instances and JVMS§4.10.2.4.
Side note:
As far as I know, field initialization is before constructor
In effect, yes; the Java compiler prepends instance initialization code to the beginning of every constructor you specify.
Remember that all classes in Java have java.lang.Object as their (ultimate) base class. Before you get to any field initialisation or construction in your class, the this pointer for that base class has already been set up.
Hence, it can never be null.

Calling a method?

okay. I wrote the above code and I need to call it from another class. how can I do it?
plus it gives me this error with DefaultTableModel prodt = (DefaultTableModel) protable.getModel(); . the error is non-static variable protable cannot be referenced from a static context.
public static void refreshProtable() {
try {
Statement s1 = Db.connectDb().createStatement();
ResultSet rs1 = s1.executeQuery("SELECT * FROM product WHERE status='" + 0 + "'");
DefaultTableModel prodt = (DefaultTableModel) protable.getModel();
while (rs1.next()) {
Vector v1 = new Vector();
v1.add(rs1.getString("pid"));
v1.add(rs1.getString("pname"));
v1.add(rs1.getString("sp_rt"));
v1.add(rs1.getString("sp_wh"));
v1.add(rs1.getString("um"));
Statement s2 = Db.connectDb().createStatement();
ResultSet rs2 = s2.executeQuery("SELECT * FROM stock WHERE pid='" + rs1.getString("pid") + "'");
if (rs2.next()) {
v1.add(rs2.getString("qty"));
}
prodt.addRow(v1);
s2.close();
}
s1.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Either mark your variable protable static or make the method non-static.
private static DefaultTableModel protable;
public static void refreshProtable() { ... }
Since the method is static, you call it using the class name that it is within.
E.g
class A {
public static void b() {
// do something
}
}
Would be called as follows:
A.b();
It might be handy to refresh yourself on how static variables work, here would be a starting point: http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
You can make your function as non-static or make protable object static.
In a word, you can not reference non-static variable in static function.
but you can reference static variable in non-static function
you need to make protable as static as you can access only static variables from a static method.
private static DefaultTableModel protable;
public static void refreshProtable() { }
the variable you are trying to call is an instance-level variable;
static variable
It is a variable which belongs to the class and not to object(instance)
Static variables are initialized only once , at the start of the execution . These variables will be initialized first, before the initialization of any instance variables
A single copy to be shared by all instances of the class
A static variable can be accessed directly by the class name and doesn’t need any object
Syntax : .
static method
It is a method which belongs to the class and not to the object(instance)
A static method can access only static data. It can not access non-static data (instance variables)
static method can call only other static methods and can not call a non-static method from it.
A static method can be accessed directly by the class name and doesn’t need any object
Syntax : .
A static method cannot refer to “this” or “super” keywords in anyway

Static Initializers And Static Methods In Java

Does calling a static method on a class in Java trigger the static initalization blocks to get executed?
Empirically, I'd say no. I have something like this:
public class Country {
static {
init();
List<Country> countries = DataSource.read(...); // get from a DAO
addCountries(countries);
}
private static Map<String, Country> allCountries = null;
private static void init() {
allCountries = new HashMap<String, Country>();
}
private static void addCountries(List<Country> countries) {
for (Country country : countries) {
if ((country.getISO() != null) && (country.getISO().length() > 0)) {
allCountries.put(country.getISO(), country);
}
}
}
public static Country findByISO(String cc) {
return allCountries.get(cc);
}
}
In the code using the class, I do something like:
Country country = Country.findByISO("RO");
The problem is that I get a NullPointerException because the map (allCountries) is not initialized. If I set up breakpoints in the static block I can see the map getting populated correctly, but it's as if the static method has no knowledge of the initializer being executed.
Can anyone explain this behavior?
Update: I've added more detail to the code. It's still not 1:1 (there are several maps in there and more logic), but I've explicitly looked at the declarations/references of allCountries and they are as listed above.
You can see the full initialization code here.
Update #2: I tried to simplify the code as much as possible and wrote it down on the fly. The actual code had the static variable declaration after the initializer. That caused it to reset the reference, as Jon pointed out in the answer below.
I modified the code in my post to reflect this, so it's clearer for people who find the question. Sorry about the confusion everyone. I was just trying to make everyone's life easier :).
Thanks for your answers!
Does calling a static method on a class in Java trigger the static initalization blocks to get executed?
Empirically, I'd say no.
You're wrong.
From the JLS section 8.7:
A static initializer declared in a class is executed when the class is initialized (§12.4.2). Together with any field initializers for class variables (§8.3.2), static initializers may be used to initialize the class variables of the class.
Section 12.4.1 of the JLS states:
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
T is a class and an instance of T is created.
T is a class and a static method declared by T is invoked.
A static field declared by T is assigned.
A static field declared by T is used and the field is not a constant variable (§4.12.4).
T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.
This is easily shown:
class Foo {
static int x = 0;
static {
x = 10;
}
static int getX() {
return x;
}
}
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(Foo.getX()); // Prints 10
}
}
Your problem is in some part of the code that you didn't show us. My guess is that you're actually declaring a local variable, like this:
static {
Map<String, Country> allCountries = new HashMap<String, Country>();
// Add entries to the map
}
That hides the static variable, leaving the static variable null. If this is the case, just change it to an assignment instead of a declaration:
static {
allCountries = new HashMap<String, Country>();
// Add entries to the map
}
EDIT: One point worth noting - although you've got init() as the very first line of your static initializer, if you're actually doing anything else before then (possibly in other variable initializers) which calls out to another class, and that class calls back into your Country class, then that code will be executed while allCountries is still null.
EDIT: Okay, now we can see your real code, I've found the problem. Your post code has this:
private static Map<String, Country> allCountries;
static {
...
}
But your real code has this:
static {
...
}
private static Collection<Country> allCountries = null;
There are two important differences here:
The variable declaration occurs after the static initializer block
The variable declaration includes an explicit assignment to null
The combination of those is messing you up: the variable initializers aren't all run before the static initializer - initialization occurs in textual order.
So you're populating the collection... and then setting the reference to null.
Section 12.4.2 of the JLS guarantees it in step 9 of the initialization:
Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.
Demonstration code:
class Foo {
private static String before = "before";
static {
before = "in init";
after = "in init";
leftDefault = "in init";
}
private static String after = "after";
private static String leftDefault;
static void dump() {
System.out.println("before = " + before);
System.out.println("after = " + after);
System.out.println("leftDefault = " + leftDefault);
}
}
public class Test {
public static void main(String[] args) throws Exception {
Foo.dump();
}
}
Output:
before = in init
after = after
leftDefault = in init
So the solution is either to get rid of the explicit assignment to null, or to move the declarations (and therefore initializers) to before the static initializer, or (my preference) both.
The static initializer will get called when the class is loaded, which is normally when it is first 'mentioned'. So calling a static method would indeed trigger the initializer if this is the first time that the class gets referenced.
Are you sure the null pointer exception is from the allcountries.get(), and not from a null Country returned by get()? In other words, are you certain which object is null?
Theoretically, static block should get executed by the time classloader loads the class.
Country country = Country.findByISO("RO");
^
In your code, it is initialized the first time you mention the class Country (probably the line above).
I ran this:
public class Country {
private static Map<String, Country> allCountries;
static {
allCountries = new HashMap<String, Country>();
allCountries.put("RO", new Country());
}
public static Country findByISO(String cc) {
return allCountries.get(cc);
}
}
with this:
public class Start
{
public static void main(String[] args){
Country country = Country.findByISO("RO");
System.out.println(country);
}
}
and everything worked correctly. Can you post the stack trace of the error?
I would say that the problem lies in the fact that the static block is declared before the actual field.
Do you have allCountries = new HashMap(); in your static initializer block? The static initializer block is actually called upon class initialization.

Categories

Resources