java中关于字符串的陷阱
1.一般面试题都会出关于String java = new String("I love java");这条语句创建了几个字符串对象?我在最开始时一直认为是只创建了一个字符串对象,但其实是创建了两个字符串对象,第一个是构造函数中作为形参的直接量对象,第二个则是构造函数返回的字符串对象。
而在 java中创建对象一般有四种方法:1.通过new调用构造函数来创建。2.通过Class对象的newInstance()方法调用构造函数来创建。3.通过java的反序列化机制从io流中恢复java对象。4.通过java对象的clone()方法复制一个新的java对象。
2.通过直接量的形式来创建java对象。如:String str1 = "hello java"; 此时创建的对象(字符直接量)会被JVM存放在字符串缓存池中。一般情况下,字符串池中的字符串对象不会被垃圾回收,当再次使用该字符串时,无须重新创建一个新的字符串对象了。
3.String str1 = "aaa的长度为:3"; String str2 = "aaa" + "长度为:" + "3"; system.out.println(str1 == str2); 输出的是 true
String str3 = "bbb的长度为:3"; String str4 = "bbb" + "长度为:" + "bbb".length(); system.out.println(str3 == str4); 输出的是 false
注:字符串对象是由字符直接量、整数直接量,没有变量的参与,没有方法调用即jvm可以在编译时就确定该字符串连接表达式的值,可以让该字符串变量直接指向字符串缓存池中的对应变量。而如果使用了变量或调用了方法,则无法使用字符串缓存池。
4.字符串可以通过compareTo()方法来进行性比较,如:“abc”.compareTo("ac"); 此时该表达式小于0,因为该方法是通过从左往右对比每个字符的ascii码。因为c>b,所以ac>abc
5.表达式类型的自动提升:整个算术表达式的数据类型自动提升到与表达式中最高等级操作数同样的类型。
byte,short,char ——》int ——》long ——》 float ——》 double
如: short sv = 5; sv = sv - 2; 在第二步时代码会报错,因为右边的表达式结果类型会自动提升为int类型,此时无法赋值给short型的sv。而如果将sv = sv - 2 ;改为 sv -= 2;则不会报错。因为复核赋值运算符中包含隐式类型装换。即sv -= 2;等价于sv = (short)(sv - 2);因此,如果使用复核赋值运算符时,右侧运算结果超出左侧类型的取值范围则会出现溢出现象导致高位截断。
public static void main(String[] args){ String s1 = "疯狂java"; String s2 = "疯狂" + "java"; // true 系统回直接缓存”疯狂java“,s2直接使用两个字符串直接量进行连接,此时指向的也是缓存中的”疯狂java“ System.out.println(s1 == s2); String s3 = "疯狂"; String s4 = "java"; String s5 = s3 + s4; // false s5引用了普通变量,在编译时无法确定 System.out.println(s1 == s5); final String s6 = "疯狂"; final String s47= "java"; final String s8 = s6 + s7; // true s8等于两个宏变量进行连接 System.out.println(s1 == s8); }
对于实例变量而言,除了可以在定义该变量时赋初始值之外,还可以在非静态初始化块、构造器中对它赋初始值,而且在这3个地方指定初始值的效果基本一样。但对于final实例变量而言,只有在定义该变量时指定初始值才会有“宏变量”的效果,在非静态初始化块、构造器中为final实例变量指定初始值则不会有这种效果,对于普通类变量,与实例变量类似