Java 內(nèi)部類(lèi)

問(wèn):Java 常見(jiàn)的內(nèi)部類(lèi)有哪幾種,簡(jiǎn)單說(shuō)說(shuō)其特征?

答:靜態(tài)內(nèi)部類(lèi)、成員內(nèi)部類(lèi)、方法內(nèi)部類(lèi)(局部?jī)?nèi)部類(lèi))、匿名內(nèi)部類(lèi)。

  • 靜態(tài)內(nèi)部類(lèi)是定義在另一個(gè)類(lèi)里面用 static 修飾 class 的類(lèi),靜態(tài)內(nèi)部類(lèi)不需要依賴(lài)于外部類(lèi)(與類(lèi)的靜態(tài)成員屬性類(lèi)似)且無(wú)法使用其外部類(lèi)的非 static 屬性或方法(因?yàn)樵跊](méi)有外部類(lèi)對(duì)象的情況下可以直接創(chuàng)建靜態(tài)內(nèi)部類(lèi)的對(duì)象,如果允許訪問(wèn)外部類(lèi)的非 static 屬性或者方法就會(huì)產(chǎn)生矛盾)。

  • 成員內(nèi)部類(lèi)是沒(méi)有用 static 修飾且定義在在外部類(lèi)類(lèi)體中的類(lèi),是最普通的內(nèi)部類(lèi),可以看做是外部類(lèi)的成員,可以無(wú)條件訪問(wèn)外部類(lèi)的所有成員屬性和成員方法(包括 private 成員和靜態(tài)成員),而外部類(lèi)無(wú)法直接訪問(wèn)成員內(nèi)部類(lèi)的成員和屬性,要想訪問(wèn)必須得先創(chuàng)建一個(gè)成員內(nèi)部類(lèi)的對(duì)象然后通過(guò)指向這個(gè)對(duì)象的引用來(lái)訪問(wèn);當(dāng)成員內(nèi)部類(lèi)擁有和外部類(lèi)同名的成員變量或者方法時(shí)會(huì)發(fā)生隱藏現(xiàn)象(即默認(rèn)情況下訪問(wèn)的是成員內(nèi)部類(lèi)的成員,如果要訪問(wèn)外部類(lèi)的同名成員需要通過(guò) OutClass.this.XXX 形式訪問(wèn));成員內(nèi)部類(lèi)的 class 前面可以有 private 等修飾符存在。

  • 方法內(nèi)部類(lèi)(局部?jī)?nèi)部類(lèi))是定義在一個(gè)方法里面的類(lèi),和成員內(nèi)部類(lèi)的區(qū)別在于方法內(nèi)部類(lèi)的訪問(wèn)僅限于方法內(nèi);方法內(nèi)部類(lèi)就像是方法里面的一個(gè)局部變量一樣,所以其類(lèi) class 前面是不能有 public、protected、private、static 修飾符的,也不可以在此方法外對(duì)其實(shí)例化使用。

  • 匿名內(nèi)部類(lèi)是一種沒(méi)有構(gòu)造器的類(lèi)(實(shí)質(zhì)是繼承類(lèi)或?qū)崿F(xiàn)接口的子類(lèi)匿名對(duì)象),由于沒(méi)有構(gòu)造器所以匿名內(nèi)部類(lèi)的使用范圍非常有限,大部分匿名內(nèi)部類(lèi)用于接口回調(diào),匿名內(nèi)部類(lèi)在編譯的時(shí)候由系統(tǒng)自動(dòng)起名為 OutClass$1.class,一般匿名內(nèi)部類(lèi)用于繼承其他類(lèi)或?qū)崿F(xiàn)接口且不需要增加額外方法的場(chǎng)景(只是對(duì)繼承方法的實(shí)現(xiàn)或是重寫(xiě));匿名內(nèi)部類(lèi)的 class 前面不能有 pravite 等修飾符和 static 修飾符;匿名內(nèi)部類(lèi)訪問(wèn)外部類(lèi)的成員屬性時(shí)外部類(lèi)的成員屬性需要添加 final 修飾(1.8 開(kāi)始可以不用)。

問(wèn):下面說(shuō)法哪些不正確,為什么?
內(nèi)部類(lèi)不能有自己的成員方法和成員變量。

內(nèi)部類(lèi)可用 abstract 修飾符定義為抽象類(lèi),也可以用 private 或 protected 定義。

