成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java Nested Classes(內(nèi)部類~第一篇英文技術(shù)文檔翻譯)

zzzmh / 1927人閱讀

摘要:鄙人最近嘗試著翻譯了自己的第一篇英文技術(shù)文檔。如果我們需要在其他外部類中使用內(nèi)部類,則一定要將嵌套類聲明為或者。方法中的會(huì)覆蓋掉內(nèi)部類中的。因此,對(duì)于一個(gè)內(nèi)部類序列化后,使用不同的進(jìn)行反序列化的話,可能會(huì)存在兼容性的問題。

鄙人最近嘗試著翻譯了自己的第一篇英文技術(shù)文檔。
Java Nested Classes Reference From Oracle Documentation

嵌套類-Nested Classes

在Java中我們可以在一個(gè)類的內(nèi)部,再定義另外一個(gè)類,其中里面的那個(gè)類被稱為嵌套類,示例如下。

class OuterClass {
    ...
    class NestedClass {
        ...
    }
}

術(shù)語:嵌套類有兩種類型:靜態(tài)和非靜態(tài),當(dāng)嵌套類被static修飾時(shí),被稱為靜態(tài)嵌套類(static nested classes),沒有被static修飾時(shí)的嵌套類被稱作內(nèi)部類(inner classes)

class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}

嵌套類是外部基類(即外部類)的成員,非靜態(tài)嵌套類(內(nèi)部類)可以獲取到外圍基類的其他成員,其中也包括被聲明為private的成員。靜態(tài)嵌套類則不可以獲取基類的其他成員。當(dāng)做為作為外部類的成員,嵌套類可以被定義為private,public,protected或者package private。如果我們需要在其他外部類中使用內(nèi)部類,則一定要將嵌套類聲明為public或者 package private。

為什么使用嵌套類-Why Use Nested Classes?

使用嵌套類有以下幾個(gè)明顯的優(yōu)勢:

當(dāng)僅會(huì)在一處用到某個(gè)類時(shí),通過嵌套類可以在邏輯上與基類(外部類)保持一種緊密的聯(lián)系關(guān)系:當(dāng)一個(gè)類只會(huì)在另一個(gè)類中使用,那么就可以把這個(gè)類嵌入到另外一個(gè)類中,可以使得兩者之間有著緊密的聯(lián)系,嵌套類又稱之為"輔助類"。

通過合理的使用可以使得整個(gè)包下的類定義更加的簡潔:更強(qiáng)的封裝性:A和B兩個(gè)類,B作為A類的嵌套類,如果不將其中B類B類設(shè)置為private的話,那么B類就擁有訪問A類成員的權(quán)限。

更好的可讀性和更高的可維護(hù)性:在編碼時(shí)內(nèi)部的嵌套類總是需要和最外層類保持一種形式上的關(guān)聯(lián)關(guān)系。

靜態(tài)嵌套類-Static Nested Classes

靜態(tài)嵌套類不能直接引用外部基類的實(shí)例變量和實(shí)例方法,對(duì)于這樣的實(shí)例變量僅可以通過對(duì)象引用來獲取。

通過使用外圍基類名稱來獲取靜態(tài)嵌套類

OuterClass.StaticNestedClass

如果我們想創(chuàng)建一個(gè)靜態(tài)嵌套類的對(duì)象,則可以使用如下的方式

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
內(nèi)部類-Inner Classes

內(nèi)部類可以通過外部類實(shí)例,直接獲取基類對(duì)象的變量和方法,同理因?yàn)閮?nèi)部類是通過實(shí)例引用來和外部類建立關(guān)系的,所以在內(nèi)部類中不能定義任何的靜態(tài)成員。只有當(dāng)外部類實(shí)例對(duì)象被創(chuàng)建出來之后,才可以實(shí)例化內(nèi)部類。

class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

內(nèi)部類實(shí)例只能存在于外部類實(shí)例中,并且可以直接訪問其外部類實(shí)例的方法和字段。

在實(shí)例化內(nèi)部類前,要先實(shí)例化外部類實(shí)例??梢酝ㄟ^如下方式,通過外部對(duì)象實(shí)例來創(chuàng)建內(nèi)部類對(duì)象。

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

內(nèi)部類有兩種類型:局部類(local classes) 和 匿名類(anonymous classes).

局部類-Local Classes

局部類是一種被定義在代碼塊中的類,局部類通常時(shí)定義在方法體中。

如何聲明局部類:

可以在任何一個(gè)方法之中定義一個(gè)局部類,如for循環(huán)中,或者在if子句中。

