final在Java中是一个保留的关键字,可以声明成员变量、方法、类以及本地变量。一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如果你试图将变量再次初始化的话,编译器会报编译错误。
凡是对成员变量或者本地变量(在方法中的或者代码块中的变量称为本地变量)声明为final的都叫作final变量。final变量经常和static关键字一起使用,作为常量。下面是final变量的例子:
1 2 |
public static final String LOAN = "loan"; LOAN = new String("loan") //invalid compilation error |
final变量是只读的。
final也可以声明方法。方法前面加上final关键字,代表这个方法不可以被子类的方法重写。如果你认为一个方法的功能已经足够完整了,子类中不需要改变的话,你可以声明此方法为final。final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。下面是final方法的例子:
使用final来修饰的类叫作final类。final类通常功能是完整的,它们不能被继承。Java中有许多类是final的,譬如String, Interger以及其他包装类。下面是final类的实例:
下面总结了一些使用final关键字的好处
创建不可变类要使用final关键字。不可变类是指它的对象一旦被创建了就不能被更改了。String是不可变类的代表。不可变类有很多好处,譬如它们的对象是只读的,可以在多线程环境下安全的共享,不用额外的同步开销等等。
String是所有语言中最常用的一个类。我们知道在Java中,String是不可变的、final的。Java在运行时也保存了一个字符串池(String pool),这使得String成为了一个特别的类。
n String类不可变性的好处
以上就是我总结的字符串不可变性的好处。
不可变对象对于缓存是非常好的选择,因为你不需要担心它的值会被更改。不可变类的另外一个好处是它自身是线程安全的,你不需要考虑多线程环境下的线程安全问题。
n 下面是创建不可变类的方法,我也给出了代码,加深理解。
FinalClassExample.java
package com.journaldev.java;
import java.util.HashMap; import java.util.Iterator;
public final class FinalClassExample {
private final int id;
private final String name;
private final HashMap testMap;
public int getId() { return id; }
public String getName() { return name; }
/** * 可变对象的访问方法 */ public HashMap getTestMap() { //return testMap; return (HashMap) testMap.clone(); }
/** * 实现深拷贝(deep copy)的构造器 * @param i * @param n * @param hm */
public FinalClassExample(int i, String n, HashMap hm){ System.out.println("Performing Deep Copy for Object initialization"); this.id=i; this.name=n; HashMap tempMap=new HashMap(); String key; Iterator it = hm.keySet().iterator(); while(it.hasNext()){ key=it.next(); tempMap.put(key, hm.get(key)); } this.testMap=tempMap; }
/** * 实现浅拷贝(shallow copy)的构造器 * @param i * @param n * @param hm */ /** public FinalClassExample(int i, String n, HashMap hm){ System.out.println("Performing Shallow Copy for Object initialization"); this.id=i; this.name=n; this.testMap=hm; } */
/** * 测试浅拷贝的结果 * 为了创建不可变类,要使用深拷贝 * @param args */ public static void main(String[] args) { HashMap h1 = new HashMap(); h1.put("1", "first"); h1.put("2", "second");
String s = "original";
int i=10;
FinalClassExample ce = new FinalClassExample(i,s,h1);
//Lets see whether its copy by field or reference System.out.println(s==ce.getName()); System.out.println(h1 == ce.getTestMap()); //print the ce values System.out.println("ce id:"+ce.getId()); System.out.println("ce name:"+ce.getName()); System.out.println("ce testMap:"+ce.getTestMap()); //change the local variable values i=20; s="modified"; h1.put("3", "third"); //print the values again System.out.println("ce id after local variable change:"+ce.getId()); System.out.println("ce name after local variable change:"+ce.getName()); System.out.println("ce testMap after local variable change:"+ce.getTestMap());
HashMap hmTest = ce.getTestMap(); hmTest.put("4", "new");
System.out.println("ce testMap after changing variable from accessor methods:"+ce.getTestMap());
}
}
|
输出:
Performing Deep Copy for Object initialization true false ce id:10 ce name:original ce testMap:{2=second, 1=first} ce id after local variable change:10 ce name after local variable change:original ce testMap after local variable change:{2=second, 1=first} ce testMap after changing variable from accessor methods:{2=second, 1=first} |
现在我们注释掉深拷贝的构造器,取消对浅拷贝构造器的注释。也对getTestMap()方法中的返回语句取消注释,返回实际的对象引用。然后再一次执行代码。
Performing Shallow Copy for Object initialization true true ce id:10 ce name:original ce testMap:{2=second, 1=first} ce id after local variable change:10 ce name after local variable change:original ce testMap after local variable change:{3=third, 2=second, 1=first} ce testMap after changing variable from accessor methods:{3=third, 2=second, 1=first, 4=new} |
从输出可以看出,HashMap的值被更改了,因为构造器实现的是浅拷贝,而且在getter方法中返回的是原本对象的引用。
private
final
int
COUNT =
10;
我们已经知道final变量、final方法以及final类是什么了。必要的时候使用final,能写出更快、更好的代码的。
如对本文有疑问, 点击进行留言回复!!
Android 4.0使用Kotlin调用C语言以及汇编语言
Java Class.forName()用法和newInstance()方法原理解析
网友评论