內(nèi)部類(lèi)可作為其他類(lèi)的成員,而且可以訪問(wèn)它所在類(lèi)的成員。

除 static 內(nèi)部類(lèi)外,不能直接在內(nèi)部類(lèi)中聲明 static 成員(static 常量除外)。

答:A 的描述是錯(cuò)誤的,其他都正確。
因?yàn)閮?nèi)部類(lèi)是指在一個(gè)類(lèi)的內(nèi)部嵌套定義的類(lèi),與普通類(lèi)一樣具有自己的成員方法和成員變量,成員和方法是類(lèi)存在且有意義的基礎(chǔ)。

問(wèn):下面的內(nèi)部類(lèi)哪些是正確的,哪些是錯(cuò)誤的?
        public class OutClass {
            class InnerClass1 {
                public static int func() {
                    return 1;
                }
            }

            public class InnerClass2 {
                static int func() {
                    return 1;
                }
            }

            private class InnerClass3 {
                int func() {
                    return 1;
                }
            }

            static class InnerClass4 {
                protected int func() {
                    return 1;
                }
            }

            abstract class InnerClass5 {
                public abstract int func();
            }
        }

答:由于靜態(tài)內(nèi)部類(lèi)可以有靜態(tài)成員或者靜態(tài)方法,而非靜態(tài)內(nèi)部類(lèi)不能有靜態(tài)成員或者靜態(tài)方法,所以 InnerClass1、InnerClass2 是錯(cuò)的。其他 InnerClass3、InnerClass4、InnerClass5 都是正確的,解釋如第一題答案。

問(wèn):Java 中為什么成員內(nèi)部類(lèi)可以直接訪問(wèn)外部類(lèi)的成員?

答:成員內(nèi)部類(lèi)可以無(wú)條件訪問(wèn)外部類(lèi)的成員或者方法的原因解釋我們可以通過(guò)下面例子來(lái)說(shuō)明。

        public class OutClass {
            public class InnerClass {
            }
        }

我們執(zhí)行命令 javac OutClass.java 編譯會(huì)發(fā)現(xiàn)得到兩個(gè) class 文件,分別為 OutClass.class 和 OutClass$InnerClass.class,所以編譯器在進(jìn)行編譯的時(shí)候會(huì)把成員內(nèi)部類(lèi)單獨(dú)編譯成一個(gè)字節(jié)碼文件,我們接著通過(guò) javap [-v] OutClass$InnerClass 看下編譯后的成員內(nèi)部類(lèi)的字節(jié)碼,如下:

        Compiled from "OutClass.java" public class OutClass$InnerClass {
            final OutClass this $0;

            public OutClass$InnerClass(OutClass);
        }

可以看到編譯后的成員內(nèi)部類(lèi)中有一個(gè)指向外部類(lèi)對(duì)象的引用,且成員內(nèi)部類(lèi)編譯后構(gòu)造方法也多了一個(gè)指向外部類(lèi)對(duì)象的引用參數(shù),所以說(shuō)編譯器會(huì)默認(rèn)為成員內(nèi)部類(lèi)添加了一個(gè)指向外部類(lèi)對(duì)象的引用并且在成員內(nèi)部類(lèi)構(gòu)造方法中對(duì)其進(jìn)行賦值操作,因此我們可以在成員內(nèi)部類(lèi)中隨意訪問(wèn)外部類(lèi)的成員,同時(shí)也說(shuō)明成員內(nèi)部類(lèi)是依賴(lài)于外部類(lèi)的,如果沒(méi)有創(chuàng)建外部類(lèi)的對(duì)象則也無(wú)法創(chuàng)建成員內(nèi)部類(lèi)的對(duì)象。

問(wèn):Java 1.8 之前為什么方法內(nèi)部類(lèi)和匿名內(nèi)部類(lèi)訪問(wèn)局部變量和形參時(shí)必須加 final?

