簡體   English   中英

將CharBuffer和StringBuilder轉換為超級接口

[英]Casting CharBuffer and StringBuilder to superinterface

StringBuilder和CharBuffer都實現CharSequence和Appendable接口。 聲明超級接口時

 public  interface IAppendableCharSequence extends CharSequence, Appendable{}

然后我可以將CharBuffer轉換為IAppendableCharSequence,但不能轉換為StringBuilder:

 private IAppendableCharSequence m_buffer;

 // ...

 m_buffer = (IAppendableCharSequence) CharBuffer.allocate(512); // ok


 m_buffer = (IAppendableCharSequence) new StringBuilder(512); // Cannot cast from StringBuilder to IAppendableCharSequence

這是為什么? 謝謝!

這些都不在運行時實際起作用,但是編譯器允許一個而不允許另一個的原因是StringBuilderfinalCharBuffer不是。

編譯器可以肯定地知道,作為instanceof StringBuilder任何東西都不可能成為IAppendableCharSequence的有效實現,因為StringBuilder本身並不實現該接口,並且final它不能具有IAppendableCharSequence類。 因此,在任何情況下該強制轉換都不會合法,編譯器會拒絕它。

在該情況下CharBuffer編譯器不具有這樣的保證,因為你可以創建一個自定義子類CharBuffer實現IAppendableCharSequence

Java語言規范中不支持強制轉換的規則,在本例中為5.1.6節 (縮小引用轉換),除其他事項外,該規則還允許轉換

從任何類類型C到任何非參數接口類型K ,只要C不是final並且不實現K

即,如果類不是final,則從任何類類型到未由該類實現的任何接口類型的轉換都是有效

我可以將CharBuffer轉換為IAppendableCharSequence

其實你做不到 您只能將類的實例轉換為該類有意實現的類型。 CharBuffer實現Appendable和CharSequence的事實並不意味着它實現了IAppendableCharSequence接口。

編譯器允許進行強制轉換,因為它無法確定CharBuffer.allocate(512)將返回什么。 據編譯器所知,它可以返回確實實現了IAppendableCharSequence的CharBuffer的子類。 但是,如果對象沒有真正實現該接口,則強制轉換將在運行時引發ClassCastException。

new StringBuilder(512)保證新對象是StringBuilder而不是其子類,因此編譯器可以在編譯時看到強制轉換無效。

解決您的問題的一種方法是制作一個可以實現您的接口的通用包裝器:

public static <T extends CharSequence & Appendable> IAppendableCharSequence wrap(T t) {
    if (t == null) throw new NullPointerException();
    final CharSequence csq = t;
    final Appendable a = t;
    return new IAppendableCharSequence() {
        @Override
        public int length() {
            return csq.length();
        }

        @Override
        public char charAt(int index) {
            return csq.charAt(index);
        }

        @Override
        public CharSequence subSequence(int start, int end) {
            return csq.subSequence(start, end);
        }

        @Override
        public Appendable append(CharSequence s) throws IOException {
            a.append(s);
            return this;
        }

        @Override
        public Appendable append(CharSequence s, int start, int end) throws IOException {
            a.append(s, start, end);
            return this;
        }

        @Override
        public Appendable append(char c) throws IOException {
            a.append(c);
            return this;
        }
    };
}

(聲明的csqa變量是不是絕對必要的存在,因為可以調用同一方法t直接,但額外的變量使返回IAppendableCharSequence對象更快一點,避免它需要每次都做演員的一個方法聲明這些變量還會進行早期安全檢查,以確保調用者沒有繞過泛型,否則僅當嘗試使用返回的IAppendableCharSequence時,否則會導致失敗。

一旦有了該方法,就可以執行以下兩項操作:

m_buffer = wrap(CharBuffer.allocate(512));
m_buffer = wrap(new StringBuilder(512));

您還可以使用其他同時實現CharSequence和Appendable的名稱來調用它。

@伊恩·羅伯茨是正確的。

難題的另一部分是Java類型系統將IAppendableCharSequence視為不僅僅是CharSequenceAppendable 實際上,它本身就是一種類型, 可以具有關聯的語義...使得既是CharSequence又是Appendable “任何舊類”都沒有資格。

這意味着,即使CharBufferStringBuilder都實現了CharSequenceAppendable接口,它還是一個 IAppendableCharSequence

Java接口比C或C ++別名更多,即使它們僅擴展其他接口也是如此。

暫無
暫無

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

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