If I have a class with constants for example AppConstants and use public static final variable from there like AppConstants.MY_STRING it would recreate this class all the time or it creates it during runtime because the fields in the class is static? So is it better to define file in constants or "at the place"?
1 Answer
Classes are loaded once by the class loader, usually when needed1. When a class is loaded, all its static members are loaded as well and "live with the class", not with a specific object reference of that class. Using a static field of the class several times won't fire a reload of the class. The only way to reload the class is using a custom class loader.
is it better to define file in constants or "at the place"?
Define them once as static final fields on a class or use enums.
1 Definition of when needed:
If you declare primitive or String constants like this:
public class AppConstants {
public static final int ONE = 1;
public static final int TWO = 2;
public static final int TEN = 10;
}
public class ClientTest {
public static void main(String[] args) {
System.out.println(AppConstants.ONE);
System.out.println(AppConstants.TWO);
System.out.println(AppConstants.TEN);
}
}
When compiling both classes and executing ClientTest, AppConstants class won't be loaded (tested using HotSpot) because the constants will be inlined by the compiler. In order to evaluate the results, do this:
> javac -cp:. AppConstants.java ClientTest.java
> javap -c ClientTest //you can see the generated bytecode
> java -verbose:class ClientTest //shows you the classes loaded to execute this app
And you will see this.
From javap -c ClientTest (proper code):
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_1 //My Comment: constant with value 1
4: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
7: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
10: iconst_2 //My Comment: constant with value 2
11: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
14: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
17: bipush 10 //My Comment: constant with value 10
19: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
22: return
}
From java -verbose:class ClientTest:
[Opened C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
[Loaded java.lang.Object from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
// Lots of classes from rt.jar
[Loaded java.security.UnresolvedPermission from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
[Loaded java.security.BasicPermissionCollection from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
[Loaded ClientTest from file:/D:/tmp/] //<-- Class being executed
[Loaded sun.launcher.LauncherHelper$FXHelper from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
[Loaded java.lang.Class$MethodArray from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
[Loaded java.lang.Void from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
1
2
10
[Loaded java.lang.Shutdown from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
[Loaded java.lang.Shutdown$Lock from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
There's no trace of AppConstants class being loaded, only ClientTest.
But if you add a constant that refers to an object reference e.g. a List, then the class will be loaded. From the example above:
public class AppConstants {
public static final int ONE = 1;
public static final int TWO = 2;
public static final int TEN = 10;
public static final List<String> NAMES = Collections.unmodifiableList(Arrays.asList("Luiggi", "Andy"));
}
public class ClientTest {
public static void main(String[] args) {
System.out.println(AppConstants.ONE);
System.out.println(AppConstants.TWO);
System.out.println(AppConstants.TEN);
System.out.println(Foo.NAMES);
}
}
Now providing the relevant output of java -verbose:class ClientTest:
//...
[Loaded ClientTest from file:/D:/tmp/] //our class being executed
[Loaded sun.launcher.LauncherHelper$FXHelper from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
[Loaded java.lang.Class$MethodArray from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
[Loaded java.lang.Void from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
1 //output of constants
2
10
[Loaded AppConstants from file:/D:/tmp/] //loads AppConstants class here because it's needed
[Loaded java.util.Arrays$ArrayList from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
[Loaded java.util.AbstractList$Itr from C:\Program Files\Java\jre1.8.0_51\lib\rt.jar]
[Luiggi, Andy] //output of AppConstants#NAMES
9 Comments
public static final variable uses are actually inlined by the compiler where possible, and the respective class is therefore not loaded at all by such references.AppConstants and you don't use it, then it won't be loaded. If you have such a line String s = AppConstants.MY_STRING and this line is executed, then AppConstants class is used, thus it will be loaded once because that class is needed.
staticmembers. Please understand that OP's inquiry is not 100% related tostaticmembers, is more about class loading. While the answer to this question explains the concepts to answer this question, it doesn't do it directly. Hence OP raises a question and gets a direct answer. If you're still against this, then raise a question on meta and ask about it.