答:在 Java 1.8 以下因?yàn)閷?duì)于普通局部變量或者形參的作用域是方法內(nèi),當(dāng)方法結(jié)束時(shí)局部變量或者形參就要隨之消失,而其匿名內(nèi)部類(lèi)或者方法內(nèi)部類(lèi)的生命周期又沒(méi)結(jié)束,匿名內(nèi)部類(lèi)或者方法內(nèi)部類(lèi)如果想繼續(xù)使用方法的局部變量就需要一些手段,所以 Java 在編譯匿名內(nèi)部類(lèi)或者方法內(nèi)部類(lèi)時(shí)就有一個(gè)規(guī)定來(lái)解決生命周期問(wèn)題,即如果訪問(wèn)的外部類(lèi)方法的局部變量值在編譯期能確定則直接在匿名內(nèi)部類(lèi)或者方法內(nèi)部類(lèi)里面創(chuàng)建一個(gè)常量拷貝,如果訪問(wèn)的外部類(lèi)方法的局部變量值無(wú)法在編譯期確定則通過(guò)構(gòu)造器傳參的方式來(lái)對(duì)拷貝進(jìn)行初始化賦值。由此說(shuō)明在匿名內(nèi)部類(lèi)或者方法內(nèi)部類(lèi)中訪問(wèn)的外部類(lèi)方法的局部變量或者形參是內(nèi)部類(lèi)自己的一份拷貝,和外部類(lèi)方法的局部變量或者形參不是一份,所以如果在匿名內(nèi)部類(lèi)或者方法內(nèi)部類(lèi)對(duì)變量做修改操作就一定會(huì)導(dǎo)致數(shù)據(jù)不一致性(外部類(lèi)方法的參數(shù)不會(huì)跟著被修改,引用類(lèi)型僅是引用,值修改不存在問(wèn)題),為了杜絕數(shù)據(jù)不一致性導(dǎo)致的問(wèn)題 Java 就要求使用 final 來(lái)保證,所以必須是 final 的。在 Java 1.8 開(kāi)始我們可以不加 final 修飾符了,系統(tǒng)會(huì)默認(rèn)添加,Java 將這個(gè)功能稱(chēng)為 Effectively final。

上面這段話可以通過(guò)下面的例子說(shuō)明(對(duì)于非 final 無(wú)法編譯通過(guò),所以不再舉例),如下:

        public class OutClass {
            private int out = 1;

            public void func(final int param) {
                final int in = 2;
                new Thread() {
                    @Override
                    public void run() {
                        out = param;
                        out = in;
                    }
                }.start();
            }
        }

上面類(lèi)文件在 java 1.8 以下通過(guò) javac 編譯后執(zhí)行 javap -l -v OutClass$1.class 查看匿名內(nèi)部類(lèi)的字節(jié)碼可以發(fā)現(xiàn)如下情況:

......
class OutClass$1 extends java.lang.Thread
......
{
  
//匿名內(nèi)部類(lèi)有了自己的 param 屬性成員。
  
final int val$param;
  
......
  
//匿名內(nèi)部類(lèi)持有了外部類(lèi)的引用作為一個(gè)屬性成員。
  
final OutClass this $0;
  
......
  
//匿名內(nèi)部類(lèi)編譯后構(gòu)造方法自動(dòng)多了兩個(gè)參數(shù),一個(gè)為外部類(lèi)引用,一個(gè)為 param 參數(shù)。
  
OutClass$1(OutClass, int);
    
......
  
public void run();
    
......
    
Code:
      stack=2, locals=, args_size=1
           
//out = param;語(yǔ)句,將匿名內(nèi)部類(lèi)自己的 param 屬性賦值給外部類(lèi)的成員 out。
         
0: aload_0
         
1: getfield      #1    // Field this$0:LOutClass;
4: aload_0
         
5: getfield      #2    // Field val$param:I
         
8: invokestatic  #4    // Method OutClass.access$002:(LOutClass;I)I
        
11: pop        //out = in;語(yǔ)句,將匿名內(nèi)部類(lèi)常量 2 (in在編譯時(shí)確定值)賦值給外部類(lèi)的成員 out。
        
12: aload_0
        
13: getfield      #1    // Field this$0:LOutClass;
        
//將操作數(shù)2壓棧,因?yàn)槿绻@個(gè)變量的值在編譯期間可以確定則編譯器默認(rèn)會(huì)在
        
//匿名內(nèi)部類(lèi)或方法內(nèi)部類(lèi)的常量池中添加一個(gè)內(nèi)容相等的字面量或直接將相應(yīng)的
        
//字節(jié)碼嵌入到執(zhí)行字節(jié)碼中。
        
16: iconst_2
        
17: invokestatic  #4    // Method OutClass.access$002:(LOutClass;I)I
        
20: pop
       
21: return
      
......
}
......

通過(guò)字節(jié)碼指令我想不用再多解釋了吧,上面字節(jié)碼包含了訪問(wèn)局部變量編譯時(shí)可確定值和不可確定值的兩種情況,自己可以再琢磨下。