下面的LocalClassExample,是用來驗(yàn)證兩個(gè)手機(jī)號(hào),在這個(gè)類的validatePhoneNumber方法中,定義了一個(gè)名為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");
    }
}

通過刪除原有手機(jī)號(hào)中除0-9之外的字符后,檢查新的字符串中是否有十個(gè)數(shù)字,輸出結(jié)果如下:

First number is 1234567890
Second number is invalid
獲取外部類成員

局部類可以獲取外部類的成員信息,在上一個(gè)例子中,PhoneNumber局部類的構(gòu)造方法里通過LocalClassExample.regularExpression,就拿到了外部類中的regularExpression成員。

另外,局部類中也能使用局部變量,但是在局部類中只能使用被final修飾后的變量,當(dāng)一個(gè)局部類要使用定義在外部代碼塊中的局部變量或者參數(shù)時(shí),他會(huì)俘獲(這個(gè)變量就是他的了)這個(gè)變量或者參數(shù)。

比如,PhoneNumber的構(gòu)造方法中,能夠/會(huì),俘獲numberLength,因?yàn)檫@個(gè)變量在外圍塊中被聲明為final,這樣的話numberLength 就成為了一個(gè)被俘獲的變量了,有了主人。

但是在java 1.8版本中局部類能夠使用定義在外部塊中的final或者effectively final的變量或者參數(shù),如果一個(gè)變量或者參數(shù)的值在初始化后便不會(huì)被改變,則被稱為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;
}

因?yàn)檫@個(gè)賦值語句numberLength = 7,變量numberLength 便不再是 effectively final了,在這種情形下,內(nèi)部類嘗試在if (currentNumber.length() == numberLength)這行代碼中獲取numberLength時(shí),編譯器時(shí)會(huì)提示"local variables referenced from an inner class must be final or effectively final"。

在java8中,如果在方法中聲明了局部類,那么可以在局部類中拿到方法的入?yún)?,就像下面的方法?/p>

public void printOriginalNumbers() {
    System.out.println("Original numbers are " + phoneNumber1 +
        " and " + phoneNumber2);
}

局部類中的printOriginalNumbers方法獲取到了方法validatePhoneNumber中的phoneNumber1 和phoneNumber2兩個(gè)參數(shù)變量。

局部類與內(nèi)部類的相似點(diǎn)

局部類像內(nèi)部類一樣,二者都不能定義和聲明靜態(tài)成員,在靜態(tài)方法validatePhoneNumber中定義的PhoneNumber局部類,只能引用外部類中的靜態(tài)成員。

如果將變量regularExpression定義為非靜態(tài),那么在java編譯器編譯的時(shí)候會(huì)提示"non-static variable regularExpression cannot be referenced from a static context."錯(cuò)誤信息。

因?yàn)橐@取外圍代碼塊中的實(shí)例成員,所以局部類不能時(shí)靜態(tài)的,所以在局部類中不能包含有靜態(tài)聲明。

不能在代碼塊中,嘗試定義或者聲明接口,因?yàn)榻涌诒举|(zhì)上就是靜態(tài)的,比如下面的代碼是不能編譯成功的,因?yàn)樵趃reetInEnglish方法內(nèi)部包含有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();
}

當(dāng)然在局部類中也不能聲明靜態(tài)方法,下面的代碼同樣,在編譯時(shí)會(huì)報(bào)"modifier "static" is only allowed in constant variable declaration",因?yàn)镋nglishGoodbye.sayGoodbye這個(gè)方法被聲明為靜態(tài)方法了。

public void sayGoodbyeInEnglish() {
    class EnglishGoodbye {
        public static void sayGoodbye() {
            System.out.println("Bye bye");
        }
    }
    EnglishGoodbye.sayGoodbye();
}

局部類中只有變量時(shí)常量的時(shí)候,才可能會(huì)出現(xiàn)有靜態(tài)成員變量的情況,下面的代碼中有靜態(tài)成員但也可以編譯通過,因?yàn)殪o態(tài)變量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();
}
匿名類-Anonymous Classes

匿名類可以使你的代碼看上去更加的精簡,可以在聲明一個(gè)匿名類的同時(shí)對(duì)它進(jìn)行初始化,除了沒有類名以外,它跟局部類很像,對(duì)于只會(huì)使用一次的局部類的場景我們可以用匿名類來代替。

