How Java class loader optimize the duplicate class loading? - java

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());
}
}

Related

Why does sun.misc.Launcher$AppClassLoader.loadClass appear in the stack

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.

How to access current actual class from static Main method

I want to create an abstract class with a main method, to prevent developers who extend it from having to implement the main method. I also want to control what happens in the main method.
The abstract base class that I'm writing extends NanoHTTPD, and you start the server by calling ServerRunner.run() with the parameter being a class object of the type of the class that you want to run.
Here is what I have so far:
public abstract class FlexibleServer extends NanoHTTPD
{
public DeadSimpleMicroserver(int port)
{
super(port);
}
public static void main(String[] args)
{
ServerRunner.run(FlexibleServer.class);
}
}
The problem is that since this class is abstract, future developers will be extending the class, so I need the parameter to ServerRunner.run() to be the ACTUAL type of the subclass, so I can't use FlexibleServer.class.
I tried changing the parameter to this.class, but then I get the compile error that "this" cannot be referenced from a static context (because main() is static).
How can get a class object of the actual subclass from main()?
If the class that you're going to pass at runtime is dynamic, then you cannot call it with a hard-coded class name. You will have to change your call to run so that you pass it either an instance of the actual class, or you would have to dynamically load the class given, for example, main method arguments.
With the above change, your problem gets resolved.
For example, if you're loading the class dynamically:
ServerRunner.run(Class.forName(args[0]));
Assuming the app will be called with the actual class name.
Alternatives include redesigning your code such that either a class name, an instance, or class object is passed in by the caller
A framework I once worked on had a base class like this, and we added a method like this:
public abstract class FrameworkServer {
// framework stuff
protected static void main(String[] args, FrameworkServer instance) {
// parse args
// actually start the instance running
}
}
And a specific server instance would need to add its own main method like so:
final class MyServer extends FrameworkServer {
public static void main(String[] args) {
main(args, new MyServer());
}
}
There is a small bit of boilerplate here for each server, but that allows you do avoid reflection and to make the code much clearer. As a bonus, the concrete subclasses can now add their own arguments to their server's constructor, which is often very useful for unit-testing.

Prevent a class from loading until a certain class is loaded

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.

NoClassDefFoundError when adding classes to the classpath at runtime when I used abstract or interface in Main class

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.

When does classLoader load imports?

Assume, that I have class with static methods only. Will class loader load every imported class when loading class to memory? Or it will only load imports when a method from this would need access to it?
Question is whether class loader loads imports when the class is loaded to memory, or just before some methods want to use them.
If it is the first option I would probably need to divide some of my Util classes, to be more specialized.
I think you can test it as follows:
package pkg1;
public class Test {
static {
System.out.println("Hello 111");
}
public static void meth() {
System.out.println("Hello 222");
}
}
Test 1:
package pkg2;
import pkg1.Test;
public class Tester {
public static void main(String... args) {
Test t;
}
}
That prints nothing.
Test 2:
package pkg2;
import pkg1.Test;
public class Tester {
public static void main(String... args) {
Test.meth();
}
}
Prints:
Hello 111
Hello 222
So, just because you have imported a class does not mean the classloader will load the class into the memory. It loads it dynamically when it's used.
I don't claim to know a lot about the class loader, but if you're talking about import statements then the class loader is irrelevant.
Import statements exist purely to allow the developer to use short class names rather than the fully qualified name of each class referenced in the class being written. The compiler uses those import statements very early on to resolve the names of the referenced classes before a single line of bytecode is created.
In general, the static code block at the top of a class file with a report (i.e. a print statement ) will give you a good idea of when the loading happens in your particular application.
However, when dealing with corner cases, like dynamic classes, inner static classes, or classes off the classpath that are dynamically loaded, you will have to be careful - because these classes might actually be loaded MULTIPLE times in an application.

Categories