問(wèn):下面關(guān)于成員內(nèi)部類(lèi) InnerClass 的子類(lèi)實(shí)現(xiàn) ChildInnerClassX 中哪些是可以編譯運(yùn)行的?
        class OutClass {
            class InnerClass {
            }
        }
        class ChildInnerClass1 extends OutClass.InnerClass {
        }
        class ChildInnerClass2 extends OutClass.InnerClass {
            public ChildInnerClass2() {
                super();
            }
        }
        class ChildInnerClass3 extends OutClass.InnerClass {
            public ChildInnerClass3(OutClass outClass) {
                super();
            }
        }
        class ChildInnerClass4 extends OutClass.InnerClass {
            public ChildInnerClass3(OutClass outClass) {
                outClass.super();
            }
        }

答:只有 ChildInnerClass4 子類(lèi)是可以編譯運(yùn)行的,其他都無(wú)法編譯通過(guò)。(雖然開(kāi)發(fā)中很少會(huì)遇到這種)因?yàn)槌蓡T內(nèi)部類(lèi)的繼承語(yǔ)法格式要求繼承引用方式為 Outter.Inner 形式且繼承類(lèi)的構(gòu)造器中必須有指向外部類(lèi)對(duì)象的引用,并通過(guò)這個(gè)引用調(diào)用 super(),其實(shí)這個(gè)要求就是因?yàn)槌蓡T內(nèi)部類(lèi)默認(rèn)持有外部類(lèi)的引用,外部類(lèi)不先實(shí)例化則無(wú)法實(shí)例化自己。

問(wèn):下面程序的運(yùn)行結(jié)果是什么?為什么?
        List list1 = new ArrayList();
        List list2 = new ArrayList() {
        };
        List list3 = new ArrayList() {{
        }};
        List list4 = new ArrayList() {
            {
            }

            {
            }

            {
            }
        };
        //1 
        System.out.println(list1.getClass() == list2.getClass());
        // 2 
        System.out.println(list1.getClass() == list3.getClass());
        // 3
        System.out.println(list1.getClass() == list4.getClass());
        // 4 
        System.out.println(list2.getClass() == list3.getClass());
        // 5 
        System.out.println(list2.getClass() == list4.getClass());
        // 6 
        System.out.println(list3.getClass() == list4.getClass());

答:程序運(yùn)行返回 6 個(gè) false。
首先 list1 指向一個(gè) ArrayList 對(duì)象實(shí)例;list2 指向一個(gè)繼承自 ArrayList 的匿名類(lèi)內(nèi)部類(lèi)對(duì)象;list3 也指向一個(gè)繼承自 ArrayList 的匿名內(nèi)部類(lèi)(里面一對(duì)括弧為初始化代碼塊)對(duì)象;list4 也指向一個(gè)繼承自 ArrayList 的匿名內(nèi)部類(lèi)(里面多對(duì)括弧為多個(gè)初始化代碼塊)對(duì)象;由于這些匿名內(nèi)部類(lèi)都出現(xiàn)在同一個(gè)類(lèi)中,所以編譯后其實(shí)得到的是 Demo$1、Demo$2、Demo$3 的形式,所以自然都互補(bǔ)相等了,不信你可以通過(guò) listX.getClass().getName() 進(jìn)行驗(yàn)證。

問(wèn):開(kāi)發(fā)中使用 Java 匿名內(nèi)部類(lèi)有哪些注意事項(xiàng)(經(jīng)驗(yàn))?

答:常見(jiàn)的注意事項(xiàng)如下。
使用匿名內(nèi)部類(lèi)時(shí)必須是繼承一個(gè)類(lèi)或?qū)崿F(xiàn)一個(gè)接口(二者不可兼得且只能繼承一個(gè)類(lèi)或者實(shí)現(xiàn)一個(gè)接口)。
匿名內(nèi)部類(lèi)中是不能定義構(gòu)造函數(shù)的,如需初始化可以通過(guò)構(gòu)造代碼塊處理。
匿名內(nèi)部類(lèi)中不能存在任何的靜態(tài)成員變量和靜態(tài)方法。
匿名內(nèi)部類(lèi)為局部?jī)?nèi)部類(lèi),所以局部?jī)?nèi)部類(lèi)的所有限制同樣對(duì)匿名內(nèi)部類(lèi)生效。
匿名內(nèi)部類(lèi)不能是抽象類(lèi),必須要實(shí)現(xiàn)繼承的類(lèi)或者實(shí)現(xiàn)接口的所有抽象方法。

