Java 在列表中添加false类型时没有异常

Java 在列表中添加false类型时没有异常,java,generics,Java,Generics,在将类类型添加到列表中的过程中,我发现了一个奇怪的行为 我有一个列表,其中包含抽象类列表myImplementations的所有实现类。我添加了一个非派生类的类型,没有错误。有人能解释一下为什么我可以像MyImplements.addSomeOtherClass.class这样做吗;毫无例外?第二个泛型类型MyAbstractClass似乎根本没有效果 --编辑-- public abstract class MyAbstractClass{ public static String get

在将类类型添加到列表中的过程中,我发现了一个奇怪的行为

我有一个列表,其中包含抽象类列表myImplementations的所有实现类。我添加了一个非派生类的类型,没有错误。有人能解释一下为什么我可以像MyImplements.addSomeOtherClass.class这样做吗;毫无例外?第二个泛型类型MyAbstractClass似乎根本没有效果

--编辑--

public abstract class MyAbstractClass{
  public static String getMyIdentification(){ throw new RuntimeException("implement method");}
}

public class MyImplementation extends MyAbstractClass{
  public static String getMyIdentification(){ return "SomeUUID";}
}

public class OtherClass{}

// in another class:
List<Class<MyAbstractClass>> myImplementations = new ArrayList<Class<MyAbstractClass>>();
myImplementations.add(MyImplementation.class); // does not cause any error
myImplementations.add(OtherClass.class); // does not cause any error, but should in my opinion??
--编辑结束--

谢谢,,
el

该类型在编译期间被擦除,因此在运行时不会看到任何异常。编译器应该对您的情况进行投诉或发出警告

List<Class<String>> list = new ArrayList<Class<String>>();
list.add(Integer.class);                      // should create a compiletime error
list.add(Class.forName("java.lang.Integer")); // should create a warning
                                              // and run due to type erasure

类型参数类在编译过程中被删除-它仅由编译器用于检查java源代码是否有效。编译后的字节码不再包含此信息,在字节码级别,列表将保存并接受Object或Object的任何子类。由于Integer.class是Object的一个子类,因此代码将一直运行,直到运行时向程序员抛出ClassCastException,因为它需要类实例。

编译过程中会删除该类型,因此在运行时不会看到任何异常。编译器应该对您的情况进行投诉或发出警告

List<Class<String>> list = new ArrayList<Class<String>>();
list.add(Integer.class);                      // should create a compiletime error
list.add(Class.forName("java.lang.Integer")); // should create a warning
                                              // and run due to type erasure

类型参数类在编译过程中被删除-它仅由编译器用于检查java源代码是否有效。编译后的字节码不再包含此信息,在字节码级别,列表将保存并接受Object或Object的任何子类。由于Integer.class是Object的一个子类,因此代码将一直运行,直到运行时向程序员抛出ClassCastException,因为它需要类实例。

使用eclipse编译器,这与预期一样:

List<Class<? extends CharSequence>> myImplementations = 
    new ArrayList<Class<? extends CharSequence>>();
myImplementations.add(String.class);
myImplementations.add(Vector.class);
i、 e.编译器只对第二次添加进行投诉。但是,如果它通过编译,列表将转换为原始列表,并且在从列表中获取元素之前不会出现异常,例如,使用foreach循环


没有这个?扩展编译失败,即使是字符串。应该是这样的。我很惊讶您没有任何错误,因为java泛型是不变的——也就是说,您不能将子类实例添加到列表中。

使用eclipse编译器,这将按预期进行:

List<Class<? extends CharSequence>> myImplementations = 
    new ArrayList<Class<? extends CharSequence>>();
myImplementations.add(String.class);
myImplementations.add(Vector.class);
i、 e.编译器只对第二次添加进行投诉。但是,如果它通过编译,列表将转换为原始列表,并且在从列表中获取元素之前不会出现异常,例如,使用foreach循环

没有这个?扩展编译失败,即使是字符串。应该是这样的。我很惊讶您没有任何错误,因为java泛型是不变的——也就是说,您不能将子类实例添加到列表中。

关于类型擦除 Java的泛型是非具体化的。列表和列表在编译时是不同的类型,但这两种类型在运行时都会被删除,以简单地列出。这意味着,通过绕过编译时检查,可以在运行时将整数插入列表中,这本身可能不会生成ClassCastException。下面是一个例子:

List<String> names = new ArrayList<String>();
List raw = names; // generates compiler warning about raw type!

raw.add((Integer) 42); // does not throw ClassCastException! (yet!)

// but here comes trouble!
for (String s : names) {
    // Exception in thread "main" java.lang.ClassCastException:
    //    java.lang.Integer cannot be cast to java.lang.String
}
可临时替换为以下内容:

    Collection<String> c = Collections.checkedCollection(
         new HashSet<String>(), String.class);
现在我们有:

List<Class<?>> list = new ArrayList<Class<?>>();

add(list, CharSequence.class, String.class);         // OK!
add(list, CharSequence.class, StringBuffer.class);   // OK!
add(list, CharSequence.class, StringBuilder.class);  // OK!

add(list, CharSequence.class, Integer.class);        // NOT OK!
// throws IllegalArgumentException:
// java.lang.CharSequence is not assignable from java.lang.Integer
关于类型擦除 Java的泛型是非具体化的。列表和列表在编译时是不同的类型,但这两种类型在运行时都会被删除,以简单地列出。这意味着,通过绕过编译时检查,可以在运行时将整数插入列表中,这本身可能不会生成ClassCastException。下面是一个例子:

List<String> names = new ArrayList<String>();
List raw = names; // generates compiler warning about raw type!

raw.add((Integer) 42); // does not throw ClassCastException! (yet!)

// but here comes trouble!
for (String s : names) {
    // Exception in thread "main" java.lang.ClassCastException:
    //    java.lang.Integer cannot be cast to java.lang.String
}
可临时替换为以下内容:

    Collection<String> c = Collections.checkedCollection(
         new HashSet<String>(), String.class);
现在我们有:

List<Class<?>> list = new ArrayList<Class<?>>();

add(list, CharSequence.class, String.class);         // OK!
add(list, CharSequence.class, StringBuffer.class);   // OK!
add(list, CharSequence.class, StringBuilder.class);  // OK!

add(list, CharSequence.class, Integer.class);        // NOT OK!
// throws IllegalArgumentException:
// java.lang.CharSequence is not assignable from java.lang.Integer

你能发布你的代码吗?给定的代码足以解决这个问题。您只需初始化列表“myImplementations”。@elCapitano它不是-请参阅我的答案。@Bozho:对于这个问题,代码已经足够了-对于解决方案不是:-@elCapitano-它还不够。你可以从答案中看出,我们必须猜测是什么导致了你的问题。你能发布你的代码吗?给定的代码足以构造问题。您只需初始化列表“myImplementations”。@elCapitano它不是-请参阅我的答案。@Bozho:对于这个问题,代码已经足够了-对于解决方案不是:-@elCapitano-它还不够。你可以从答案中看出,我们必须猜测是什么导致了你的问题。是的!这对我来说是一个解决方案,但不能解释为什么第二种类型没有效果。无论如何谢谢你!我怀疑他已经关闭了那些讨厌的不安全转换等警告信息。除非你知道你正在做的是一项非常明智的政策,否则不要触摸默认值:是的!这对我来说是一个解决方案,但不能解释为什么第二种类型没有效果。无论如何谢谢你!我怀疑他关闭了那些讨厌的不安全转换等警告信息。除非你知道你正在做的是一项非常明智的政策,否则不要触摸默认值: