The title says it all. I'm working on top of another project (aka working with Forge) and I want to put a certain class (class no. 1) on hold - not load it until another class (class no. 2) has been loaded. Then after that certain class (class no.2) has been loaded, the first class (class no. 1) should be normally loaded.
You can load your Class1 when Class2 gets loaded.
Class1 {
public static void loadMe() {}
}
class2 {
public Class2() {
// Calling a dummy static member for loading the class
Class1.loadMe();
}
}
The advantage is that both will be loaded by the same ClassLoader by default. Alternatively, you can,
Class.forName("Class1");
In both the cases, no one in the entire App should try to access any static member of this class or it will get loaded.
Related
I have a method where one of the class is getting loaded by passing the current class name.
This method is called from multiple places and multiple times.How many instances of the class is loaded into JVM. Does this impact the application performance.
Class TestClass{
public void load() throws Exception{
Class.forName(TestClass.class.getName());
}
}
I have instrumented JDK and application. Entry and exit points are recorded for call graph construction.
The call graph looks like
sun.misc.Launcher$AppClassLoader.loadClass->com.example.Main.main
->sun.misc.Launcher$AppClassLoader.loadClass->com.example.Foo.foo
Source code
public class Main{
public static void main(String[] args){
Foo.foo()
}
}
public class Foo{
public static void foo(){};
}
This must be how classloader works but I don't see anything shows in bytecode that indicate the call site "sun.misc.Launcher$AppClassLoader.loadClass". So, how does classloader work internally?
Classes are loaded lazily.
You can see this by writing code to print to the console within static initialisers.
The first time a class reference is used by any code loaded by a specific class loader, the JVM request the Class from the loader in the current thread. If the parent class loader hasn't loaded a class of the fully qualified name, then the current class loader will define it (or throw an exception).
In the early days applets would make a network connection for each class file.
I know Java loads Classes in first Access (creating new Instance, calling static method or static field), but in this simple example I try to execute a jar file that uses some classes which there aren't in my ClassPath at run time. I expect (because of loading classes in first access) print my messages in static block and main method before an exception occurred. but I got "Exception in thread "main" java.lang.NoClassDefFoundError: com/example/DateAbstract" and nothing printed.
This occurred when I used an abstract class or interface in main class which that classes or interfaces are in another jar file.
public class Driver {
static { System.out.println("I am first.[static block]"); }
public static void main(String[] args) {
System.out.println("I am first.[ main method]");
DateAbstract date = new CustomDate();
System.out.println(date.sayDate());
}
in my another jar :
public class CustomDate extends DateAbstract {
#Override
public String sayDate() {
return new Date().toString();
}
public abstract class DateAbstract {
public abstract String sayDate();
}
when I use this code for add my classes to classpath at runtime. nothing changed. I got execption before execute static block.
public class Driver {
static {
System.out.println("I am first.[static block]");
try {
URL url = new File("lib/DateApi.jar").toURI().toURL();
URLClassLoader urlClassLoader = (URLClassLoader) URLClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(urlClassLoader,url);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println("I am first.[ main method]");
DateAbstract date = new CustomDate();
System.out.println(date.sayDate());
}
}
Questions :
why is this happening and how to solve it ?
It’s not correct to say that in Java classes are loaded on their first access. You are confusing this with the initialization of a class, which implies executing the Java code of static initializer blocks and field initializers. The loading and verification might happen at an earlier time; the specification provides some freedom to the JVMs in this regard.
The key point here is that your main method instantiates an object of type CustomDate, stores it into a variable of the compile-time type DateAbstract and then tries to invoke sayDate() on that variable. This combination of instantiating CustomDate and invoking DateAbstract.sayDate() on it requires the verification of its correctness, i.e. whether CustomDate is a subtype DateAbstract. So the loading of these two classes will already happen at verification time.
You can easily check that this is the cause. If you change the type of the local variable date to CustomDate, the instantiated type and the receiver type of the method invocation are the same, so the correctness can be proven without loading the type, so it will be indeed deferred to the actual attempt to instantiate CustomDate, hence the messages will be printed.
Still, the loading time is an implementation-specific detail. A different JVM could load the referenced classes eagerly, even if they are not required for verification. The only safe way to ensure a deferred loading, is to use dynamic loading, e.g. Class.forName(String). Note that within the class detached this way, all types might be again referenced ordinarily. So if you do the dynamic loading once after the class path has been adjusted, there is not much impact on how you have to write the code nor its performance. Of course, having the code adjusting the class path and the code depending on it within the same class won’t work reliably.
I am trying the following wrt Refleciton, let me know if this is possible
public class A {
void start(){
execute();
}
}
public class B extends A {
void execute()
{
doWork();
}
public abstract void doWork();
}
I have the above classes packaged in a jar and have it running on a JVM.
Now I am trying to create another class at run time, compile it at run time and trying to use reflection to invoke Class B's execute function().
public class C extends B {
#Override
public void doWork()
{
//Implementation
}
}
Reflection code:
Classloader = urls of application jars and url of C.class, compiled at run time. Parent loader - Thread.currentThread().getContextClassLoader()
I am also setting the current thread's context class loader to the classloader created above.
Class<? extends B> cls = (Class<? extends B>) Class.forName("className", true, clsLoader);
Object obj = cls.newInstance();
Method method = obj.getClass().getSuperclass().getMethod("start", new Class[0]);
method.invoke(obj, new Object[0]);
I am able to get the method and the invoke also gets called. However when class B's execute is called, it is trying to call the doWork() and then I run into an AbstractMethodError. Upon looking up on the exception, I see that the exception happens with incorrect classloaders/jars.
But I am not sure how do I go about fixing it in my case.
Can anyone assist?
First of all, let’s clarify the myths about the context class loader of a Thread: unless code asks explicitly for that loader via Thread.getContextClassLoader() (and uses it), it has no relevance for class loading at all.
Each class has an initiating class loader which defined the class and references to other classes within that class are always resolved via that initiating class loader. This even applies to reflective loading via Class.forName(String) (without an explicit ClassLoader); it will use the initiating class loader of the caller.
If you want to load C via a custom class loader which needs to have access to B, because C subclasses it, the best way to determine the parent loader for the creation of your new loader is B.class.getClassLoader(). However, in your simple setup, it’s the same loader as returned by ClassLoader.getSystemClassLoader() which is also the default class loader as returned by Thread.getContextClassLoader(), that’s why it worked.
You know that it worked because you could load C successfully. While other references might be resolved lazily, the direct superclass must be resolved immediately, so B is in scope of C’s loader.
Assuming that the absence of a declaration of execute() in A or an abstract modifier on class B are just oversights made by posting the question, the reason why invoking the method doesn’t work is much simpler: the method abstract void doWork(); is not public.
Since B and C are loaded by different class loaders, they are considered to reside in different packages, regardless of their qualified name. Therefore, the method doWork() in C does not override the method doWork() in B. This hasn’t been detected at compile-time, as, at compile-time, there is no class loader hierarchy. So the compiler considers B and C to reside in the same package, based on their qualified name (or explicit package declaration). Therefore the compiler assumes that C.doWork() implements B.doWork() and C can be declared non-abstract.
If you declare the method doWork() in B as public, it should work. And it should work much simpler:
try(URLClassLoader l = new URLClassLoader(new URL[]{/* url pointing to C */})) {
l.loadClass("C").asSubclass(B.class).newInstance().execute();
}
When is static variable loaded, runtime or compile time? Can someone please explain it.
I would really appreciate the help.
Thank you.
The compiler optimizes inlineable static final fields by embedding the value in the bytecode instead of computing the value at runtime.
When you fire up a JVM and load a class for the first time (this is done by the classloader when the class is first referenced in any way) any static blocks or fields are 'loaded' into the JVM and become accessible.
A demonstration:
public class StaticDemo {
// a static initialization block, executed once when the class is loaded
static {
System.out.println("Class StaticDemo loading...");
}
// a constant
static final long ONE_DAY_IN_MILLIS = 24 * 60 * 60 * 1000;
// a static field
static int instanceCounter;
// a second static initialization block
// static members are processed in the order they appear in the class
static {
// we can now acces the static fields initialized above
System.out.println("ONE_DAY_IN_MILLIS=" + ONE_DAY_IN_MILLIS
+ " instanceCounter=" + instanceCounter);
}
// an instance initialization block
// instance blocks are executed each time a class instance is created,
// after the parent constructor, but before any own constructors (as remarked by Ahmed Hegazy)
{
StaticDemo.instanceCounter++;
System.out.println("instanceCounter=" + instanceCounter);
}
public static void main(String[] args) {
System.out.println("Starting StaticDemo");
new StaticDemo();
new StaticDemo();
new StaticDemo();
}
static {
System.out.println("Class StaticDemo loaded");
}
}
Output:
Class StaticDemo loading...
ONE_DAY_IN_MILLIS=86400000 instanceCounter=0
Class StaticDemo loaded
Starting StaticDemo
instanceCounter=1
instanceCounter=2
instanceCounter=3
Notice how 'Starting StaticDemo' does not appear as the first line of output. This is because the class must be loaded before the main method can be executed, which means all static fields and blocks are processed in order.
They are loaded at runtime.
Static means: that the variable belong to the class, and not to instances of the class. So there is only one value of each static variable, and not n values if you have n instances of the class.
run time when class is loaded.
- Have a look at initialization
The static fields are loaded when the class is loaded. This usually happens which the file object of a class is created, but it can be earlier if the class is used another way.
The static initialiser is thread safe and you can access the class in multiple threads safely. This is useful as a way to create a thread safe singleton without having to use a lock.
Note: the class can be loaded (and its static intialisation block run) more than once if multiple class loaders are used. Generally, loading the same class in multiple class loaders can be confusing and is avoided, but it is supported and does work.
How would you load a variable at compile time? The variable is initialized when the corresponding class is loaded. See the JVMS.
Loading is a runtime operation. Everything is loaded at runtime.
When you type java ClassName then class loads into JVM with static variables, so you don't need an object for it.
Where as instance variable loaded by JVM when the object is created.
Static fields gets loaded at the time of class loading in JVM.