局部類就是一個(gè)類,而匿名類則更像是一個(gè)表達(dá)式,那么我們便可以在另外的表達(dá)式中使用匿名類。
下面的例子中 HelloWorldAnonymousClasses通過使用匿名類創(chuàng)建局部變量frenchGreeting 和spanishGreeting,通過使用局部類來創(chuàng)建和初始化englishGreeting。

public class HelloWorldAnonymousClasses {
  
    interface HelloWorld {
        public void greet();
        public void greetSomeone(String someone);
    }
  
    public void sayHello() {
        
        class EnglishGreeting implements HelloWorld {
            String name = "world";
            public void greet() {
                greetSomeone("world");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hello " + name);
            }
        }
      
        HelloWorld englishGreeting = new EnglishGreeting();
        
        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "tout le monde";
            public void greet() {
                greetSomeone("tout le monde");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Salut " + name);
            }
        };
        
        HelloWorld spanishGreeting = new HelloWorld() {
            String name = "mundo";
            public void greet() {
                greetSomeone("mundo");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hola, " + name);
            }
        };
        englishGreeting.greet();
        frenchGreeting.greetSomeone("Fred");
        spanishGreeting.greet();
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp =
            new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }            
}
如何使用和定義一個(gè)匿名類

我們可以通過frenchGreeting的創(chuàng)建過程來一探匿名類的組成。

HelloWorld frenchGreeting = new HelloWorld() {
    String name = "tout le monde";
    public void greet() {
        greetSomeone("tout le monde");
    }
    public void greetSomeone(String someone) {
        name = someone;
        System.out.println("Salut " + name);
    }
};
匿名類的組成部分

new 操作符

要實(shí)現(xiàn)的接口名,或者要繼承的父類的名稱,在此例中匿名類實(shí)現(xiàn)了HelloWorld接口。

括號(hào),跟一般初始化一個(gè)類實(shí)例別無二致,需要填入構(gòu)造方法中的構(gòu)造參數(shù),注:用匿名類實(shí)現(xiàn)接口時(shí),沒有構(gòu)造方法,那么括號(hào)中不需要填參數(shù)即可。

類主體,即匿名類的實(shí)現(xiàn)。

因?yàn)槟涿惐划?dāng)做表達(dá)式一樣被使用,如在定義frenchGreeting對(duì)象時(shí),匿名類的全部定義都是該表達(dá)式的一部分, 這也解釋了為什么匿名類定義的最后要以;結(jié)尾,因?yàn)楸磉_(dá)式以分號(hào);結(jié)尾。

訪問外部類的局部變量、聲明和使用匿名類成員

像局部類一樣,匿名類同樣也可以俘獲變量,對(duì)于外部區(qū)域的局部變量擁有一樣的訪問特性。

匿名類可以訪問外部其封閉類的成員

匿名類無法訪問那些不是final或者effectively final的局部變量

匿名類中的聲明的類型變量,會(huì)覆蓋掉外部區(qū)域中的同名的變量

對(duì)于匿名類中的成員,匿名類具有跟局部類相同的限制

不能在匿名類中聲明靜態(tài)代碼塊,或者再定義內(nèi)部成員接口

匿名類中僅當(dāng)變量為常量時(shí),才可以出現(xiàn)靜態(tài)成員

小結(jié),在匿名類中可以聲明如下內(nèi)容

列表項(xiàng)目

字段

額外的方法(即使不實(shí)現(xiàn)任何父類的方法)

實(shí)例代碼塊

局部類

但是,不可以在匿名類中聲明構(gòu)造方法

匿名類的一個(gè)實(shí)例

匿名類在java GUI中使用的較為頻繁

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
 
public class HelloWorld extends Application {
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Hello World!");
        Button btn = new Button();
        btn.setText("Say "Hello World"");
        btn.setOnAction(new EventHandler() {
 
            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });
        
        StackPane root = new StackPane();
        root.getChildren().add(btn);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }
}
變量覆蓋問題-Shadowing

在內(nèi)部類或者方法定義中聲明的變量類型跟外圍區(qū)域有相同的名稱,那么內(nèi)部的聲明會(huì)覆蓋掉外部區(qū)域中的聲明,不能直接通過變量名拿到外部區(qū)域中定義的變量,如下所示:

public class ShadowTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
        }
    }

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}

輸出如下

x = 23
this.x = 1
ShadowTest.this.x = 0

