Java类工作流程

时间:2015-08-26 15:44:06

标签: java

如果我有一个带有常量的类,例如AppConstants,并且从那里使用public static final变量,如AppConstants.MY_STRING,它将一直重新创建此类,或者在运行时创建它,因为这些字段在班上是静态的?那么在常量或“在这个地方”定义文件更好吗?

1 个答案:

答案 0 :(得分:3)

类加载器一次加载类,通常在需要时 1 。加载类时,它的所有static成员都会被加载,并且"与类#34;一起使用,而不是与该类的特定对象引用一起使用。使用该类的static字段几次就不会重新启动该类。重新加载类的唯一方法是使用自定义类加载器。

  

最好在常量中定义文件,还是在#34;?

处定义文件

将其定义为一个类static final字段,或使用enum s。

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