在上一章的使用
步骤,在"访问某个类或者接口的静态变量 " 这一步骤留下一个疑问?为什么是加载MyParent类呢? 下面我们来说说倒是为什么?
我们先写个例子:
public class Test1 {
public static void main(String[] args) {
System.out.println(MyParent.str);
}
public static class MyParent {
public static final int str = 123;
public MyParent(){
System.out.println("MyParent inited");
}
}
}
然后我们运行,发现控制台只打印了 123
,并没有打印MyParent inited
,这是为什么呢?
其实在JVM中,静态变量会存在于调用该静态变量的方法所属的类的变量池中
这句话听起来是很绕口,我们把他带到刚才的例子中解释一遍
就是调用MyParent.str
静态变量的main
方法,main
方法所属的Test1
这个类中的变量池中
其实就是在jvm加载的过程中,会把MyParent.str
这个变量保存到Test1
这个类中。
验证方式:
-
通过Javap来解析下
发现编译的时候,已经把变量123
加载进来了。 -
把
MyParent
编译的class文件删除,再次执行
删除后,再次执行main方法,会发现可以正常使用。说明已经加载到Test1
中
什么是常量呢?
常量是指被final修饰的变量,值一旦确定就无法改变。
final可以修饰静态变量、实例变量和局部变量。
所以,能保存到常量池中的值,必须是被final 修饰的 变量。
哪些类型支持哪些常量池呢?
Java中八种基本类型的包装类的大部分都实现了常量池技术,它们是Byte、Short、Integer、Long、Character、Boolean,另外两种浮点数类型的包装类(Float、Double)则没有实现。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值在-128到127时才可使用对象池。
String 类型的intern()
String类型的intern()
会扩展变量池。如下面的例子
public static void main(String[] args) {
String s0 = "xyz";
String s1 = new String("xyz");
System.out.println(s0 == s1); //false
String intern = s1.intern();
System.out.println(s0 == intern);//true
}
为什么调用intern()
后,再比较会相同呢?
因为在调用intern()
后,会先看看常量池中是否存在“xyz”这个值,如果不存在就保存,并且返回,如果存在,就直接获取并且返回。