java中数据类型
基本类型:int、short、long、double、float、boolean、char 注意:并没有String的基本类型,存在于栈中
包装类数据:integer、String、Double等包装类,存在于堆
第一个概念:
自动装箱和自动拆箱:
当你用基本类型的值给包装类赋值时,就会发生基本类型向包装类型的转换:“自动装箱”
当你用包装类的值给基本类型的值进行赋值时,系统也会自动的将包装类转换为基本类型:自动装箱
第二个实例:Integer、double、float的缓存
Integer、double、float的缓存cache:
integer:在 Java 5 中,为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。上面的规则适用于整数区间 -128 到 +127,
而且需要注意的是integer类型字面量赋值时才会缓存,而使用构造器创建的 Integer 对象不能被缓存。
比如:
Integer abc=new Integer(45); //不会有缓存这一项操作
其他缓存的对象
这种缓存行为不仅适用于Integer对象。我们针对所有整数类型的类都有类似的缓存机制。
有 ByteCache 用于缓存 Byte 对象
有 ShortCache 用于缓存 Short 对象
有 LongCache 用于缓存 Long 对象
有 CharacterCache 用于缓存 Character 对象
Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。
System.out.println("自动装箱和自动拆箱"); Integer a=1; Integer b=2; Integer c=3; Integer d=3; Integer e=321; Integer f=321; Long g=3L; System.out.println(c==d);//true //缓存 System.out.println(e==f);//false //超出缓存的范围 System.out.println(c.equals(a+b));//true 第一步进行了自动拆箱,然后比较两个int的值 System.out.println(c==(a+b));//true //算术运算时,进行自动拆箱,c变为int,a+b 变为int 值,然后比较两个int值 System.out.println(g==(a+b));//true //首先对a+b进行自动拆箱为int,然后涉及隐式类型转换,int-->long, System.out.println(g.equals(a+b));//false a+b进行拆箱, int A=1; Integer B=1; System.out.println(B.equals(A)); //true System.out.println(B==A);//true
String:是一个特殊的包装类数据
String Str="asd";创建String类型需要经过三个步骤
1.首先在常量池中查找是否存在内容为"abc"的字符串对象
2.如果不存在则在常量池中创建一个"abc"的字符串对象,并让str引用该对象
3.如果存在则直接让str引用该对象
String string="asdas"; String string1="asdas"; System.out.println(string==string1);\true
String str = new String("abc")创建实例的过程
1首先定义一个str的String类型的引用并存放在栈中
2在字符串常量池中查看是否存在内容为"abc"字符串对象
3若存在则跳过这个步骤,若不存在,则在字符串常量池中创建一个内容为"abc"的字符串对象
4执行new操作,在堆中创建一个指定的对象"abc",这里堆的对象是字符串常量池“abc”对象的一个拷贝对象
5让str指向堆中“abc”这个对象(也就是存储这个对象的在堆中的地址)
情景一:
java虚拟机(JVM)中,存在着一个字符串常量池,其中保存着很多String对象
并且可以被共享使用,因此它提高了效率,由于String类时final的 ,它的值一经创建就不可改变。
字符串池由String 类维护,我们可以调用intern()方法来访问字符串池
String S1="Abc"; //字符串创建了一个对象 String S2="Abc"; //"Abc"在字符串池存在,便生成一个对象S2指向"Abc" System.out.println(S1==S2);//true System.out.println(""+S1.equals(S2));//true
情景二:
String S3=new String("Abc"); //字符串池生成一个“abc”的对象,堆中生成一个指向字符串“abc”的对象, 并且生成一个S3的引用指向堆中的对象 String S4=new String("Abc"); //字符串池中已经存在“abc”,在堆中生成一个新对象,生成一个指向堆中对象的引用S4 S4==S3 //false 堆中以及字符串池中的地址不相同
情景三;intern()方法可以返回该字符串在常量池中的对象的引用
String str1 = "abc"; String str2 = newString("abc").intern(); System.out.println(str1==str2); //true
情景四:”假“改变,真生成:看似改变了,其实时真的生成了
String str1 = "abc"; String str2 = "abc"; str1 = "bcd"; //String引用改变指向,指向了“bcd” //当JVM发现在常量池中没有存放该值的地址,便开辟这个地址,并创建了一个对象, System.out.println(str1 + "," + str2); //bcd, abc System.out.println(str1==str2); //false
情景五:宏变量、宏代替的使用
String str1 = "abc"; final String str2 = "ab"; String str3 = str2+"c"; System.out.println(str1==str3); // true String str1 = "abc"; String str2 = "ab"; String str3 = str2+"c"; System.out.println(str1==str3); // false
涉及到str2是变量,str3不能生成宏代替,先是生成一个StringBuilder,然后append(str2).append("c")
然后让str3指向StringBuilder.toString()返回的对象
String S3=new String("Abc");
//字符串池生成一个“abc”的对象,堆中生成一个指向字符串“abc”的对象,
并且生成一个S3的引用指向堆中的对象
String S4=new String("Abc");
//字符串池中已经存在“abc”,在堆中生成一个新对象,生成一个指向堆中对象的引用S4
S4==S3 //false 堆中以及字符串池中的地址不相同