Java 将CharBuffer和StringBuilder转换为superinterface

Java 将CharBuffer和StringBuilder转换为superinterface,java,stringbuilder,charsequence,Java,Stringbuilder,Charsequence,StringBuilder和CharBuffer都实现CharSequence和Appendable接口。 在声明超级接口时 public interface IAppendableCharSequence extends CharSequence, Appendable{} 然后我可以将CharBuffer强制转换为IAppendableCharSequence,但不能转换为StringBuilder: private IAppendableCharSequence m_buffer;

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

为什么呢?谢谢

这两种方法在运行时都不起作用,但编译器允许其中一种而不允许另一种的原因是
StringBuilder
final
CharBuffer
不是

编译器肯定知道,作为StringBuilder的
实例的任何东西都不能是
IAppendableCharSequence
的有效实现,因为
StringBuilder
本身不实现该接口,并且作为
final
它不能有子类。因此,在任何情况下,强制转换都不可能是合法的,编译器会拒绝它

CharBuffer
的情况下,编译器没有这种保证,因为您可能会创建
CharBuffer
的自定义子类,该子类实现
IAppendableCharSequence

编译器允许哪些类型转换而哪些不允许的规则在Java语言规范中,在本例中(缩小引用转换),其中包括允许转换的规则

从任何类类型
C
到任何非参数化接口类型
K
,前提是
C
不是
final
且不实现
K


也就是说,如果类不是最终类,则从任何类类型转换到该类未实现的任何接口类型都是有效的。

这两种转换在运行时都不会实际工作,但编译器允许其中一种而不允许另一种的原因是
StringBuilder
final
CharBuffer
不是

编译器肯定知道,作为StringBuilder的
实例的任何东西都不能是
IAppendableCharSequence
的有效实现,因为
StringBuilder
本身不实现该接口,并且作为
final
它不能有子类。因此,在任何情况下,强制转换都不可能是合法的,编译器会拒绝它

CharBuffer
的情况下,编译器没有这种保证,因为您可能会创建
CharBuffer
的自定义子类,该子类实现
IAppendableCharSequence

编译器允许哪些类型转换而哪些不允许的规则在Java语言规范中,在本例中(缩小引用转换),其中包括允许转换的规则

从任何类类型
C
到任何非参数化接口类型
K
,前提是
C
不是
final
且不实现
K


即,如果该类不是最终类,则从任何类类型转换为该类未实现的任何接口类型是有效的。

@Ian Roberts是正确的

谜题的另一部分是Java类型系统将
IAppendableCharSequence
视为不仅仅是
CharSequence
appendeable
。实际上,它本身就是一个类型,可以有相关的语义。。。这样,既是
字符序列
又是
可追加的
的“任何旧类”都不符合条件

这意味着下面的
CharBuffer
StringBuilder
是一个
IAppendableCharSequence
,即使它们都实现了
CharSequence
appendeable
接口


java接口更多的是C或C++别名,即使它们只扩展其他接口…

@阿兰·罗伯茨是正确的。< /P> 谜题的另一部分是Java类型系统将
IAppendableCharSequence
视为不仅仅是
CharSequence
appendeable
。实际上,它本身就是一个类型,可以有相关的语义。。。这样,既是
字符序列
又是
可追加的
的“任何旧类”都不符合条件

这意味着下面的
CharBuffer
StringBuilder
是一个
IAppendableCharSequence
,即使它们都实现了
CharSequence
appendeable
接口

java接口更多的是C或C++别名,即使它们只扩展其他接口…

我可以将CharBuffer强制转换为IAppendableCharSequence

事实上你不能。只能将类的实例强制转换为该类有意实现的类型。CharBuffer实现Appendable和CharSequence并不意味着它实现了IAppendableCharSequence接口

编译器允许强制转换,因为它无法判断CharBuffer.allocate(512)
将返回什么。据编译器所知,它可以返回CharBuffer的子类,该子类确实显式实现了IAppendableCharSequence。但是,如果对象没有真正实现该接口,则cast将在运行时抛出ClassCastException

然而,
newstringbuilder(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;
        }
    };
}
您还可以使用实现CharSequence和Appendable的任何其他方法调用它

我可以将CharBuffer强制转换为IAppendableCharSequence

事实上你不能。只能将类的实例强制转换为该类有意实现的类型。CharBuffer实现Appendable和CharSequence并不意味着它实现了IAppendableCharSequence接口

编译器允许强制转换,因为它无法判断
CharBuffer.allocate将返回什么
m_buffer = wrap(CharBuffer.allocate(512));
m_buffer = wrap(new StringBuilder(512));