Static Initialization in Java? - java

I was trying to execute the following code:
public class StaticTest {
private static List<String> dat1;
{
dat1 = new ArrayList<>();
}
private StaticTest(){
System.out.println(dat1.contains("a")); //Marked Line 2: this one is not throwing
}
public static void main(String[] args) {
System.out.println(dat1.contains("a")); //Marked Line 1: This line throws null pointer
new StaticTest();
}
}
I tried to execute the above code, I got Null pointer exception at Marked Line 1. But when I commented Marked Line 1 I got the output.
Why am I getting the exception in first case and not in second ?
When I use private static List<String> dat1= new ArrayList<>();, no exception is thrown.

Simple:
System.out.println(dat1.contains("a"));
runs a constructor (because it is inside the constructor!).
And part of running the constructor is: to run all non-static initializer blocks of a class.
Whereas:
public static void main(String[] args) {
System.out.println(dat1.contains("a")); //Marked Line 1: This line
does only run your static initializers - but no constructor code (it does - but after that line).
So your problem is that this initializer block:
{
dat1 = new ArrayList<>();
}
isn't static!
In other words: your problem is caused by mixing static/non-static in very unhealthy ways. If a field is static, make sure that a static init code will initialize it.
Btw: the reasonable solution is to simply do:
private final static List<String> data = new ArrayList<>();
This makes sure that the list is initialized as soon as possible; and then compiler will even tell you when you forgot to initialize it.

This code
{
dat1 = new ArrayList<>();
}
This constructor block. Which will be executed every constructor after super() , so it will not run on Mark1 yet.
If you have code like this, it will be executed when class is loaded.
static {
dat1 = new ArrayList<>();
}
more detail here
http://www.jusfortechies.com/java/core-java/static-blocks.php

Hi #kajal please refer to the correct code below:-
public class StaticTest {
private static List<String> dat1;
static
{
dat1 = new ArrayList<String>();
}
private StaticTest(){
System.out.println(dat1.contains("a")); //Marked Line 2: this one is not throwing
}
public static void main(String[] args) {
System.out.println(dat1.contains("a")); //Marked Line 1: This line throws null pointer
new StaticTest();
}
}
Instance block is executes when you create a instance of that class.
Question why you are getting the NullPointerException :-
Please find the below flow of the StaticTest class execution :-
First all the import class will load like :-
Object class 2.java.lang Package Class 3.java.util.ArrayList Class.
The compiler goes through the StaticTest Class and allocate the Memory for the all the Static Members in your case it is dat1.
Now the javac compiler searches for the Static block for the execution. in your case their is no Static block.
Now the compiler executes the main method and executes the System.out.println(dat1.contains("a")); is called as null.contains("a"); which trhows the execption but as i said the Instance block is executes when you create a instance of that class. so dat1 is initialized when you create object new StaticTest();

Your code:
{
dat1 = new ArrayList<>();
}
Is a non-static initializer. This is called, when you are calling the constructor with: new StaticTest(). After that dat1 will be initialized.
You can change your code to static initializing by preceding it with the static keyword:
static
{
dat1 = new ArrayList<>();
}
Then it will work for both cases.

Related

Calling a method on an Object from within a Class vs from within a method

This might be a really elementary question but it puzzles me at this stage of my Java learning.
I have got the following piece of code:
package com.soti84;
import java.util.ArrayList;
public class InvokeMethod {
public static void main(String[] args) {
ArrayList<String> exams= new ArrayList<String>();
exams.add("Java");
exams.add("C#");
}
}
If I move the line that instantiates the ArrayList object and the calls on that object outside the method, the line that creates the object is fine but the add() method calls on the object are not allowed. Why is that?
package com.soti84;
import java.util.ArrayList;
public class InvokeMethod {
ArrayList<String> exams= new ArrayList<String>();
exams.add("Java");
exams.add("C#");
public static void main(String[] args) {
}
}
Thanks.
You simply can't do that code outside of methods. If you wanted to do this you would need initializer block or static block.
public class InvokeMethod {
ArrayList<String> exams= new ArrayList<String>();
{
exams.add("Java");
exams.add("C#");
}
Now that block is gonna execute when you create an instance. If your variable was static, you could make that block static (just add static before that block). Static block is gonna execute when your class is initialized. Those blocks can be quite convenient when you need a populated static list/map. Ofcourse, everything that is convenient in programming is probably a bad practice, and same here, those blocks are frowned upon by some people, they can be quite dangerous and lead to hard-to-find bugs (mostly about the order of execution).
In the two examples you are trying to achieve two totally different things.
In the first example you declare the ArrayList inside the main method, therefore the scope of the list will be just this method. The enclosing class has absolutely no connection with that ArrayList.
In the second one you try to create a data member called exams in the class InvokeMethod. That means, every instance of this class will have its own list.
The addition of the elements does not work, because "out of the methods" only declaration and initialization can happen. To fix that, you can use an initialization block:
public class InvokeMethod {
ArrayList<String> exams = new ArrayList<String>();
{
exams.add("Java");
exams.add("C#");
}
public static void main(String[] args) {
}
}
or, the constructor of the class:
public class InvokeMethod {
ArrayList<String> exams = new ArrayList<String>();
public InvokeMethod() {
exams.add("Java");
exams.add("C#");
}
public static void main(String[] args) {
}
}
Note: You can also retrieve this list from main method via an instance of the InvokeMethod class:
public class InvokeMethod {
ArrayList<String> exams = new ArrayList<String>();
public InvokeMethod() {
exams.add("Java");
exams.add("C#");
}
public static void main(String[] args) {
InvokeMethod invokeMethod = new InvokeMethod();
System.out.println(invokeMethod.exams.toString());
invokeMethod.exams.add("Delphi");
System.out.println(invokeMethod.exams.toString());
}
}
will print
[Java, C#]
[Java, C#, Delphi]
That's because "you're calling it from outside the function/method"
ArrayList<String> exams= new ArrayList<String>();
The line above means you're declaring it as the property of an Object. which means you can only access it inside a Method.
If you're going to place the following in your Main
exams.add("Java");
exams.add("C#");
This should work just fine, although you declared the "exams" outside the method.
As per Java language specification, class body declaration has Instance Initializer but don't has method invocation. So in your example ArrayList<String> exams= new ArrayList<String>(); is allowed inside class body but not exams.add("Java");
JLS excerpt :
ClassBody:
{ ClassBodyDeclarationsopt }
ClassBodyDeclarations:
ClassBodyDeclaration
ClassBodyDeclarations ClassBodyDeclaration
ClassBodyDeclaration:
ClassMemberDeclaration
InstanceInitializer
StaticInitializer
ConstructorDeclaration
ClassMemberDeclaration:
FieldDeclaration
MethodDeclaration
ClassDeclaration
InterfaceDeclaration
;

How is it possible to create object in Class definition itself?

I have some doubt on how this works, consider a simple Java program:
package com.example;
public class Test {
public static void main(String[] args) {
Test t = new Test(); (1) <---- How is this possible
t.print();
}
public void print() {
System.out.println("This is demo");
}
}
This is pretty straightforward program.
However, I have doubt at (1). We are creating an instance of Test, but this is still in the definition of Class Test. How is this possible?
Any explanation to help this would be great.
The instance will be created at run-time.
By then, compile-time is over and all of the code of your application (including all class definition) will be "ready".
Even if you call a constructor of a class that has not been encountered by the JVM up to that point, it will dynamically load the class (in its entirety) before executing the constructor call. Note that a) this might actually fail at run-time, in which case you get a ClassNotFoundError, and b) that cannot happen in your case, because you are calling the constructor of the class from itself (so it must have been loaded already).
The compiler does not run any of your code (not even things like static initializers) during compilation.
But it does make sure (during compilation) that every method or constructor that you are trying to call does in fact exist. Again, this could theoretically fail at runtime (if you mess up class files), in which case you would get a NoSuchMethodError.
First We have to Compile this Porgram using javac After Compilation It will give a Class File.
Now time to Execute Your Class Using java which Invokes JVM and load the Class File to the Class Loader.
java fileName.Class
And here
public static void main(String[] args) {
Test t = new Test(); (1) <---- How is this possible
t.print();
}
All we know static Content (either it is Variable or Method In Java) Of class loaded when ClassLoader loads a Class
As You see Main Method is a static Method. and So, It will Automatically Load into the ClassLoader with class File.
Now JVM First find the public static void main(String... args) in class. Which is a static Content means Its a part of Class but not a part of Class Instance. There is no need of Class Instance to Invoke this MainMethod`.
main(String... args) will be Invoked without getting Instance of the Class. In that Main Method , Your Class is Getting Instantiated
Test t = new Test(); \\here t is reference Variable to Test Class Object.
Now Because Class is loaded into the class Loader new Test(); will create a New Object in Heap memory Area of JVM and your method
public void print() {
System.out.println("This is demo");
}
will be invoked using t.print() Which is a Instance Method (Not Static), So It needs Class Instance to Invoke print() Method.
Q: Test t = new Test(); (1) <---- How is this possible
A: Because of the "static" in public static void main(String[] args)
The "static" means that method "main()" is independent of any specific class object.
You can create any class object you want - including a new "Test" object.
One of the benefits of defining "main" to be static is that you can use "main()" as a test method for the class. Each class can have it's own "main", and you can test each class individually by specifying that class in your Java command line.
For example:
public class MyClass {
public int add2(int n) {
return n + 2;
}
public static void main (String[] args) {
MyClass unitTest = new MyClass ();
System.out.println ("add2(2)=" + unitTest.add2(2));
System.out.println("Expected result=4");
}
}
Then test as follows:
javac MyClass.java
java MyClass
add2(2)=4
Expected result=4
This question has actually been asked and answered many times. For example:
Why is the Java main method static?
==================================================================
Here are a few more examples that illustrate the point:
public class CreateMyself {
private int value = 0;
private static CreateMyself m_singleton = null;
// EXAMPLE 1: You can legally create an instance in the constructor ...
public CreateMyself () {
value++;
// CreateMyself o = new CreateMyself (); // BAD!!! This will cause infinite recursion and crash your stack!!!
System.out.println ("Leaving constructor, value=" + value + "...");
}
// EXAMPLE 2: You can legally create another instance in a normal class member
public void createAnother() {
// But ... WHY??? Is there anything you can't do directly, in your own instance?
CreateMyself newInstance = new CreateMyself ();
System.out.println ("Leaving createAnother, value=" + value + "...");
}
// EXAMPLE 3: This is a common idiom for creating a "singleton"
// NOTE: for this to work, you'd also make the constructor PRIVATE (or protected), so the client *must* call "getInstance()", instead of "new".
public static CreateMyself getInstance () {
if (m_singleton == null) {
m_singleton = new CreateMyself ();
}
System.out.println ("returning singleton instance...");
return m_singleton;
}
// EXAMPLE 4: Creating an instance in "static main()" is a common idiom
public static void main (String[] args) {
CreateMyself newInstance = new CreateMyself ();
newInstance.createAnother ();
}
}
There are many other possible uses. For example, maybe you'll have a static method that does a database lookup and returns a list matching objects.
Note that most of the cases where it's really useful for a class to have a method where it creates an instance of itself are probably static methods.

Android:I do not understand: static { foo();} [duplicate]

This question already has answers here:
What is the difference between a static and a non-static initialization code block
(9 answers)
Static Block in Java [duplicate]
(7 answers)
Closed 7 years ago.
Sometimes I see something like it, in a class in Android:
static
{
foo();
}
What does this do?
Why?
That's a static block. It is executed the first time that class is referenced on your code, and it is calling a static method called foo(). You can find more about the static block here. As mentioned by #CommonsWare, you can initialize a static field in two different ways, inline a declaration time
static ArrayList<String> test = new ArrayList<String>() {{
add("A");
add("B");
add("C");
}};
but as you can see it is not easy to read. If you use a static block instead
static ArrayList<String> test;
static {
test = new ArrayList<>();
test.add("a");
test.add("b");
test.add("c");
}
or as in your question have
static ArrayList<String> test;
static {
foo();
}
private static void foo() {
test = new ArrayList<>();
test.add("a");
test.add("b");
test.add("c");
}
A static class member means it can be called without having an instance of a variable.
e.g.
class my_class
{
static void my_static_function()
{
// whatever
}
}
You can call it in both ways:
my_class::my_static_function();
my_class m;
m.my_static_function();
It's a static initializer block, which are used for initializing static variables. These are run once for the life of a class (not each time you create an instance). For example, you may want to populate a static data structure in a way that can't be done usually.
There are also non-static initializer blocks. These are run every time an instance is created. They're often used to initialize the variables of anonymous classes. It's useful to know that these execute before the constructor.
class BlockTest {
static {
System.out.println("Static block.");
}
{
System.out.println("Non-static block.");
}
public BlockTest() {
System.out.println("Constructor.");
}
public static void main(String[] args) {
new BlockTest();
}
}
This code will output the following:
Static block.
Non-static block.
Constructor.

Java Access Modifier and NullPointerException

I am getting a runtime error in my Java code, and I'm trying to understand the reason behind it. The two static access modifiers between double asterisks are the items in question. The code compiles with or without these modifiers (asterisks removed of course). But at runtime, it only runs without an error when the modifiers are present. Why is this? The error generated at runtime when the static modifiers are not present is pasted below the code. Thank you so much for your help!
Here is the code:
public class Blue {
public int[][] multiArray(int x, int y){
int[][] myArray = new int[x][y];
return myArray;
}
static Blue blueObject = new Blue();
public **static** int[][] one = blueObject.multiArray(3,3);
public **static** int[][] two = blueObject.multiArray(3,3);
public static void main(String[] args){
System.out.println("Hello world!");
}
}
Error generated at runtime without the static access modifiers:
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.NullPointerException
at Blue.<init>(Blue.java:13)
at Blue.<clinit>(Blue.java:11)
The issue is related to how JVM deals with class loading and how your class is defined.
When you have static int[][] one, it works because JVM read/load static code by the same order as they represented in the class. So when JVM tries to initialize int[][] one, the static Blue blueObject is ready for use.
However if you declare int[][] one as non-static, when JVM try to create static Blue
blueObject, it has to create a fully initialized Blue object and assign it to static blueobject, so it tries to initialize the int[][]; but at this moment, your static blueObject.multiArray(3,3); is not ready yet.
I hopethis make sense to your question.
It's because you declared blueObject as static, chang the definition to:
Test blueObject = new Test();
and it will run!
Either work in "singleton mode" (everything is static) or in "object mode" (where you create an object and call the class methods through the object) - you can't have both.
#user1419674
Normally JVM will initialize static variables first and then instance variables. And also the static variables are initialized only once at the first time the code is invoked.
public class Test {
public Test(){
System.out.println("constructor of class Test");
}
}
public class App {
private Test test = new Test();
private static int s_i;
static {
s_i = 1;
System.out.println("initializing static field");
}
public static void main(String args[]) {
App app1 = new App();
App app2 = new App();
}
}
Running code above will print out :
initializing static field
constructor of class Test
constructor of class Test
However, in your code, the static variable is of type of Blue itself. And the it becomes like the initialization of static Blue blueObject depends on the initialization of int[][] one which in true requires static Blue blueObject.

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