Java中String类是java.lang包下的一个类,它被final关键字修饰。final关键字可以修饰类、变量和方法。被final修饰有如下特性:
①final修饰类,表示该类不能被继承。类不能被继承,标志着该类的属性和方法不能被其他类继承;
②final可以修饰静态成员变量(也叫类变量)、普通成员变量、局部变量。
被final修饰的变量称作final变量,也叫做final常量。一般来说,final常量名大写。
而值得注意的是,final修饰类变量的时候,必须在声明的时候就要显式地赋值,并且一旦赋值就不能再更改!
final修饰普通成员变量时,要么在声明的时候显式地赋值,要么在构造方法中赋值(如果该类有多个构造方法,那么每一个构造方法中都要显式地赋值或者调用this()方法),并且一旦赋值就不能改变!
final修饰局部变量的时候,不必第一次就赋值,而是可以再用到的时候再赋值。但是一旦赋值,就不能再更改!
final常量和final变量是只读的,不能再修改他们的值。
final修饰引用变量时,变量的引用不能改,但是可以改变引用的内容!这个需要注意!
③final修饰方法,代表这个方法不可以被子类重写。final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定了。
以上是final关键字的作用。
通过对String源码进行查看,发现String类是被final修饰的,说明String不能被继承,它的属性和方法都不能通过继承管理被复用。同时,String的成员变量有两个,一个是被final修饰的字符数组char[] value,一个是普通属性散列码hash。
其中,value是字符数组常量,在构造方法时就被赋值了。在其他的方法中,都没有去修改这个value的值,事实上,修改的话是不能编译通过的,因为final常量是只读的。
关于String的一些特性,经常会在面试过程中被问到。
========================面试问题分割线========================
String是一个特殊的包装类数据,可以用:
String str = new String("abc");
String str = "abc";
两种形式来创建,第一种是用new()来创建对象的,它会存放在堆中,每调用一次就会创建一个新的对象;而第二种是先在栈中创建一个对String类的对象引用变量str ,然后查找字符串常量池中有没有存放"abc",如果没有,则将"abc"存放到字符串常量池中,并令str 指向"abc",如果已经有"abc",则直接令str 指向"abc"。
面试官也会问,第一种方式创建了几个对象?
首先是在堆内存中生成了一个对象,值为“abc”,同时会去常量池中查找是否存在这个字符串,如果不存在则生成一个"abc"放到池子里去,因此可以说是创建了两个对象。
比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用 == ,下面用例子说明上面的理论。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1 == str2); // true
可以看出str1 和str2 指向同一个对象
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1 == str2); // false
用new的方式是生成不同的对象,每一次调用都生成一个新的对象。
因此用第二种方式(String str = "abc";)创建多个"abc"字符串,在内存中其实只存放一个对象而已。这种写法有利于节省内存空间,同时它可以在一定程度上提高程序的运行速度,因为jvm(java virtual machine)会自动根据栈中数据的实际情况来决定是否有必要创建新的对象。而对于String str = new String("abc"); 的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新的对象,从而加重了程序的负担。
另一方面,要注意:
我们在使用诸如String str = "abc";的格式创建对象时,总是想当然地认为创建了String类的对象str,小心陷阱,对象可能并没有被创建!而可能只是指向一个先前已经创建好的对象。只有通过new()方法才能保证每次都创建一个新的对象。由于String类的不可变(immutable)性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。
例子:
String a = "abc";
String b = "abc";
String c = new String("abc");
String d = c.intern();
这段代码(code)共创建了几个对象?
我认为是两个,首先a,b指向池子里的同一个字符串"abc",c指向堆里面的对象,d指向常量池中的"abc",因此我认为是创建了两个对象。
说完了String,那么另一个值得关注的类是Integer,看下面的例子:
int a=1;
Integer b=1;
Integer c=new Integer(1);
Integer d=new Integer(1);
Integer e=223;
Integer f=223;
思考:
a==b true or false?
a==c true or false?
b==c true or false?
c==d true or false?
e==f true or false?
想知道答案及原因?且听下回分解!