类由类加载器加载一次,通常在需要时1。当一个类被加载时,它的所有static 成员也会被加载并“与类一起存在”,而不是与该类的特定对象引用一起加载。多次使用类的static 字段不会触发类的重新加载。重新加载类的唯一方法是使用自定义类加载器。
在常量中定义文件还是“在原地”更好?
将它们定义为类中的static final 字段或使用enums。
1定义当需要时:
如果您像这样声明原始或String 常量:
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);
}
}
当编译两个类并执行ClientTest 时,AppConstants 类将不会被加载(使用 HotSpot 测试),因为编译器将内联常量。为了评估结果,请执行以下操作:
> 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
你会看到这个。
来自javap -c ClientTest(正确代码):
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
}
来自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]
没有AppConstants 类被加载的痕迹,只有ClientTest。
但是如果你添加一个引用对象引用的常量,例如List,然后将加载该类。从上面的例子:
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);
}
}
现在提供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