鄙人最近嘗試着翻譯了本身的第一篇英文技術文檔。
Java Nested Classes Reference From Oracle Documentationhtml
在Java中咱們能夠在一個類的內部,再定義另一個類,其中裏面的那個類被稱爲嵌套類,示例以下。java
class OuterClass { ... class NestedClass { ... } }
術語:嵌套類有兩種類型:靜態和非靜態,當嵌套類被static修飾時,被稱爲靜態嵌套類(static nested classes),沒有被static修飾時的嵌套類被稱做內部類(inner classes)oracle
class OuterClass { ... static class StaticNestedClass { ... } class InnerClass { ... } }
嵌套類是外部基類(即外部類)的成員,非靜態嵌套類(內部類)能夠獲取到外圍基類的其餘成員,其中也包括被聲明爲private的成員。靜態嵌套類則不能夠獲取基類的其餘成員。當作爲做爲外部類的成員,嵌套類能夠被定義爲private,public,protected或者package private。若是咱們須要在其餘外部類中使用內部類,則必定要將嵌套類聲明爲public或者 package private。ide
使用嵌套類有如下幾個明顯的優點:this
靜態嵌套類不能直接引用外部基類的實例變量和實例方法,對於這樣的實例變量僅能夠經過對象引用來獲取。編碼
經過使用外圍基類名稱來獲取靜態嵌套類spa
OuterClass.StaticNestedClass
若是咱們想建立一個靜態嵌套類的對象,則可使用以下的方式翻譯
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
內部類能夠經過外部類實例,直接獲取基類對象的變量和方法,同理由於內部類是經過實例引用來和外部類創建關係的,因此在內部類中不能定義任何的靜態成員。只有當外部類實例對象被建立出來以後,才能夠實例化內部類。code
class OuterClass { ... class InnerClass { ... } }
內部類實例只能存在於外部類實例中,而且能夠直接訪問其外部類實例的方法和字段。orm
在實例化內部類前,要先實例化外部類實例。能夠經過以下方式,經過外部對象實例來建立內部類對象。
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
內部類有兩種類型:局部類(local classes) 和 匿名類(anonymous classes).
局部類是一種被定義在代碼塊中的類,局部類一般時定義在方法體中。
能夠在任何一個方法之中定義一個局部類,如for循環中,或者在if子句中。
下面的LocalClassExample,是用來驗證兩個手機號,在這個類的validatePhoneNumber方法中,定義了一個名爲PhoneNumber的局部類。
public class LocalClassExample { static String regularExpression = "[^0-9]"; public static void validatePhoneNumber( String phoneNumber1, String phoneNumber2) { final int numberLength = 10; // Valid in JDK 8 and later: // int numberLength = 10; class PhoneNumber { String formattedPhoneNumber = null; PhoneNumber(String phoneNumber){ // numberLength = 7; String currentNumber = phoneNumber.replaceAll( regularExpression, ""); if (currentNumber.length() == numberLength) formattedPhoneNumber = currentNumber; else formattedPhoneNumber = null; } public String getNumber() { return formattedPhoneNumber; } // Valid in JDK 8 and later: // public void printOriginalNumbers() { // System.out.println("Original numbers are " + phoneNumber1 + // " and " + phoneNumber2); // } } PhoneNumber myNumber1 = new PhoneNumber(phoneNumber1); PhoneNumber myNumber2 = new PhoneNumber(phoneNumber2); // Valid in JDK 8 and later: // myNumber1.printOriginalNumbers(); if (myNumber1.getNumber() == null) System.out.println("First number is invalid"); else System.out.println("First number is " + myNumber1.getNumber()); if (myNumber2.getNumber() == null) System.out.println("Second number is invalid"); else System.out.println("Second number is " + myNumber2.getNumber()); } public static void main(String... args) { validatePhoneNumber("123-456-7890", "456-7890"); } }
經過刪除原有手機號中除0-9以外的字符後,檢查新的字符串中是否有十個數字,輸出結果以下:
First number is 1234567890 Second number is invalid
局部類能夠獲取外部類的成員信息,在上一個例子中,PhoneNumber局部類的構造方法裏經過LocalClassExample.regularExpression,就拿到了外部類中的regularExpression成員。
另外,局部類中也能使用局部變量,可是在局部類中只能使用被final修飾後的變量,當一個局部類要使用定義在外部代碼塊中的局部變量或者參數時,他會俘獲(這個變量就是他的了)這個變量或者參數。
好比,PhoneNumber的構造方法中,可以/會,俘獲numberLength,由於這個變量在外圍塊中被聲明爲final,這樣的話numberLength 就成爲了一個被俘獲的變量了,有了主人。
可是在java 1.8版本中局部類可以使用定義在外部塊中的final或者effectively final的變量或者參數,若是一個變量或者參數的值在初始化後便不會被改變,則被稱爲effectively final。
好比在下面的代碼中,變量numberLength沒有被顯示的聲明爲final,在初始化後有在方法中又將numberLength的值修改成7:
PhoneNumber(String phoneNumber) { numberLength = 7; String currentNumber = phoneNumber.replaceAll( regularExpression, ""); if (currentNumber.length() == numberLength) formattedPhoneNumber = currentNumber; else formattedPhoneNumber = null; }
由於這個賦值語句numberLength = 7,變量numberLength 便再也不是 effectively final了,在這種情形下,內部類嘗試在if (currentNumber.length() == numberLength)
這行代碼中獲取numberLength時,編譯器時會提示"local variables referenced from an inner class must be final or effectively final"
。
在java8中,若是在方法中聲明瞭局部類,那麼能夠在局部類中拿到方法的入參,就像下面的方法:
public void printOriginalNumbers() { System.out.println("Original numbers are " + phoneNumber1 + " and " + phoneNumber2); }
局部類中的printOriginalNumbers方法獲取到了方法validatePhoneNumber中的phoneNumber1 和phoneNumber2兩個參數變量。
局部類像內部類同樣,兩者都不能定義和聲明靜態成員,在靜態方法validatePhoneNumber中定義的PhoneNumber局部類,只能引用外部類中的靜態成員。
若是將變量regularExpression定義爲非靜態,那麼在java編譯器編譯的時候會提示"non-static variable regularExpression cannot be referenced from a static context."錯誤信息。
由於要獲取外圍代碼塊中的實例成員,因此局部類不能時靜態的,因此在局部類中不能包含有靜態聲明。
不能在代碼塊中,嘗試定義或者聲明接口,由於接口本質上就是靜態的,好比下面的代碼是不能編譯成功的,由於在greetInEnglish方法內部包含有HelloThere接口:
public void greetInEnglish() { interface HelloThere { public void greet(); } class EnglishHelloThere implements HelloThere { public void greet() { System.out.println("Hello " + name); } } HelloThere myGreeting = new EnglishHelloThere(); myGreeting.greet(); }
固然在局部類中也不能聲明靜態方法,下面的代碼一樣,在編譯時會報"modifier 'static' is only allowed in constant variable declaration"
,由於EnglishGoodbye.sayGoodbye這個方法被聲明爲靜態方法了。
public void sayGoodbyeInEnglish() { class EnglishGoodbye { public static void sayGoodbye() { System.out.println("Bye bye"); } } EnglishGoodbye.sayGoodbye(); }
局部類中只有變量時常量的時候,纔可能會出現有靜態成員變量的狀況,下面的代碼中有靜態成員但也能夠編譯經過,由於靜態變量EnglishGoodbye.farewell是常量。
public void sayGoodbyeInEnglish() { class EnglishGoodbye { public static final String farewell = "Bye bye"; public void sayGoodbye() { System.out.println(farewell); } } EnglishGoodbye myEnglishGoodbye = new EnglishGoodbye(); myEnglishGoodbye.sayGoodbye(); }
匿名類可使你的代碼看上去更加的精簡,能夠在聲明一個匿名類的同時對它進行初始化,除了沒有類名之外,它跟局部類很像,對於只會使用一次的局部類的場景咱們能夠用匿名類來代替。
局部類就是一個類,而匿名類則更像是一個表達式,那麼咱們即可以在另外的表達式中使用匿名類。
下面的例子中 HelloWorldAnonymousClasses經過使用匿名類建立局部變量frenchGreeting 和spanishGreeting,經過使用局部類來建立和初始化englishGreeting。
原文出處:https://www.cnblogs.com/lingyejun/p/10085629.html