string类是java中使用最多,也是面试中最常考到的知识点,所以掌握他是必现的。他在JDK的api中是这样定义的
public final class String extends Object implements Serializable, Comparable
, CharSequence String 类代表字符串。Java 程序中的所有字符串字面值(如
"abc"
)都作为此类的实例实现。字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。例如:
String str = "abc";
在学习之前先思考下这些问题
Q、String是不是基本数据类型?有哪些基本数据类型?各占多少字节?
Q、String为什么设计成不可变?
Q、String str = new String( "abc")创建了几个对象?
Q、String、StringBuffer和StringBuilder三者的区别?
Q、String转换成integer的方式和原理?
Q、编程题
Q、Integer 和 int的区别?
基本数据类型:四大类八种
基本类型 | 字节大小 |
boolean | 1(Jvm规范中做int处理,占4个字节) |
byte | 1 |
char | 2 |
short | 2 |
int | 4 |
float | 4 |
long | 8 |
double | 8 |
引用数据类型有:类、接口类型、数组类型、枚举类型、注解类型
二、不可变String
不可变对象的好处
String str = new String( "abc")创建了几个对象?
这个问题经常在面试中考到,正确答案是2个,为什么不是3个呢?
可变性
String类用字符数组保存字符串,即private final char value[],所以String对象不可变
StringBufferr类与StringBuilder类都是继承AbstractStringBuilder类,AbstractStringBuilder是用字符数组保存字符串,即char value[],所以StringBuffer与StringBuilder对象是可变的
线程安全性
String类对象不可变,所以理解为常量,线程安全
StringBuffer类对方法加了同步锁,线程安全
StringBuilder类对方法未加同步锁,线程不安全
性能
String类进行改变的时候,都会产生新的String对象,然后将指针指向新的String对象
StringBuffer进行改变的时候,都会复用自身对象,性能比String高
StringBuilder行改变的时候,都会复用自身对象,相比StringBuffer能获得10%~15%左右的性能提升,但是得承担多线程的不安全的风险
下面两种转换方式
1、String转换成integer
由于在JDK 5以后就有了自动拆箱和自动装箱。因此我们可以用数据的类型来做数据的转换。
我们可以用类型名来接解析成对应的类型再赋值给对应类型的变量。
String dd = new String("12");
int temp = Integer.parseInt(cc);
2、其他类型转换成String,String类中有valueOf( )方法,可以进行转换
char ch[] = new char[]{'A','B','C'};
String str = String.valueOf(ch);
public static void main(String[] args){
Integer i1 = 127;
Integer i2 = 127;
int i3 = 127;
Integer i4 = new Integer(127);
Integer i5 = new Integer(127);
System.out.println(i1 == i2);
System.out.println(i4 == i5);
System.out.println(i1 == i4);
System.out.println(i3 == i4);
System.out.println(System.identityHashCode(i1));
System.out.println(System.identityHashCode(i2));
System.out.println(System.identityHashCode(i3));
System.out.println(System.identityHashCode(i4));
System.out.println(System.identityHashCode(i5));
}
输出结果是:
true
false
false
true
1975012498
1975012498
1975012498
1808253012
589431969
可以发现a、b、ab三个内存地址是一样,而aa、bb都是不同的内存地址
首先Ingeter是int的包装类,int的初值为0,Ingeter的初值为null,
其次不同点是值的比较,通过上面的编程题,看下下面这个情况
Integer i6 = 128;//java在编译的时候,被翻译成-> Integer i6 = Integer.valueOf(128);
Integer i7 = 128;
System.out.println(i6 == i7);
可以看到返回结果是:false
这个时候就要看valueOf()源码了,对于-128到127之间的数,会进行缓存,Integer i1= 127时,会将127进行缓存,下次再写Integer i2 = 127时,就会直接从缓存中取,就不会new了。
* This method will always cache values in the range -128 to 127, * inclusive, and may cache other values outside of this range. public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
所以总结下他们的不同:
①无论如何,Integer与new Integer不会相等。不会经历拆箱过程,i4的引用指向堆,而i1指向专门存放他的内存(常量池),他们的内存地址不一样,所以为false
②两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false
java在编译Integer i6 = 128的时候,被翻译成-> Integer i6 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存
③两个都是new出来的,都为false
④int和integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比
下面从String源码来了解一下啊
略!看JDK API去
参考文章:解读不可变的String