final關鍵字
先看看final關鍵字,它能夠被用於如下幾個地方:
一、修飾屬性、局部變量、方法參數:
若是final修飾的是一個基本類型,就表示這個變量所賦予的值不可修改,即它是個常量;若是final修飾的是一個對象,就表示這個變量被賦予的引用不可修改(但咱們能夠修改該引用所指向對象裏的內容,這裏所說的不可修改是指final修改的引用一但指向了誰,就不能再指向別的對象了)。下面來看看修改屬性與變量時須要注意的幾點:
在方法中定義的內部類只能訪問方法中的final類型的局部變量,由於用final定義的局部變量是一個常量,運行時不是放在棧裏的,所以它的生命同期超出了方法運行的生命週期:
編程
//final不能去掉,不然編譯通不過 spa
public Comparable f(final Comparable o1) { 指針
return new Comparable() { orm
public int compareTo(Object o2) { 對象
return o1.compareTo(o2); blog
} 繼承
}; 接口
} 生命週期
final修改的靜態屬性,必須在聲明的同時或者在靜態塊中初始化;final修飾的非靜態屬性,必須在聲明的同時、或非靜態塊中或者是構造函數中初始化:
public class A {
private final int a = 1;//非靜態屬性在定義時初始化
private final static int b = 1;//靜態屬性在定義時初始化
private final int c;//非靜態屬性在定義時未初始化
{
//非靜態屬性在非靜態塊中初始化
c = 1; (對)
}
private final static int d;//靜態屬性在定義時未初始化
static {
//靜態屬性在靜態塊中初始化
d = 1; (對)
}
private final int e;//非靜態屬性在定義時未初始化
A() {
//非靜態屬性在構造函數中初始化
e = 1; (對)
}
}
靜態屬性不能在非靜態塊中初始化(由於非靜態塊是在new時才調用,而靜態屬性在對象尚未建立時也能使用(靜態屬性在類加載的時候進行了初始化));
非靜態屬性不能在靜態塊中(由於在靜態塊中不能訪問非靜態屬性、變量及方法)初始化,能夠在非靜態塊或構造函數中初始化
public class A {
private final int a;//!! 非靜態屬性未初始化
private final static int b;//!! 靜態屬性未初始化
private final int c;
static {
//!! 非靜態屬性不能在靜態塊中初始化
c = 1; (錯)
}
private final static int d;
{
//!! 靜態屬性不能在非靜態塊中初始化
d = 1; (錯)
}
private final static int e;
A() {
//!! 靜態屬性不能在構造函數中初始化
e = 1; (錯)
}
}
接口中的屬性成員默認就是 public final static,只能在定義時就初始化:方法默認是public abstract
package A;
public interface A {
//接口中的屬性成員默認就是 public final static
int i = 1;
// !! 接口中的訪問修飾符只能是 public (Illegal modifier for the interface field idd.a; only public, static & final are permitted) ,但可不寫
//protected int a = 1; (錯)
// !! 接口中的屬性只能在定義時就初始化
// public static final int b; (錯)
public static final int b=0; (對)
// !! 接口中的屬性是常量,不能在靜態塊與非靜態塊中初始化,由於接口中不能有靜態塊與非靜態塊
// (錯) static{
// b=1;
// }
// (錯) {
// b=1;
// }
// 接口中方法的訪問修飾符只能是 public (Illegal modifier for the interface method ssss; only public & abstract are permitted) ,但可不寫
// public void ssss();
}
package B;
import A.A;
public class B {
public static void main(String[] args) {
// !! 不能修改,由於接口中的定義的屬性默認就是final
//A.i = 2; (錯)
//接口中的定義的屬性默認就是public final static,由於能夠被不一樣包靜態訪問
System.out.println(A.i);
}
}
這裏提到了靜態區與非靜態區,它們的區別是,靜態區在類裝載時執行一次,而非靜態區每在實例化一個對象時就執行一次:
public class A {
static {
System.out.println("static block");
}
{
System.out.println("block");
}
public static void main(String[] args) {
new A();
new A();
}
/* output:
static block
block
block
*/
}
另外,用final修飾的變量會有更高的效率,若是一個變量不在變化時,那麼它就應該定義成常量,因此在須要的地方咱們儘可能使用常量,由於這樣在編譯時期就能肯定。
二、修飾方法:
被final修改的方法不能被覆寫。
class A {
public final void f() {}
}
class B extends A {
// !! 不能覆寫final方法
// public void f() {} (錯)
// public final void f() {} (錯)
}
private方法默認就是final方法,編譯器在處理private方法時,是按照final方法來對待的,這樣能夠提升該方法被調用時的效率。
三、修飾類
final類不容許被繼承(若是String類),編譯器在處理時把它的全部方法都看成final的(但數據成員既能夠是final,也能夠不是,以定義時前面修飾爲準),所以final類比普通類擁有更高的效率:
final class A {
//注,final中的屬性能夠是final,也能夠不是,以定義時前面修飾爲準
int i = 1;
public final void f() {}
//final類中的全部方法默認就是final方法
void m() {}
}
// !! final 類不能繼承
//class B extends A {}
public class C {
public static void main(String[] args) {
A a = new A();
a.i = 2;//能夠修改final類的非final屬性成員
}
}
接口與抽象類不能用final來修飾,即final interface、final abstract class是不容許的:
// !! 接口不能用final來修飾
public final interface A {} (錯)
// !! 抽象類不能用final來修飾
public final abstract class A {} (錯)
finally關鍵字
finally關鍵字用在try/catch語句最末,表示不論是否拋出異常,finally塊中的語句最終確定、必定會被執行,執行的順序爲 try塊 —> finally塊(不拋異常狀況下)或 try塊 —> catch塊(拋異常狀況下)—> finally塊 :
try {//不拋異常狀況下
System.out.println("try");
}
catch (Exception e) {
System.out.println("catch");
}
finally {
System.out.println("finally");
}
System.out.println("last");
/* output:
try
finally
last
*/
try {//拋異常狀況下
System.out.println("try");
throw new NullPointerException();
}
catch (NullPointerException e) {
System.out.println("catch");
throw e;//再次拋出
}
finally {
//不論是try塊仍是catch塊裏拋異常,finally塊最後必定會執行
System.out.println("finally");
}
// System.out.println("finally"); (錯) 編譯不經過;由於有了catch裏有了throw e;//catch裏再次拋出異常後,不能在finally後面再寫了,若是沒有在catch裏再拋出異常就能夠
結果:
/* output:
try
catch
finally
*/
下面看看try、catch、finally有return語句時,到底從哪裏返回:
class A {
public static void main(String[] args) {
System.out.println(A.f1());//3
System.out.println(A.f2());//2
try {
System.out.println(A.f3());//方法異常結束
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println(A.f4());//1
System.out.println(A.f5());//4
try {
System.out.println(A.f6());//方法異常結束
}
catch (Exception e) {
e.printStackTrace();
}
}
/*
* 若是 finally 塊中有 return 語句,則忽略 try、catch 塊中的retrun ,
* 但 finally 中有return不是一種好的編程方式,這樣會引發編譯時警告
*/
public static int f1() {
System.out.println("--f1()--");
try {
System.out.println("f1 - 1");
nullExcp();//拋空指針異常
return 1;
}
catch (NullPointerException e) { 沒執行)
System.out.println("f1 - 2");
return 2;
}
finally {
System.out.println("f1 - 3");
return 3;//從這裏返回
}
/*
* !! 這裏不能有語句,由於方法在此前已從finally塊中返回,或者finally 塊中已拋
* 異常後方法結束,但要注意的是,無論catch塊中是否拋異常,最會執行finally塊
*/
// return 4;
}
/*
* 若是 finally 塊中沒有 return 語句,但 try、catch 塊中有時,若是try中不拋
* 異常,則從try語句塊中正常返回,若是try中拋出異常,則從catch塊中正常返回或者
* catch拋出異常時方法異常結束
*/
public static int f2() {
System.out.println("--f2()--");
try {
System.out.println("f1 - 1");
nullExcp();//拋空指針異常
return 1;
}
catch (NullPointerException e) {
System.out.println("f1 - 2");
return 2;//從這裏返回
}
finally {
System.out.println("f1 - 3");
}
/*
* !! 這裏也不能有其餘語句了,由於到此方法已經正常或異常結束了
*/
// return 4;
}
//try與catch塊都拋異常,最後方法在執行完finally塊後從catch塊中異常結束
public static int f3() {
System.out.println("--f3()--");
try {
System.out.println("f1 - 1");
nullExcp();//拋空指針異常
return 1;
}
catch (NullPointerException e) {
System.out.println("f1 - 2");
nullExcp();//拋空指針異常,從這裏方法異常結束
return 2;
}
finally {
System.out.println("f1 - 3");
}
/*
* !! 這裏也不能有其餘語句了,由於到此方法已經正常或異常結束了
*/
// return 4;
}
//這是咱們一般寫法,只在try或最後返回結果:正常從try中返回
public static int f4() {
System.out.println("--f4()--");
try {
System.out.println("f1 - 1");
return 1;//從這裏返回
}
catch (NullPointerException e) {
System.out.println("f1 - 2");
}
finally {
System.out.println("f1 - 3");
}
return 4;
}
//這是咱們一般寫法,只在try或最後返回結果:異常後從最後返回
public static int f5() {
System.out.println("--f5()--");
try {
System.out.println("f1 - 1");
nullExcp();//拋空指針異常
return 1;
}
catch (NullPointerException e) {
System.out.println("f1 - 2");
}
finally {
System.out.println("f1 - 3");
}
return 4;//從這裏返回
}
public static int f6() {
System.out.println("--f6()--");
try {
System.out.println("f1 - 1");
nullExcp();//拋空指針異常
return 1;
}
catch (NullPointerException e) {
System.out.println("f1 - 2");
nullExcp();//拋空指針異常,從這裏方法異常結束
}
finally {
System.out.println("f1 - 3");
}
return 4;
}
private static void nullExcp() {
throw new NullPointerException();
}
}
從上面例子能夠看出return語句是不會阻止finally塊執行的,那麼continue和break可否阻止?答案是不會的,與return同樣,finally語句塊是在循環被跳過(continue)和中斷(break)以前被執行的:
class A {
public static void main(String[] args) {
int i = 0;
System.out.println("--continue--");
while (i++ <= 1) {
try {
System.out.println("i=" + i);
continue;
}
catch (Exception e) {
e.printStackTrace();
}
finally {
System.out.println("finally");
}
}
System.out.println("--break--");
while (i++ <= 3) {
try {
System.out.println("i=" + i);
break;
}
catch (Exception e) {
e.printStackTrace();
}
finally {
System.out.println("finally2");
}
}
}
}
結果:
--continue--
i=1
finally
i=2
finally
--break--
i=4
finally2
finalize關鍵字
finalize()是Object類的一個方法,finalize()方法是GC(garbage collector)運行機制的一部分,由對象的垃圾回收器調用此方法,當一個對象被回收時,finalize()方法將會被調用。但咱們要注意的是,若是 finalize 方法拋出未捕獲的異常,那麼該異常將被忽略,而且該對象的終結操做將終止:
protected void finalize() throws Throwable {
System.out.println("finalize");
}
public static void main(String[] args) {
A a = new A();
a = null;
//加快GC回收,但不必定立刻執行加收動做,由虛擬機決定
System.gc();
}
參考原文地址:http://jiangzhengjun.iteye.com/blog/577045