簡體   English   中英

為什么我不能把enum的內部課程公開?

[英]Why cant I make an enum's inner class public?

測試了一些東西我嘗試做一個枚舉,其中枚舉中的每個元素都有一個不同的類。

舉個例子:

public enum MyEnum {

    first{
        class First{}
    },
    second {
        class Second{}
    };
}

如果我嘗試在任何類之前放置一個公共修飾符,則此處不允許使用修飾符。 我不太清楚為什么會這樣。 我不能在枚舉之外實例化這些類,也不能看到它們。 但是我可以設法讓實例這樣做:

public enum MyEnum {

    first{
        class First{}

        public Object getObject(){
            return new First();
        }
    },
    second {
        class Second{}

        public Object getObject(){
            return new Second();
        }
    };

    public abstract Object getObject();
}


public class Main {
    public static void main(String[] args) {
        System.out.println(MyEnum.first.getObject().getClass());
        System.out.println(MyEnum.second.getObject().getClass());
    }
}

隨着輸出:

class MyEnum $ 1 $ First

class MyEnum $ 2 $秒

我可以清楚地引用這個類,為什么我不能在編譯時訪問它?

這是一個非常有趣的問題。 即使允許使用public修飾符,您也無法在編譯時訪問這些類,因為它們包含在隱式匿名類中,因此無論如何它們都無法通過名稱訪問(除了在匿名類中)。 您無法通過變量訪問類型,即訪問MyEnum.first.First根本不可能在Java中訪問。

但是,沒有用處並不一定決定可以聲明什么,即在private外部類中聲明public內部類也是可能的。 正式規則是相關的,雖然它看起來像乍看之下的預期行為,但令人驚訝的是,它沒有以這種方式得到規范的支持。

JLS§8.9.1,Enum Constants聲明:

枚舉常量的可選類體隱式定義了一個匿名類聲明(第15.9.5節 ),該聲明擴展了直接封閉的枚舉類型。 班級機構由匿名班級的通常規則管理......

這給了我們一個有趣的提示,即

class Outer {
    static Object o = new Object() {
        public class Inner {
        }
    };
}

被編譯器拒絕。

考慮JLS,§8.1.1。 類修飾符

訪問修飾符public (第6.6節 )僅適用於頂級類(第7.6節 )和成員類(第8.5節 ),不適用於本地類( 第14.3節 )或匿名類(第15.9.5節 )。

我們必須決定Inner或您的First Class屬於哪個類別。 這並不是因為他們周圍的班級是一個匿名班級。 顯然,它們既不是頂級類也不是匿名類,因為它們是嵌套的並且具有名稱。 因此,他們必須是成員類( public允許)或本地類( public不允許)。

JLS,§8.5。 會員類型聲明

成員類是一個類,其聲明直接包含在另一個類或接口聲明的主體中(第8.1.6節 ,第9.1.4節 )。

“另一個類......聲明的主體”是通過指向§8.1.6來定義的,它實際上定義了ClassBody語言語法,它通常由命名聲明匿名類enum常量體使用 ; 所有這些都指向§8.1.6的“階級主體”。 考慮到這一點,我們的類是“成員類”,因為它們包含在類體中。

現在我們可以嘗試將其解釋為錯誤的交叉引用,假設“另一個類的主體...... 聲明 ”是指類聲明 ,即使用class關鍵字命名的類聲明,但是,有本地類的定義,反駁這種解釋。

JLS§14.3,本地類

局部類是一個嵌套類( §8(類) ),其是不屬於任何類的成員,並且具有名稱( §6.2§6.7 )。

...

每個本地類聲明語句都立即被一個塊包含(第14.2節 )。 本地類聲明語句可以與塊中的其他類型的語句自由混合。

“塊”實際上意味着塊類似於非abstract方法,構造函數或初始化器(第14.2節 )的定義。 這不適用於上面的Inner課程或您的FirstSecond課程。 它們不是放在一個塊中,也不能與該上下文中的語句自由混合,因為此時不允許聲明。

換句話說,它們絕對不是本地類,並且假設沒有規范沒有描述的另一類類,我們必須將它們視為成員類 ,因為成員類的定義的當前編寫和鏈接也表明,換句話說, 根據引用的規則,應該允許在這個地方使用public修飾符

為了完整起見,這里是匿名類的定義,只是為了表明沒有例外規則說他們的成員類不允許public

15.9.5。 匿名類聲明

Java編譯器自動從類實例創建表達式派生匿名類聲明。

匿名類永遠不是abstract (第8.1.1.1節)。

匿名類總是隱式final (§8.1.1.2)。

匿名類始終是內部類(第8.1.3節); 它永遠不會是static (§8.1.1,§8.5.1)。

最后一點暗示,反過來,他們的成員類也不能是static ,但是,沒有規則禁止他們public

你正在使用當前的方法MyEnum{}語法創建一個匿名子類),它起作用但看起來過於復雜。 你有什么相當於像,

public enum MyEnum {
    first, second; // <-- convention would be FIRST, SECOND
    public static class First { // <-- can be public.
    }
    public static class Second {
    }
    public Object getObject() {
        if (this == first) {
            return new First();
        }
        return new Second();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM