I have a question regarding static blocks:
Let's say i've got a class looking like this:
class SomeClass {
static {
System.out.println("static block");
}
}
and I define a variable of type SomeClass somewhere.
public static void main(String args[]) {
SomeClass foo;
}
Now i thought the static block would have been executed but it wasn't. As far as i know the static block is executed as soon as the classloader loads the SomeClass class. Now to my real question:
Isn't the class loaded as soon as I define a variable of that type?. If yes why isn't the static block executed?
If the answer should be no, then how can i know if a class has already been loaded by the class loader and what are the different possibilities to have the class loaded (I know of 2: initializing the variable & using a static field/method)
Refer to this doc: http://www.javaworld.com/article/2077260/learn-java/learn-java-the-basics-of-java-class-loaders.html
So when are classes loaded? There are exactly two cases: when the new bytecode is executed (for example, FooClass f = new FooClass();) and when the bytecodes make a static reference to a class (for example, System.out).
In your example, SomeClass foo; does neither execute the bytecode of SomeClass nor make a static reference to SomeClass. That's why the class is not loaded.
So following your example, add a static field in the class
public class SomeClass {
static {
System.out.println("static block");
}
static String abc = "abc";
}
SomeClass is loaded in either:
SomeClass foo = new SomeClass();
Or
System.out.println(SomeClass.abc);
Isn't the class loaded as soon as I define a variable of that type?.
Yes, it is loaded1, but it won't be initialized as a result of declaring a variable. However, when you create an instance of that type, or access a static field of that type, that is sufficient to trigger initialization, including the execution of static blocks.
See this related Q&A - When does static class initialization happen? - which lists all of the things that can trigger initialization.
How can i know if a class has already been loaded by the class loader and what are the different possibilities to have the class loaded (I know of 2: initializing the variable & using a static field/method)
The only ways I can think of for finding out when a class is loaded (as distinct from initialized) are:
turning on the JVM's class loader messages (using -verbose:class), or
using a customer classloader that notices, and does something appropriate when it sees a request to load the class.
A class is actually going to be loaded:
when it is explicitly loaded using Class.forName or similar, or a direct call to a classloader,
when it is necessary to load it in order to link another class, or
at JVM launch time, if the class is named as the entry point class.
The loading / linking / initializing steps are specified in Chapter 12 of the JLS.
1 - In fact, SomeClass needs to be loaded at the same time that the class containing that main method is linked; i.e. before the method containing that local declaration is called.
Related
I couldn't find anything about this online, because I didn't know what to search for, but Java doesn't mark this code as having an error:
public class Test {
// ...
{
int test;
}
// ...
}
Does this serve any purpose in Java? If so, what?
This is called an instance initializer (JLS section 8.6)
When creating an object the instance initializer is run after super constructors but before the called constructor of the class they are defined in. See JLS 12.5 Creation of New Class Instances. Specifically, instance initializers are evaluated in step 4 of the object creation process. The key point is that instance initiailzers always get called no matter what constructor is used to instantiate the object.
There are also static initializers which are similar but marked with the static keyword.
public class Test {
static {
// Do something interesting on class load.
}
}
In my experience static intiailzers are more common as you can use them to setup complex class state (like linking JNI libraries) when the class is loaded.
We cant access non static instance from a static method. But main() method is static and runs first. During initialization of any other class in main method, it will call the constructor. Is that constructor static ? what is the basic flow for JVM ?
The main method is called by the JVM to run the method which is outside the scope of project.
When the JVM calls the main method, there is no object existing for the class being called. So it has to have static method to allow this from class.
During initialization of any other class in main method, it will call the constructor.
If you mean instantiation, then Yes it will. Creating an instance of a class calls the constructor, whether the new call is made in main or anywhere else.
If you really do mean class initialization (which typically happens implicitly), then No it won't. The initialization of a class does no involve the classes constructors.
For example
public class Example {
private static int foo = OtherClass.someMethod();
static {
// do something
}
public Example() {
// do something
}
}
Class initialization executes the initializer for foo and the static initializer block, but is doesn't execute the constructor. Creating an instance of Example calls the Example() constructor.
Is that constructor static ?
Constructors are always static ... in the sense that new doesn't require an existing instance.
Yes, we can't access non-static variables from static block because, non-static variable are instance variables & can only be accessed by creating an object of class with new operator or using reflection like Class.newInstance(). Whereas, static variables are class level & it's value is constant for every single object. It means no need to create an object of a class to access those variables. You can access static variable by using class name (different class) or directly (within same class) like :-
public class HelloWorld {
private static String message = "Hello";
public static void main(String[] args) {
System.out.println(message);
System.out.println(HelloWorld1.sayHello);
}
}
public class HelloWorld1 {
public static String sayHello = "Hello1";
}
main() method :
public static void main(String[] args) {}
In Java, main() method is static & it's the entry point of JVM. Since, main() method doesn't belong to any class in Java. When we define main() method in any user-defined class, then it will belong to that class. And since it's static & within the same class, no need to access it using class name. The main method is directly available to JVM.
How JVM works :
When there is need to execute to any Java class ClassLoader comes into picture. The Java Classloader is a part of the Java Runtime Environment that dynamically loads Java classes into the Java Virtual Machine.
Image taken from : Understanding JVM Internals
When JVM starts to execute a Java file, it'll
First compile .java file & convert it into .class file which contains bytecode i.e, machine language or assembly language. Each time the same bytecodes are processed, JVM works with JIT (Just-In-Time) compiler to convert byte code into native code.
Loads the .java file & necessary packages using System Class Loader & BoostrapperClassLoader resp.
After loading, JVM will look into .class file & store all information like variables, packages, methods, etc & save them into a memory & initialize all the field variables.
The JVM then starts interpreting bytecode & displays the result of that in human readable form.
I have a class:
public class Foo {
public static boolean flag = false;
//some code
}
I am using this boolean flag in another class:
public class FooImpl{
public static void main (String args[]) {
if (Foo.flag){
//Line 1
//some code
}
}
}
So at Line 1, does class Foo gets fully loaded in the memory or just the static variable gets loaded with default value?
A classes static initialization normally happens immediately before the first time one of the following events occurs:
an instance of the class is created,
a static method of the class is invoked,
a static field of the class is assigned,
a non-constant static field is used, or
See JLS 12.4.1.
The class gets loaded when there is a static reference to the class. It is loaded by ClassLoader [java.lang.ClassLoader].
when you access a class member or constructor [creating an instance of that class] you need information about the class and it gets loaded.
you might have seen some ClassNotFoundException for some library function calls. The ClassLoader is behind that.
But there is other fact that the class gets initialized when something in the class is used first.
Initialization of a class consists of executing its static initializers and the initializers
for static fields (class variables) declared in the class.
In line 1 you are referring to a member of class and its loaded for sure.
Initialization Occurs:
T is a class and an instance of T is created.
T is a class and a static method declared by T is invoked.
static field declared by T is assigned.
A static field declared by T is used and the field is not a constant variable
T is a top level class, and an assert statement lexically nested within T is executed.
A reference to a static field (§8.3.1.1) causes initialization of only the class or
interface that actually declares it, even though it might be referred to through the
name of a subclass, a subinterface, or a class that implements an interface.
I have 2 jars, let's call them a.jar and b.jar.
b.jar depends on a.jar.
In a.jar, I defined a class, let's call it StaticClass. In the StaticClass, I defined a static block, calling a method named "init" :
public class StaticClass {
static {
init();
}
public void static init () {
// do some initialization here
}
}
in b.jar, I have a main, so in the main, I expect that the init() method has been called, but actually not. I suspect that is because the StaticClass has not been loaded by the jvm, could anyone tell me
Is my conclusion correct?
What triggers the jvm to load a class?
How can I get the static block executed automatically?
Thanks
Yes, you are right. Static initialization blocks are run when the JVM (class loader - to be specific) loads StaticClass (which occurs the first time it is referenced in code).
You could force this method to be invoked by explicitly calling StaticClass.init() which is preferable to relying on the JVM.
You could also try using Class.forName(String) to force the JVM to load the class and invoke its static blocks.
Yes you are right, since you are not using your StaticClass it is not loaded by the vm and therefore init() is never executed.
For your second question, you probably have to go the hard way and scan all available classes and load them.
https://stackoverflow.com/a/3223019/393657
First of all class loading is different than class initialization. For anyone looking for explanation from Java Language Specification, when is static block executed - here it is.
The JLS §8.7 says that :
A static initializer declared in a class is executed when the class is initialized (§12.4.2).
So what does the initialization mean? Let's refer to JLS §12.4.2. This describes detailed initialization procedure. However point JLS §12.4.1 might be more appropriate here. It says that :
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.
So to make the static initializer block to be executed automatically, you have to force one of those options to happen.
You are right, the easiest way is to access the class, for instance do a
StaticClass.class.newInstance();
Or something to that respect in your main method. This will ensure the class is loaded by the classloader.
The static code is executed when your class (StaticClass I guess) is referenced.
Thus, it should be executed if you create a new instance of StaticClass or if you call one of its static methods.
Static block is executed when a loaded class is initialized or referenced first. Loading class doesnt mean that class is to initialized. JVM Class Loading is separate things to concern.
Yes, the static initializer will be executed when the class is loaded. This normally occurs when you access the class in the class loading context for the first time.
in b.jar main method class should extend that StaticClass then automatically that static block and init() will be invoked
Adding some more:
static block will be executed when jvm load class.
Here in your example you can call init() method of your StaticClass by intantiating class
like
StaticClass staticClass=new StaticClass();
or
StaticClass.class.newInstance(); this is more preferebal
By default, Sun's JVM both lazily loads classes and lazily initializes (i.e. calls their <clinit> methods) them. Consider the following class, ClinitBomb, which throws an Exception during a static{} block.
public class ClinitBomb {
static {
explode();
}
private static void explode() {
throw new RuntimeException("boom!");
}
}
Now, consider how to trigger the bomb:
public class Main {
public static void main(String[] args) {
System.out.println("A");
try {
Class.forName("ClinitBomb");
} catch (Exception e) {
e.printStackTrace(System.out);
}
System.out.println("B");
ClinitBomb o2 = new ClinitBomb();
System.out.println("C");
}
}
We're guaranteed the explosion happens before point B, since forName's documentation says so; the question is whether it happens before point A (when Main is loaded.) In Sun's JVM, even though main() contains a static reference to ClinitBomb, it happens after A.
I want a way to tell the JVM to load and initialize ClinitBomb as soon as it initializes Main (so the bomb explodes before point A.) In general, I want a way to say, "whenever loading/initializing class X, also do so for any classes Y it references."
Is there a way to do that?
There is no way to do this. The JLS says, in §12.4.1 When Initialization Occurs (emphasis mine):
Initialization of a class consists of executing its static initializers and the initializers for static fields declared in the class. [...]
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, and an assert statement (§14.10) lexically nested within T is executed.
Invocation of certain reflective methods in class Class and in package java.lang.reflect also causes class or interface initialization. A class or interface will not be initialized under any other circumstance.
A Java implementation which initialized classes as soon as they were loaded would violate the JLS.
Although what you could do would be to use the JVM instrumentation API to write a ClassFileTransformer which added a static block to every class which explicitly initialized its referenced classes (via Class.forName, probably). As soon as one class gets initialized, all the classes reachable from it will be initialized. That might give you the result you're after. It's quite a lot of work, though!
Class.forName("...", true /*initialize*/, getClassLoader());
You were halfways there.