示例代碼中定義了三個(gè)名為x的變量,ShadowTest中的成員變量,內(nèi)部類FirstLevel中成員變量,以及方法methodInFirstLevel中的參數(shù)。
方法methodInFirstLevel中的x會(huì)覆蓋掉內(nèi)部類FirstLevel中的x。因?yàn)楫?dāng)你在方法methodInFirstLevel中使用變量x時(shí),實(shí)際上使用的的是方法參數(shù)的值。
如果想引用內(nèi)部類FirstLevel中的x,需要使用this關(guān)鍵字,來代表引用的時(shí)內(nèi)部類中方法外圍的x。

System.out.println("this.x = " + this.x);

如果向引用最外面的基類變量x,則需要指明外部類的類名

System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
序列化問題-Serialization

我們強(qiáng)烈不建議對(duì)內(nèi)部類、局部類及匿名類,實(shí)現(xiàn)序列化。
當(dāng)Java編譯器編譯內(nèi)部類的構(gòu)造方法時(shí),會(huì)生成synthetic constructs。即一些在源碼中未曾出現(xiàn)過的類、方法、字段和其他的構(gòu)造方法也會(huì)被編譯出來。
synthetic constructs方式,可以在不改變JVM的前提下,只通過java編譯器就可以實(shí)現(xiàn)java的新特性。然而,不同的編譯器實(shí)現(xiàn)synthetic constructs的方式有所不同,這也就意味著,對(duì)于同樣的.java源碼,不同的編譯器會(huì)編譯出來不同的.class文件。
因此,對(duì)于一個(gè)內(nèi)部類序列化后,使用不同的JRE進(jìn)行反序列化的話,可能會(huì)存在兼容性的問題。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/72583.html

相關(guān)文章

  • 內(nèi)部和靜態(tài)嵌套

    摘要:嵌套類增加了封裝性內(nèi)部類和靜態(tài)嵌套類的不同根源來自于,最大區(qū)別在于訪問外部類成員的權(quán)限。靜態(tài)嵌套類修飾符使得嵌套類對(duì)象成為外部類的靜態(tài)成員,與外部類直接關(guān)聯(lián)。 術(shù)語規(guī)范:按照官方文檔,定義在外部類(封裝類)內(nèi)部的類稱之為nested class,根據(jù)是否被static關(guān)鍵字修飾又分為兩類:static nested classes 和 inner classes。 class Oute...

    hsluoyz 評(píng)論0 收藏0
  • 程序語言

    摘要:一面應(yīng)該還問了其他內(nèi)容,但是兩次面試多線程面試問題和答案采訪中,我們通常會(huì)遇到兩個(gè)主題采集問題和多線程面試問題。多線程是關(guān)于并發(fā)和線程的。我們正在共享重要的多線程面試問題和答案。。 2016 年末,騰訊,百度,華為,搜狗和滴滴面試題匯總 2016 年未,騰訊,百度,華為,搜狗和滴滴面試題匯總 【碼農(nóng)每日一題】Java 內(nèi)部類(Part 2)相關(guān)面試題 關(guān)注一下嘛,又不讓你背鍋!問:Ja...

    mtunique 評(píng)論0 收藏0
  • 程序語言

    摘要:一面應(yīng)該還問了其他內(nèi)容,但是兩次面試多線程面試問題和答案采訪中,我們通常會(huì)遇到兩個(gè)主題采集問題和多線程面試問題。多線程是關(guān)于并發(fā)和線程的。我們正在共享重要的多線程面試問題和答案。。 2016 年末,騰訊,百度,華為,搜狗和滴滴面試題匯總 2016 年未,騰訊,百度,華為,搜狗和滴滴面試題匯總 【碼農(nóng)每日一題】Java 內(nèi)部類(Part 2)相關(guān)面試題 關(guān)注一下嘛,又不讓你背鍋!問:Ja...

    stefan 評(píng)論0 收藏0
  • Spring、Spring Boot和TestNG測試指南 - 使用Spring Boot Test

    摘要:地址前面一個(gè)部分講解了如何使用工具來測試項(xiàng)目,現(xiàn)在我們講解如何使用工具來測試項(xiàng)目。所以我們可以利用這個(gè)特性來進(jìn)一步簡化測試代碼。因?yàn)橹挥羞@樣才能夠在測試環(huán)境下發(fā)現(xiàn)生產(chǎn)環(huán)境的問題,也避免出現(xiàn)一些因?yàn)榕渲貌煌瑢?dǎo)致的奇怪問題。 Github地址 前面一個(gè)部分講解了如何使用Spring Testing工具來測試Spring項(xiàng)目,現(xiàn)在我們講解如何使用Spring Boot Testing工具來測...

    Anshiii 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

zzzmh

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<