問(wèn):Java 匿名內(nèi)部類(lèi)在使用時(shí)如何初始化嗎?

答:匿名內(nèi)部類(lèi)無(wú)法通過(guò)構(gòu)造方法初始化,所以我們只能通過(guò)構(gòu)造代碼塊進(jìn)行初始化。

問(wèn):非靜態(tài)內(nèi)部類(lèi)里面為什么不能有靜態(tài)屬性和靜態(tài)方法?

答:static 類(lèi)型的屬性和方法在類(lèi)加載的時(shí)候就會(huì)存在于內(nèi)存中,要使用某個(gè)類(lèi)的 static 屬性或者方法的前提是這個(gè)類(lèi)已經(jīng)加載到 JVM 中,非 static 內(nèi)部類(lèi)默認(rèn)是持有外部類(lèi)的引用且依賴(lài)外部類(lèi)存在,所以如果一個(gè)非 static 的內(nèi)部類(lèi)一旦具有 static 的屬性或者方法就會(huì)出現(xiàn)內(nèi)部類(lèi)未加載時(shí)卻試圖在內(nèi)存中創(chuàng)建內(nèi)部類(lèi)的 static 屬性和方法,這自然是錯(cuò)誤的,類(lèi)都不存在(沒(méi)被加載)卻希望操作它的屬性和方法。從另一個(gè)角度講非 static 的內(nèi)部類(lèi)在實(shí)例化的時(shí)候才會(huì)加載(不自動(dòng)跟隨主類(lèi)加載),而 static 的語(yǔ)義是類(lèi)能直接通過(guò)類(lèi)名來(lái)訪問(wèn)類(lèi)的 static 屬性或者方法,所以如果沒(méi)有實(shí)例化非 static 的內(nèi)部類(lèi)就等于非 static 的內(nèi)部類(lèi)沒(méi)有被加載,所以無(wú)從談起通過(guò)類(lèi)名訪問(wèn) static 屬性或者方法。

問(wèn):Java 匿名內(nèi)部類(lèi)為什么不能直接使用構(gòu)造方法,匿名內(nèi)部類(lèi)有沒(méi)有構(gòu)造方法?

答:因?yàn)轭?lèi)是匿名的(相當(dāng)于沒(méi)有名字),而且每次創(chuàng)建的匿名內(nèi)部類(lèi)同時(shí)被實(shí)例化后只能使用一次,所以就無(wú)從創(chuàng)建一個(gè)同名的構(gòu)造方法了,但是可以直接調(diào)用父類(lèi)的構(gòu)造方法(譬如 new InnerClass(xxx, xxx) {})。

實(shí)質(zhì)上匿名內(nèi)部類(lèi)是有構(gòu)造方法的,是通過(guò)編譯器在編譯時(shí)幫忙生成的,如下代碼:

        class InnerClass {
        }
        public class OutClass {
            InnerClass clazz = new InnerClass() {
            };
        }

通過(guò)編譯后生成了 InnerClass.class、OutClass$1.class、OutClass.class,可以看見(jiàn) OutClass$1.class 就是我們匿名內(nèi)部類(lèi)的字節(jié)碼名字,我們通過(guò) javap -v OutClass$1.class 可以看到如下:

......
{
  
final OutClass this$0;
  
......
  
OutClass$1(OutClass);
    descriptor: (LOutClass;)
    flags:
    Code:
      stack=2, locals=2, args_size=2 
0: aload_0
         
1: aload_1
         
2: putfield      #1      // Field this$0:LOutClass;
         
5: aload_0
         
6: invokespecial #2      // Method InnerClass."<init>":()V
         
9: return    
LineNumberTable:        
        line 8: 0
}
......

可以很明顯看到內(nèi)部類(lèi)的字節(jié)碼中編譯器為我們生成了參數(shù)為外部類(lèi)引用的構(gòu)造方法,其構(gòu)造方法和普通類(lèi)的構(gòu)造方法沒(méi)有區(qū)別,都是執(zhí)行 <init> 方式。

問(wèn):Java 中非靜態(tài)內(nèi)部類(lèi)和靜態(tài)內(nèi)部類(lèi)有什么區(qū)別?

