I know that Java uses the ClassLoader hierarchy for loading the classes.
For example a program:
public void test(){
A a = new A(); // Line 1 The class is accessed first time here so it should be loaded and defined
A ab = new A(); //Line 2 How can the second line be represented?
}
The first line of the code is similar to
Thread.currentThread().getContextClassLoader().loadClass("A");
So the class is loaded and defined to create instance of Class.
Now the question is when the second line is executed the Class A is referred again, will Java not lookup for the class again and return the same loaded instance of the Class?
As the Java classloader document says that every class loader should maintain the instances of loaded classes and return the same instances for the next call.
Where does Java keep the loaded classes? ClassLoader class has a Vector of classes which is called by VM to add the loaded classes.
Maybe the question is a bit confusing, basically I am trying to figure out from which method are the already loaded classes returned. I tried to keep a debug point in the loadClass() method but it is not called for the Line 2.
The loadClass() method of ClassLoader has findLoadedClass method but that too is not called.
If you want to "translate" the mention of A to any method call, then the closest you could get is not loadClass() but Class.forName().
This method call queries the classloader for the class, which may or may not trigger class loading (and the caller doesn't even care). It will simply return a fully loaded (and initialized, if you don't use the three-argument version) class back to the caller.
And once the class has been loaded, the class loader no longer get's invoked when the class is used (as the name suggests, it's job is done, once it loaded the class).
package java_language;
public class NewClass {
Java_language j;
public NewClass() throws ClassNotFoundException {
j=new Java_language();
if (Class.forName("java_language.Java_language", true, Thread.currentThread().getContextClassLoader()).equals(j.getClass())) {
System.out.println("CLass has been loaded");
}
}
public static void main(String[] args) throws ClassNotFoundException {
new NewClass();
}
}
package java_language;
public class Java_language {
static Java_language java_language = null;
public Java_language() {
System.out.println("Stack Overflow");
}
}
Ans is:
enter image description here
Related
In normal Java class, when VM load a class, it will invoke clinit method, so I wonder know when VM load a interface, can it invoke some code?
for example, class B implements A, new B(), VM invoke clinit of B, what will VM do with A, in A can I insert some code like System.out.println("hello")
Directly not, Java interfaces are not supposed to contain any code, even if you can now have default method. Following code will not compile:
interface Foo {
init {
System.out.println("Loading Foo...");
}
}
However, interfaces can contain static fields:
interface Foo {
static class FooLoader {
private static Object init() {
System.out.printf("Initializing %s%n", Foo.class);
}
}
Object NULL = FooLoader.init();
}
Again, it may work BUT:
through Reflection, it's still possible to invoke init() method, so it can be called twice
code isn't really called at load time but at init time. To understand, what I mean check this simple main:
System.out.println("START");
System.out.println(Foo.class);
System.out.println("END");
As long as you don't access static members, Java interfaces are not initialized (See ยง5.5 of JVM Specification)
So, to truely catch load time, you can use a custom class loader, or instrumentation API.
Having static {} block in interfaces isn't possible. But if you are really certain that you need to invoke some code when loading interface you can use custom classloader which will hook your interface loading and perform some action on that
Here is an example:
static class MyClassLoader extends ClassLoader {
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals("test.Test1")) {
... do whatewer you need on loading class/interface...
}
return getParent().loadClass(name);
}
}
}
How to replace classes in a running application in java ?
Also there is very usefull tutorial: https://zeroturnaround.com/rebellabs/reloading-objects-classes-classloaders/
As mentioned in another answers, you cannot have static section in interfaces. However you can have static methods and static final fields. You can combine both for debugging purposes.
interface TestInterface {
int dummy = init();
static int init() {
System.out.println("Loaded TestInterface");
return 1;
}
}
So I have two projects A and B, and project B is imported in project A, and in project B I want to initialize some objects which have static initializers.
The problem is, they aren't getting called (already tested with final keyword, does not help).
So I actually want to have a small system and it should go this way (every class decribed here are in project B):
class A is a main class in which you can call a method addClassToLoad()* to add other classes (which will be "loaded" when method start() in class A will be called);
classes B, C and D call method addClassToLoad() from its static initializer;
when some class from project A calls a method start(), class A lists all classes it has gotten and calls a method onLoad() (explained in *).
And every method is static, so it's meant to be only one (no "instancing").
Saddly, static initializers aren't getting called.
And the question is: do I do something wrong (or maybe it is not possible at all) or maybe there is another way to do this small system? (I just don't really want to write in class A about every class, which must be loaded at start() method)
*addClassToLoad() takes an interface which has one method onLoad(), so it is getting called when method start() is called in class A
In code version:
class A:
public class A {
private static ArrayList<ClassToLoad> classesToLoad;
public static void addClassToLoad(ClassToLoad c) {
if (classesToLoad == null)
classesToLoad = new ArrayList<ClassToLoad>();
classesToLoad.add(c);
}
public static void start() {
for (ClassToLoad c : classesToLoad) {
c.onLoad();
}
}
}
class B (and others (C, D etc.) like this one):
public class B {
static {
A.addClassToLoad(new ClassToLoad() {
public void onLoad() {
load();
}
});
}
private static void load() {
// do something here on load ...
}
}
class ClassToLoad:
public interface ClassToLoad {
public void onLoad();
}
This is the same question when you add a new JDBC driver, why you have to call Class.forName() to register a JDBC driver. Every JDBC driver class has a static initializer to register itself with DriverManager. Why? A class loader does not by default load all the classes in jar files. A class is loaded only when it is referenced during execution, which is smart as the class loader never has to load those unused classes into memory. So to resolve your issue, you have to manage to load those classes, like by Class.forName() before you call start(). If you use spring, you can create a list of all those classes in your configure. Spring also provides an util to scan packages for certain types of classes, then you can just specify a package name to scan.
Static fields will be set, and static initializers (static blocks) when ClassLoader will load class for the first time. Rembemer that this will happen when given class will be used for the first time as ClassLoader loads classes in lazy fashion (when needed)
So it seems it's not possible for me to execute those static blocks, so I added every class, which I need to load, into class A, and that way they're actually loading without any problems (in project B). And in project A I need to add other classes, which I need to load, in the main class, obviously.
So I made those classes as Singletons, so they're actually loaded and are ready for "main" loading, launching and disposing. So the adding class looks like this:
A.addClassToLoad(B.getInstance());
I used class ClassToLoad as a generic class to load (sounds funny), though I renamed it to SystemCycle.
So the code as an example of class B now looks like this:
public class B implements SystemCycle {
private static B instance = new B();
private B() {}
public static void getInstance() {
return instance;
}
public void onLoad() { /* some code here */ }
public void onLaunch() { /* some code here */ }
public void onDispose() { /* some code here */ }
}
And SystemCycle class looks now like this:
public interface SystemCycle {
public void onLoad();
public void onLaunch();
public void onDispose();
}
Well, that was obvious, because of example of class B.
And I even made small checking system, so if the user tries to call one of these methods, it will be ignored, as the class implementing SystemCycle checks whether the class A is actually loading, launching or disposing at that moment. But if not, it just can do return. (though if the usermade class doesn't check that, it can be abused by other usermade class).
P.S. addClassToLoad in my project is actually called addSystemToLoad, so I made it here this way to make an example easier to understand.
Small edit: I even tried something to do with annotations first, but even that thing didn't help me.
Are static variables initialised every time a new instance of the object containing these variables are created ? Or are they initialised just once when the object is first called?
You said
Are instance static variables initialised...
stop right there, the statement makes no sense. static variables live on the class, not on any particular instance. They are initialized in an initialization procedure that is run when an instance is created, a static method on the class is run, or a static variable on the class is accessed. (Full disclosure, #Bruno's answer led me to this information).
Static fields are initialized during the initialization of the class (don't mix initialization and loading, they are different things -- a class can be loaded, and you can do reflection on it, without ever initializing it).
Also, class initialization can happen more than once for a given class if you are using multiple ClassLoaders.
See VM Spec section 2.17.4, Initialization, and section 2.17.5, Detailed initialization procedure for more details on when exactly a class will be loaded and when exactly it will be initialized..
EDIT: trivial example that will show how a class can be loaded and initialized multiple times and that loading does not automatically imply initialization:
public class A { static { System.out.println("I've been initialized!"); } }
public class Main {
public static void main(String... args) {
ClassLoader cl = new URLClassLoader(..., null);
System.out.println("loading...");
Class<?> aClass = cl.loadClass("A");
// here you could perform reflection on aClass, without initializing it
System.out.println("Will be initialized now:");
Object o = aClass.newInstance();
System.out.println("Let's load once again...");
ClassLoader cl2 = new URLClassLoader(..., null);
Class<?> aClass2 = cl2.loadClass("A");
System.out.println("Will be initialized a second time:");
Object o2 = aClass2.newInstance();
// the following is false:
System.out.println("aClass1.equals(aClass2) = " + aClass1.equals(aClass2));
// the following is true:
System.out.println("aClass1.getName().equals(aClass2.getName())" + aClass1.getName().equals(aClass2.getName()));
}
}
(I hope this compiles when you specify the missing URL[] object in the URLClassLoader's constructor...)
Note that it is necessary to set the class loaders' parents null, otherwise their parents would be the main application class loader (ie, the same that loaded the class Main), then because Java delegates the loading to the parent class loader first by default, if the class A is in the class path, you would see the load and initialization only once.
Finally, note that Class.load("A") is not equivalent to classLoader.loadClass("A"). If you check the documentation of Class.load(String), you will see that this method loads and initializes the class. There's an overload of Class.load(...) that takes a boolean indicating if it should initialize the class or not.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Difference betweeen Loading a class using ClassLoader and Class.forName
AFAIK, two ways are provided in java to init a class from its name.
Class
public static Class forName(String
className) throws
ClassNotFoundException
public static Class forName(String
name, boolean initialize, ClassLoader
loader) throws ClassNotFoundException
ClassLoader:
public Class loadClass(String
name) throws ClassNotFoundException {
return loadClass(name, false);
}
The known thing is in forName method, we can specify the flag of initialize to be false ,this will skip some static things to be initialized for this class. But what's else?
And how should I use them correctly?
It's better you can show some good examples.
Thanks!
UPDATE:
After raised question,I made some simple classLoader test.
ClassLoader cls = ClassLoader.getSystemClassLoader();
Class someClass = cls.loadClass("Test");
Class someClass0= Class.forName("Test");
Class someClass1= Class.forName("Test",false,cls);
URL[] urls = new URL[] {new File("bin/").toURL()};
ClassLoader cls2 = new URLClassLoader(urls, null);
Class someClass2 = cls2.loadClass("Test");
ClassLoader cls3 = new URLClassLoader(urls, cls);
Class someClass3 = cls3.loadClass("Test");
System.out.println(someClass.equals(someClass0));
System.out.println(someClass.equals(someClass1));
System.out.println(someClass.equals(someClass2));
System.out.println(someClass.equals(someClass3));
The result is
true,true,false,true
UPDATE
Here is my answer about
Difference between loadClass(String name) and loadClass(String name, boolean resolve)
Consider this code
class X
{
static{ System.out.println("init class X..."); }
int foo(){ return 1; }
Y bar(){ return new Y(); }
}
The most basic API is ClassLoader.loadClass(String name, boolean resolve)
Class classX = classLoader.loadClass("X", resolve);
If resolve is true, it will also try to load all classes referenced by X. In this case, Y will also be loaded. If resolve is false, Y will not be loaded at this point.
There doesn't seems to be any good reason for resolve=true. If nobody calls X.bar(), Y will never be needed, why should we load it at this point? And if Y is missing or corrupt, we'll get an error trying to load X, which is totally unnecessary.
Interestingly, this method is protected, so it's not easy to invoke it.
Another method loadClass(name) simply calls loadClass(name,false). It's public, and it takes the sensible choice of resolve=false. So it is exactly what's needed by developers.
ClassLoader only loads classes, it does not initialize classes. We can inspect the class metadata, e.g. its super class, its annotations, its methods and fields, etc. without triggering the static initialization execution. This fact is very important for frameworks.
Now, Class.forName
Basically, Class.forName(String name, boolean initialize, ClassLoader loader) calls loader.loadClass(name). And if initialize=true, the class is initialized - in the X example, we'll see "init class X..." printed.
Class.forName(name) is the same as forName(name, true, currentLoader).
Now, why would anyone want to initialize the class at this point? Wouldn't it be better if the class is initialized only when necessary? A famous use case is JDBC initializing:
Class.forName("com.mysql.jdbc.Driver");
The convention is, a JDBC driver class registers itself in its static initializer. The above code will trigger the static initialization, making the driver available for subsequent uses.
From today's point of view, that design is really odd. We usually don't rely on static initializers. So there isn't much justification for initialize=true, and Class.forName(name) should be avoided.
A "class literal" will return the class, without initializing it
Class c = com.mysql.jdbc.Driver.class;
// actually compiled to
Class c = Class.forName("com.mysql.jdbc.Driver", false, currentLoader);
Now, what the heck is the "currentLoader"? It is the class loader of the current class
class A
{
void foo()
{
currenLoader == THIS_A_CLASS.getClassLoader()
}
}
When X.bar() is invoked for the first time, a "Y" class is needed. what's happening is roughly
class X
bar()
// new Y();
Class classY = currentLoader.loadClass("Y");
Constructor cst = classY.getConstructor();
// next line will initialize Y (if not yet)
// creating an instance of a class requires it be initialized
Object y = cst.newInstance();
ClassLoader.loadClass(String name) will attempt to load the class using the specified classloader. Class.forName(String name) will attempt to load the class using the default system classloader hierarchy.
I come across to a strange behavior while trying to override a method with default accessor (ex: void run()).
According to Java spec, a class can use or override default members of base class if classes belongs to the same package.
Everything works correctly while all classes loaded from the same classloader.
But if I try to load a subclass from separate classloader then polymorphism don't work.
Here is sample:
App.java:
import java.net.*;
import java.lang.reflect.Method;
public class App {
public static class Base {
void run() {
System.out.println("error");
}
}
public static class Inside extends Base {
#Override
void run() {
System.out.println("ok. inside");
}
}
public static void main(String[] args) throws Exception {
{
Base p = (Base) Class.forName(Inside.class.getName()).newInstance();
System.out.println(p.getClass());
p.run();
} {
// path to Outside.class
URL[] url = { new URL("file:/home/mart/workspace6/test2/bin/") };
URLClassLoader ucl = URLClassLoader.newInstance(url);
final Base p = (Base) ucl.loadClass("Outside").newInstance();
System.out.println(p.getClass());
p.run();
// try reflection
Method m = p.getClass().getDeclaredMethod("run");
m.setAccessible(true);
m.invoke(p);
}
}
}
Outside.java: should be in separate folder. otherwise classloader will be the same
public class Outside extends App.Base {
#Override
void run() {
System.out.println("ok. outside");
}
}
The output:
class App$Inside
ok. inside
class Outside
error
ok. outside
So then I call Outside#run() I got Base#run() ("error" in output). Reflections works correctly.
Whats wrong? Or is it expected behavior?
Can I go around this problem somehow?
From Java Virtual Machine Specification:
5.3 Creation and Loading
...
At run time, a class or interface is
determined not by its name alone, but
by a pair: its fully qualified name
and its defining class loader. Each
such class or interface belongs to a
single runtime package. The runtime
package of a class or interface is
determined by the package name and
defining class loader of the class or
interface.
5.4.4 Access Control
...
A field or method R is accessible to a class
or interface D if and only if any of
the following conditions is true:
...
R is either protected or package private (that is, neither public nor
protected nor private), and is
declared by a class in the same
runtime package as D.
The Java Language Specification mandates that a class can only override methods that it can access. If the super class method is not accessible, it is shadowed rather than overridden.
Reflection "works" because you ask Outside.class for its run method. If you ask Base.class instead, you'll get the super implementation:
Method m = Base.class.getDeclaredMethod("run");
m.setAccessible(true);
m.invoke(p);
You can verify that the method is deemed inaccessible by doing:
public class Outside extends Base {
#Override
public void run() {
System.out.println("Outside.");
super.run(); // throws an IllegalAccessError
}
}
So, why is the method not accessible? I am not totally sure, but I suspect that just like equally named classes loaded by different class loaders result in different runtime classes, equally named packages loaded by different class loaders result in different runtime packages.
Edit: Actually, the reflection API says that it's the same package:
Base.class.getPackage() == p.getClass().getPackage() // true
I found the (hack) way to load external class in main classloader so this problem is gone.
Read a class as bytes and invoke protected ClassLoader#defineClass method.
code:
URL[] url = { new URL("file:/home/mart/workspace6/test2/bin/") };
URLClassLoader ucl = URLClassLoader.newInstance(url);
InputStream is = ucl.getResourceAsStream("Outside.class");
byte[] bytes = new byte[is.available()];
is.read(bytes);
Method m = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class, int.class });
m.setAccessible(true);
Class<Base> outsideClass = (Class<Base>) m.invoke(Base.class.getClassLoader(), "Outside", bytes, 0, bytes.length);
Base p = outsideClass.newInstance();
System.out.println(p.getClass());
p.run();
outputs ok. outside as expected.