一:符号引用
符号引用只是一些符号,包含在字节码文件的常量池中,它主要包括:
在该类中,出现过的各类包,类,接口,字段,方法等元素的全限定名,所谓符号引用,只是一个符号而已,只是告知jvm,此类需要哪些调用方法,引用或者继承哪些类等等信息.
但是JVM在使用这些资源的时候,只有这些符号是不行的,必须详细知道这些资源的地址,才能正确地调用相关资源.直接引用,就是这样一类指针,它直接指向目标.
解析过程,就是完成将符号引用转化为直接引用的过程,方便后续资源的调用.
为什么会出现符号引用呢?
JAVA中符号引用的出现是非常自然的,因为在类没有加载的时候,也不能确保其调用的资源被加载,更何况还有可能调用自身的方法或者字段.
就算能确保,其调用的资源也不会每次在程序启动时,都加载在同一个地址.
简而言之,在编译阶段,字节码文件根本不知道这些资源在哪,所以根本没办法使用直接引用,于是只能使用符号引用代替.
二:字面量
字面量可以理解为实际值,int a = 8中的8和String a = "hello"中的hello都是字面量
三:字段
java中的字段在Java 中 一旦你定义了一个类(也就是你自己定义的类型),就可以在类中设置这个类的俩个元素,字段(数据成员) 和方法(有人称之为函数)。字段可以是任何类型的对象,可以用这个类型的引用来封装数据或者与之通信,也可以是基本数据类型。如果字段是一个一个对象的引用那么在你使用这个引用之前必须要初始化该对象的引用,表示有一个实际的对象跟这个类相关联,也就是用new关键字来实例化该对象的引用
四:方法区,class常量池,堆,栈(1.8以后我们的方法区在元空间里,元空间和堆分离开来了,元空间就是以前堆的永久代)
静态变量、常量在方法区,所有方法,包括静态和非静态的,也在方法区。成员变量在堆 局部变量在栈 在Java源文件被编译到的字节码文件中时,所有的变量和方法引用都作为符号引用保存在Class文件中的常量池里面
五:常量池的好处
常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。
- 节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。
- 节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。
java中基本类型的包装类的大部分都实现了常量池技术,即Byte,Short,Integer,Long,Character,Boolean。这5种包装类默认创建了数值[-128,127]的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。 两种浮点数类型的包装类Float,Double并没有实现常量池技术。
- Integer i1=40;Java在编译的时候会直接将代码封装成Integer i1=Integer.valueOf(40);,从而使用常量池中的对象。
- Integer i1 = new Integer(40);这种情况下会创建新的对象。
- 语句i4 == i5 + i6,因为+这个操作符不适用于Integer对象,首先i5和i6进行自动拆箱操作,进行数值相加,即i4 == 40。然后Integer对象无法与数值进行直接比较,所以i4自动拆箱转为int值40,最终这条语句转为40 == 40进行数值比较。
• String str1 = "abcd";
String str2 = new String("abcd");
System.out.println(str1==str2);//false,引用地址不相同
String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing"; //这样才会添加到字符串常量池中
String str4 = str1 + str2; //这种是不会被加入到字符串常量池中,属于运行时创建的字符串,具有独立的内存地址,所以不引用自同一String对象。
System.out.println("string" == "str" + "ing");// true
System.out.println(str3 == str4);//false
String str5 = "string";
System.out.println(str3 == str5);//true
- “abcd”是在常量池中拿对象,new String(“abcd”)是直接在堆内存空间创建一个新的对象。只要使用new方法,便需要创建新的对象。
- 连接表达式 +,只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入常量池中。
- 对于字符串变量的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,其属于在运行时创建的字符串,具有独立的内存地址,所以不引用自同一String对象。(应该是在堆中创建了新的对象)