final修饰类的时候,表明该类不能被继承
final修饰方法的时候,表明该方法在子类中不能被覆盖
类的private方法会隐式地被指定为final方法
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。(打个比喻:现实中,如果把你的女朋友,比作一个引用类型变量的话,就是你的对象,你是希望她被final修饰,还是不希望她被final修饰呢?如果被final修饰了,那你的对象就不能再找另外的对象了!就是不能再new 一个对象给她了,只能属于你一个人!!)
那被final修饰的引用变量指向的对象内容可变吗?(这个其实也很容易理解,接着上面的比喻:,你的对象虽然只属于你一个人的,不能再找其他对象了,但是你的对象不可能一直都不变吧,比如你对象的体重,最近吃的比较多了,体重增加了可以吧。所以被final修饰的引用变量指向的对象内容是可以改变的)
public class People{
public static void main(String[] args){
final Girl yourgirlfriend = new Gril();//final修饰引用类型变量,对象不能再改变
System.out.println(++yourgirlfriend .weight );//输出为 91,说明对象指向的内容是可以改变
}
}
class Girl{
public int weight =90;
}
- final变量和普通变量到底有何区别呢?看下面的例子1和例子2:
解释:大家可以先想一下这道题的输出结果。为什么第一个比较结果为true,而第二个比较结果为fasle。这里面就是final变量和普通变量的区别了,当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。这种和C语言中的宏替换有点像。因此在例子1这一段代码中,由于变量b被final修饰,因此会被当做编译器常量,所以在使用到b的地方会直接将变量b 替换为它的值。而对于变量d的访问却需要在运行时通过链接来进行。想必其中的区别大家应该明白了,不过要注意,只有在编译期间能确切知道final变量值的情况下,编译器才会进行这样的优化,比如例子2的这段代码就不会进行优化:
例子1
public class Test {
public static void main(String[] args) {
String a = "hello2";
final String b = "hello";
String d = "hello";
String c = b + 2;
String e = d + 2;
System.out.println((a == c));//true
System.out.println((a == e));//false
}
}
例子2
public class Test {
public static void main(String[] args) {
String a = "hello2";
final String b = getHello();
String c = b + 2;
System.out.println((a == c));//false
}
public static String getHello() {
return "hello";
}
}
7.final与static修饰变量之间的区别:static作用于成员变量用来表示只保存一份副本,而final的作用是用来保证变量不可变。运行这段代码就会发现,每次打印的两个j值都是一样的,而i的值却是不同的。从这里就可以知道final和static变量的区别了。
public class Test {
public static void main(String[] args) {
MyClass myClass1 = new MyClass();
MyClass myClass2 = new MyClass();
System.out.println(myClass1.i);
System.out.println(myClass1.j);
System.out.println(myClass2.i);
System.out.println(myClass2.j);
}
}
class MyClass {
public final double i = Math.random();
public static double j = Math.random();
}
8.关于final参数的问题:关于网上流传的”当你在方法中不需要改变作为参数的对象变量时,明确使用final进行声明,会防止你无意的修改而影响到调用方法外的变量“这句话,我个人理解这样说是不恰当的。
因为无论参数是基本数据类型的变量还是引用类型的变量,使用final声明都不会达到上面所说的效果。
上面这段代码好像让人觉得用final修饰之后,就不能在方法中更改变量i的值了。殊不知,方法changeValue和main方法中的变量i根本就不是一个变量,因为java参数传递采用的是值传递,对于基本类型的变量,相当于直接将变量进行了拷贝。所以即使没有final修饰的情况下,在方法内部改变了变量i的值也不会影响方法外的i。
再看下面这段代码:
public class Test {
public static void main(String[] args) {
MyClass myClass = new MyClass();
StringBuffer buffer = new StringBuffer("hello");
myClass.changeValue(buffer);
System.out.println(buffer.toString());
}
}
class MyClass {
void changeValue(final StringBuffer buffer) {
buffer.append("world");
}
}
运行这段代码就会发现输出结果为 helloworld。很显然,用final进行修饰并没有阻止在changeValue中改变buffer指向的对象的内容。有人说假如把final去掉了,万一在changeValue中让buffer指向了其他对象怎么办。有这种想法的朋友可以自己动手写代码试一下这样的结果是什么,如果把final去掉了,然后在changeValue中让buffer指向了其他对象,也不会影响到main方法中的buffer,原因在于java采用的是值传递,对于引用变量,传递的是引用的值,也就是说让实参和形参同时指向了同一个对象,因此让形参重新指向另一个对象对实参并没有任何影响。
所以关于网上流传的final参数的说法,我个人不是很赞同。