答:常見(jiàn)的區(qū)別如下。
非靜態(tài)內(nèi)部類(lèi)默認(rèn)持有外部類(lèi)的引用,靜態(tài)內(nèi)部類(lèi)不存在該特性。
非靜態(tài)內(nèi)部類(lèi)中不能定義靜態(tài)成員或者方法,靜態(tài)內(nèi)部類(lèi)中可以隨便定義。
非靜態(tài)內(nèi)部類(lèi)可以直接訪問(wèn)外部類(lèi)的成員變量或者方法,靜態(tài)內(nèi)部類(lèi)只能直接訪問(wèn)外部類(lèi)的靜態(tài)成員或者方法(實(shí)質(zhì)是持有外部類(lèi)名)。
非靜態(tài)內(nèi)部類(lèi)可以定義在外部類(lèi)的任何位置(方法里外均可,在方法外面定義的內(nèi)部類(lèi)的 class 訪問(wèn)類(lèi)型可以是 public、protected 等,方法里的只能是默認(rèn) class,類(lèi)似局部變量),靜態(tài)內(nèi)部類(lèi)只能定義在外部類(lèi)中最外層,class 修飾符可以是 public、protected 等。
非靜態(tài)內(nèi)部類(lèi)創(chuàng)建實(shí)例時(shí)必須先創(chuàng)建外部類(lèi)實(shí)例,靜態(tài)內(nèi)部類(lèi)不依賴(lài)外部類(lèi)實(shí)例。
靜態(tài)方法中定義的內(nèi)部類(lèi)是靜態(tài)內(nèi)部類(lèi)(這時(shí)不能在類(lèi)前面加 static 關(guān)鍵字),靜態(tài)方法中的靜態(tài)內(nèi)部類(lèi)與普通方法中的內(nèi)部類(lèi)使用類(lèi)似,除了可以直接訪問(wèn)外部類(lèi)的 static 成員變量或者方法外還可以訪問(wèn)靜態(tài)方法中的局部變量(java 1.8 以前局部變量前必須加 final 修飾符)。

問(wèn):Java 中內(nèi)部類(lèi)有什么好處(即 Java 的內(nèi)部類(lèi)有什么作用)?

答:具體好處如下。

  1. 內(nèi)部類(lèi)可以很好的實(shí)現(xiàn)隱蔽,一般的非內(nèi)部類(lèi),是不允許有 private 與 protected 等權(quán)限的,但內(nèi)部類(lèi)(除過(guò)方法內(nèi)部類(lèi))可以通過(guò)這些修飾符來(lái)實(shí)現(xiàn)隱藏。

  2. 內(nèi)部類(lèi)擁有外部類(lèi)的的訪問(wèn)權(quán)限(分靜態(tài)非靜態(tài)情況),通過(guò)這一特性可以比較好的處理類(lèi)之間的關(guān)聯(lián)性,將一類(lèi)事物的流程放在一起內(nèi)部處理。

  3. 通過(guò)內(nèi)部類(lèi)可以實(shí)現(xiàn)多重繼承,java 默認(rèn)是單繼承,我們可以通過(guò)多個(gè)內(nèi)部類(lèi)繼承實(shí)現(xiàn)多個(gè)父類(lèi),接著由于外部類(lèi)完全可訪問(wèn)內(nèi)部類(lèi),所以就實(shí)現(xiàn)了類(lèi)似多繼承的效果。

  4. 通過(guò)內(nèi)部類(lèi)可以避免修改接口而實(shí)現(xiàn)同一個(gè)類(lèi)中兩種同名方法的調(diào)用(譬如你的類(lèi) A 中有一個(gè)參數(shù)為 int 的 func 方法,現(xiàn)在類(lèi) A 需要繼承實(shí)現(xiàn)一個(gè)接口 B,而接口 B 中也有一個(gè)參數(shù)為 int 的 func 方法,此時(shí)如果直接繼承實(shí)現(xiàn)就會(huì)出現(xiàn)同名方法矛盾問(wèn)題,這時(shí)候如果不允許修改 A、B 類(lèi)的 func 方法名則可以通過(guò)內(nèi)部類(lèi)來(lái)實(shí)現(xiàn) B 接口,因?yàn)閮?nèi)部類(lèi)對(duì)外部類(lèi)來(lái)說(shuō)是完全可訪問(wèn)的)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評(píng)論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,634評(píng)論 3 419
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,653評(píng)論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,063評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,835評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,235評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,459評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,000評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,819評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,004評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,257評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,676評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,937評(píng)論 1 288
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,717評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,003評(píng)論 2 374