谈到String,很多java新手认为它是基本数据类型其中之一,其实不然。java里面一共有8个基本数据类型,它们分别是四种整数类型:byte(8位),short(16位),int(32位),long(64位);两种浮点类型:float(32位),double(64位);还有一种字符类型:char(16位),最后一共就是布尔类型了,有true和false两种值,和C语言不同的是,C语言里面是非1即为真,例如2,3等等数值都是为真的,在java里只有true这个布尔类型才为真。可能有人会问了,为什么java是一种面向对象对象的语言,为什么还会有基本数据类型呢,其实JVM虚拟机内部早已对它进行了优化,就是基本数据类型没有对象.方法()出现了,JVM内部还是以对象的形式进行操作的。java其实对其进行了自动拆装箱功能,8个基本数据类型的包装类是Byte,Short,Integer,Long,Float,Double,Characher,Boolean,它们可以进行自动转换;
例如:
Integer b=new Integer(8);
int c=b.intValue();
System.out.println(c);
}
那我们再来说重点,String不属于基本数据类型,而是属于类。Strings are constant;就是String对象一旦创建就不能进行改变。举例说明:
public static void main(String[] args) {
String str=new String("hello");
str=str+"world";
System.out.println(str);
}
运行结果:helloworld
到这里,可能对于初学者感到迷惑了,很显然这里的str已经改变了,为什么说String对象不可改变呢。其实是这样的当我们写下 String str=new String("hello");在jvm内存模型里是做了这样一件事,在虚拟机栈(也叫方法栈)里面建了一对象引用str,在堆里面开辟了一个内存区域用于存储“”hello”,然后str指向hello,接着又做了str=str+"world",实际上在内存区域内是做了在堆里开辟了另外一个内存区域存储"helloworld",然后str断开之前的连接"hello",然后重新指向"helloword",然后之前的hello没有变量指向它,那么它将在一个不确定的时刻被垃圾回收机制回收回去。这里面hello其实是没有改变的,是我们重新建了一个内存区域而已。所以当我们最好不要用这个,用StringBuffer,或者StringBuilder,它们是可以改变的大小的。它们之间的优缺点将在我下面的博文中讲解。
下面我们在来谈谈字符串缓存池,看个例子:
public static void main(String[] args) {
String a="wang";//1
String b="wang";//2
String c=new String("wang");//3
String d=new String("wang");//4
System.out.println(a==b);//5
System.out.println(a==c);//6
System.out.println(c==d);//7
}
运行结果为:
true
false
false
解释下:String a="wang";当我们执行这句话的时候,是先看字符串缓存池中看有没有wang这个字符串,如果没有在缓冲池中创建wang这个字符串,如果已经有的话,则直接引用,所以当1,2两句执行完的时候实际上方法区里面的字符串缓冲池里面只有一个wang这个字符串,而"=="比较的则是两个引用是否指向同一个对象。所以结果才为true;而3句是在堆里开辟了一个空间,然后放置"wang",栈里面的c指向它,而4句依然是在堆里开辟另外一个区域用于存储另一个"wang"字符串,所以堆里现在应该有两个"wang",而且每个都有指向自己的引用,所以当我们判断"c==d"?这个语句的时候,那么就是false了,因为这两个是不同的指向。同理a==c等于false也是一样的道理。对于==我们只要判断是否是指向同一个引用就可以了。我们也能看出来3,4两句比较费内存的,所以我们我也很少使用new来创建字符串,因为容易内存溢出。
再举例几个String的例子解释下:
String str = "abc";
is equivalent to:
char data[] = {'a', 'b', 'c'};
String str = new String(data);
System.out.println("abc");
String cde = "cde";
System.out.println("abc" + cde);
String c = "abc".substring(2,3);
String d = cde.substring(1, 2);
前面几句说的是初始化的方面,String类里面有很多不同的初始化,根据需要我们可以使用不同的初始化,然后就是关于substring(beginindex,endidex)函数的用法了,该函数实际上返回一个字符串,然后作为其子链。
public static void main(String[] args) {
String c = "abcde".substring(1,4);
System.out.println(c);
}
运行结果:bcd
可以看出这个函数的功能是实现一个子字符串,截取字符串的方法是左边可以取到(inclusive),右边娶取不到(exclusive),结果就显而易见了。
然后String类的其它方法都差不多,我们可以通过阅读其JDK里面的源码,学习此String的使用。