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.
Related
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 have some test classes that need to verify that GLFW-functions were called. But when I want to execute all tests in IntelliJ then I get the error:
Native Library lwjgl.dll already loaded in another classloader
I use Powermock to verify that the static methods have been called:
#RunWith(PowerMockRunner.class)
#PrepareForTest({GLFW.class})
public class GlfwWindowImplTest {
// ...
#Test
public void update_swapsBufferAndPollsEvents() {
GlfwWindowImpl target = new GlfwWindowImpl(1L);
mockStatic(GLFW.class);
target.update();
verifyStatic();
GLFW.glfwSwapBuffers(1L);
verifyStatic();
GLFW.glfwPollEvents();
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest({GLFW.class})
public class GlfwWindowSystemImplTest {
// ...
#Test(expected = GlfwInitializeException.class)
public void initialize_throwsExceptionIfGlfwInitFails() {
GlfwWindowSystemImpl target = new GlfwWindowSystemImpl();
mockStatic(GLFW.class);
when(GLFW.glfwInit()).thenReturn(GL_FALSE);
target.initialize();
}
}
It may be a bit late to answer this post, but I ran into a similar problem and I was able to solve it with PowerMock. PowerMock has #SuppressStaticInitializationFor that should help you overcome this issue. Section Suppress static initializer in the link below has a nice example about how to do that:
https://github.com/powermock/powermock/wiki/Suppress-Unwanted-Behavior
Basically, in your case, there could be a class that is calling System.loadLibrary("lwjgl"). You need to locate that class. Example:
public class SomeClass {
...
static {
System.loadLibrary ("lwjgl");
}
...
}
Then in your test class use #SuppressStaticInitializationFor with the fully qualified name of the class:
#SuppressStaticInitializationFor("com.example.SomeClass")
If in case the class doing the loadLibrary call is an inner class, then you need to add $InnerClass to fully qualify the inner class. Example:
public class SomeClass {
...
public static class SomeInnerClass {
static {
System.loadLibrary ("lwjgl");
}
}
...
}
Then you need to use:
#SuppressStaticInitializationFor("com.example.SomeClass$SomeInnerClass")
#PrepareForTest({GLFW.class}) loads the ClassLoader for the native library lwjgl.dll which is already loaded in the ClassLoader.
You can use the #PowerMockIgnore to defer the loading of classes with the names supplied to value() to the system ClassLoader.
For example suppose you'd like to defer the loading of all classes in the org.myproject package and all its sub-packages but you still like to prepare "MyClass" for test. Then you do like this:
#PowerMockIgnore("org.myproject.*")
#PrepareForTest(MyClass.class)
#RunWith(PowerMockRunner.class)
public class MyTest {
...
}
JavaDoc Reference
#PrepareForTest({GLFW.class}) create new ClassLoader and load ammended class in it. I suspect that GLFW load lwjgl library in its static initializer section.
You can try to unload library, but I don't know what consequences it may lead to.
I suggest wrap GLFW and use that wrapper in your applicatin.
Context: Two classes from different packages (Second class in second package inherits class in first package) are connected through inheritance and made a method call to subclass from parent class.
What I did:
Written two classes in two different notepad files and trying executing one after other but was not possible for me to execute and showing error messages and my classes are as follows:
package first;
import second.Sample1;
public class Sample {
public static void main(String a[])
{
Sample1 s=new Sample1();
s.dis(1);
}
package second;
import first.Sample;
public class Sample1 extends Sample{
public void dis(int i)
{
System.out.println(i);
}
}
In Eclipse, it is giving output as 1 but in what order I should execute these codes using notepads files. Observed that compiling these classes in any order giving error messages.
Thanks much. :)
You created a cyclic package dependency, which is not a good idea.
Your base class Sample doesn't have to know anything about its sub-classes, and when it does, it is usually a sign of bad design.
Just move the main method to Sample1, and Sample class won't have to import second.Sample1.
So i'm awfully new to coding but i quite like it, i'm really young so i have 0 experience on related stuff.
I'm watching this youtube series about java code and in this episode:
he creates another class and uses it in the main one but im on intelij(not eclipse as he is) and it gave me two errors saying java couldnt find the symbol (my second class);
my code:
package com.company;
public class Main {
public static void main(String[] args) {
tuna tunaObject = new tuna();
tunaObject.simpleMessage(null);
}
Second class:
public class tuna{
public void simpleMessage(){
System.out.println("Another class");
}
}
Your simple message method does not accept parameters, so don't try to pass in any. Instead of calling simpleMessage(null) simply call simpleMessage().
Also either make sure that the tuna class is located in the same package as your main class, or import the tuna class via an import statement above the Main class and below the package declaration. Even if the two source files are in the same physical directory, the Java compiler won't understand which class you are referring to unless you specifically define each class in the same package.
Adjust your second class to:
package com.company;
public class tuna{
public void simpleMessage(){
System.out.println("Another class");
}
}
Wecome to Java.
Maybe you can confirm first that the second class is located in the same package with the Main. And it is better to claim a class in First letter upper-cased format.
I tried dynamic loading of classes in a simple program and intrestingly when ever i try dynamic loading of classes with simple name it fails with classnotfoundexception. this happends only if the classes are under a package other than default package.
But when i specify the full path name, the dynamic loading succeeds. The class being loaded is in the same package as the Main class.
File Main.java:
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
System.out.println(Class.forName("m"));
}
}
class m extends Main{
}
No, Class.forName always needs the package-qualified class name. From the parameter documentation:
className - the fully qualified name of the desired class.
The package of the calling code is irrelevant.
You have to put fully qualified class name for the Class here
such as System.out.println(Class.forName("com.sample.M"));
assuming
com.sample is your class package name.