一、final相关
final是”不可更改的”的意思,一般有以下几种用法:
1.修饰类
当用final修饰一个类,那么这个类就不能被继承了
2.修饰方法
该方法在子类中将不会被覆盖。
住:类的private方法隐式的为final方法
3.修饰变量
如果这个变量是基本类型(除了String),那么这个变量的值是不能改变的。如final int i=1;那么i是不能改变的。
如果变量是个引用类型,那么引用不能改变,即这个引用不能指向其他的实例,但是实例的内容是可以改变的。
public class test {
public static void main(String args[]){
final A a1=new A();
A a2=new A();//a1=a2;错误
System.out.println("k="+a1.k);
a1.k++;
System.out.println("k="+a1.k);
}
}
class A{
int k;
}
二、String相关
String有两种创建的方式:
String str=new String("hello world!");
String str="hello world!";
第一种方式创建的字符串,引用str放在栈里面,字符串”hello world!”放在堆里面。
第二种方式创建的字符串,创建的”hello world!”放在常量池中,并返回引用给str。
在常量池中,只保存一个对象,即若s1=”dd”;s2=”dd”.那么常量池中只有一个”dd”,s1,s2都指向”dd”.
三、final String相关问题
先看一段代码:
public class test {
public static void main(String args[]){
String s1="helloworld";
String s2="hello";
final String s3="hello";
String s4=s3+"world";
String s5=s2+"world";
System.out.println((s1==s4));
System.out.println(s1==s5);
}
}
运行的结果是:
true
false
为什么会这样呢???
首先s1,s2,s3都是在常量池的。其中s3是一个常量,因为它被final修饰,在编译阶段,就可以确定s3的值就是”hello”,所以遇到s3,就直接替换成”hello”。所以s4=”hello”+”world”=”helloworld”,而且存放在常量池,所以s4和s1是同一个字符串的引用,所以s1==s4为true。而s5=s2+”world”,这种形式,s2是一个变量,不管是不是在常量池中,都会在堆上创建一个s2,然后再和”world”拼接,这样形成一个新的对象,s5是新对象的引用,这样s5是在堆上面,而s1在常量池中,所以指向的不是同一个对象,故为false。
再看一段代码,思考结果是什么?
public class test {
public static void main(String args[]){
A a=new A();
a.print();
}
}
class A{
final String s;
public A(){s="hello";}
public void print(){
String str="helloworld";
String s1="world";
String s2=s+s1;
System.out.println(s2==str);
}
}
结果为false
。为什么???
再看一段代码:
public class test {
public static void main(String args[]){
A a=new A();
a.print();
}
}
class A{
final static String s;
static {
s="hello";
}
public A(){}
public void print(){
String str="helloworld";
String s1="world";
String s2=s+s1;
System.out.println(s2==str);
}
}
结果也是false
。
前面不是说,遇到final可以直接进行替换吗??
当字符串在类的构造器中赋值或在静态块中赋值,无法在编译时确定这个变量是不是来自常量池,所以会在堆上创建这个对象,所以两者的结果都是false。