【问题标题】:Explanation of ClassCastException in JavaJava中ClassCastException的解释
【发布时间】:2018-01-03 01:18:44
【问题描述】:

我阅读了一些关于“ClassCastException”的文章,但我无法很好地理解它的含义。什么是 ClassCastException?

【问题讨论】:

    标签: java casting classcastexception


    【解决方案1】:

    直接来自ClassCastException 的 API 规范:

    抛出表示代码有 试图将对象投射到 它不是一个子类 实例。

    因此,例如,当尝试将 Integer 强制转换为 String 时,String 不是 Integer 的子类,因此将抛出 ClassCastException

    Object i = Integer.valueOf(42);
    String s = (String)i;            // ClassCastException thrown here.
    

    【讨论】:

    • 对于任何一种排序,所有项目都必须相互可比(相互可比)。如果不是,则会抛出 ClassCastException。所以,如果 items 没有实现 Comparable 那么Collections.sort() 会抛出这个异常
    【解决方案2】:

    这真的很简单:如果您尝试将 A 类的对象类型转换为 B 类的对象,但它们不兼容,您会得到一个类转换异常。

    让我们考虑一个类的集合。

    class A {...}
    class B extends A {...}
    class C extends A {...}
    
    1. 您可以将任何这些东西强制转换为 Object,因为所有 Java 类都继承自 Object。
    2. 您可以将 B 或 C 转换为 A,因为它们都是 A 的“种类”
    3. 只有当真实对象是 B 时,才能将对 A 对象的引用转换为 B
    4. 您不能将 B 转换为 C,即使它们都是 A。

    【讨论】:

      【解决方案3】:

      你了解铸造的概念吗?强制转换是类型转换的过程,这在 Java 中很常见,因为它是一种静态类型的语言。一些例子:

      通过Integer.parseInt("1") 将字符串"1" 转换为int -> 没问题

      将字符串 "abc" 转换为 int -> 引发 ClassCastException

      或者想一个带有Animal.classDog.classCat.class的类图

      Animal a = new Dog();
      Dog d = (Dog) a; // No problem, the type animal can be casted to a dog, because it's a dog.
      Cat c = (Dog) a; // Will cause a compiler error for type mismatch; you can't cast a dog to a cat.
      

      【讨论】:

      • 有点挑剔,但字符串“1”不能“强制转换”为int,但可以通过Integer.parseInt(String)方法转换为int。
      • 将字符串“1”转换为 int -> 没问题?错了
      • 即使Cat c = (Dog) a 也不会引发ClassCastException,而是编译器错误(类型不匹配
      【解决方案4】:

      您试图将一个对象视为一个类的实例,但它不是。这大致类似于试图按下吉他上的制音踏板(钢琴有制音踏板,吉他没有)。

      【讨论】:

        【解决方案5】:

        如果您尝试向下转换一个类,但实际上该类不是该类型,则会发生异常。

        考虑这个层次结构:

        对象 -> 动物 -> 狗

        你可能有一个方法叫做:

         public void manipulate(Object o) {
             Dog d = (Dog) o;
         }
        

        如果使用此代码调用:

         Animal a = new Animal();
         manipulate(a);
        

        它会编译得很好,但在运行时你会得到一个ClassCastException,因为 o 实际上是一个动物,而不是狗。

        在更高版本的 Java 中,您确实会收到编译器警告,除非您这样做:

         Dog d;
         if(o instanceof Dog) {
             d = (Dog) o;
         } else {
             //what you need to do if not
         }
        

        【讨论】:

        • 不一定沮丧 - 如果 Cat 是 Animal 的子类并且您尝试将其转换为 Dog,您会得到相同的异常
        【解决方案6】:

        当您尝试将一种数据类型的对象转换为另一种数据类型时,Java 会引发类转换异常。

        只要转换发生在兼容的数据类型之间,Java 就允许我们将一种类型的变量转换为另一种类型。

        例如,您可以将字符串转换为对象,类似地,可以将包含字符串值的对象转换为字符串。

        示例

        假设我们有一个包含许多 ArrayList 对象的 HashMap。

        如果我们这样写代码:

        String obj = (String) hmp.get(key);
        

        它会抛出一个类转换异常,因为哈希映射的 get 方法返回的值将是一个数组列表,但我们正试图将它转换为一个字符串。这会导致异常。

        【讨论】:

          【解决方案7】:

          一旦您意识到 JVM 无法猜测未知数,您就可以更好地理解 ClassCastException 和强制转换。如果 B 是 A 的一个实例,它在堆上的类成员和方法比 A 多。JVM 无法猜测如何将 A 强制转换为 B,因为映射目标更大,并且 JVM 将不知道如何填充额外的成员。

          但如果 A 是 B 的一个实例,这是可能的,因为 A 是对 B 的完整实例的引用,所以映射将是一对一的。

          【讨论】:

            【解决方案8】:

            举个例子,

            class Animal {
                public void eat(String str) {
                    System.out.println("Eating for grass");
                }
            }
            
            class Goat extends Animal {
                public void eat(String str) {
                    System.out.println("blank");
                }
            }
            
            class Another extends Goat{
              public void eat(String str) {
                    System.out.println("another");
              }
            }
            
            public class InheritanceSample {
                public static void main(String[] args) {
                    Animal a = new Animal();
                    Another t5 = (Another) new Goat();
                }
            }
            

            Another t5 = (Another) new Goat():您将获得ClassCastException,因为您无法使用Goat 创建Another 类的实例。

            注意:只有在类扩展父类并且子类被强制转换为其父类的情况下,转换才有效。

            ClassCastException如何处理:

            1. 尝试将一个类的对象转换为另一个类时要小心。确保新类型属于其父类之一。
            2. 您可以通过使用泛型来防止 ClassCastException,因为泛型提供编译时检查并可用于开发类型安全的应用程序。

            Source of the Note and the Rest

            【讨论】:

              【解决方案9】:

              我可以给你的 Java 中 classcastException 的一个很好的例子是在使用“Collection”时

              List list = new ArrayList();
              list.add("Java");
              list.add(new Integer(5));
              
              for(Object obj:list) {
                  String str = (String)obj;
              }
              

              上面的代码会在运行时给你 ClassCastException。因为您试图将 Integer 转换为 String,所以会抛出异常。

              【讨论】:

                【解决方案10】:

                Java ClassCastException 是当您尝试不正确地将类从一种类型转换为另一种时可能发生的异常。

                import java.util.ArrayList;
                import java.util.Iterator;
                import java.util.List;
                
                public class ClassCastExceptionExample {
                
                  public ClassCastExceptionExample() {
                
                    List list = new ArrayList();
                    list.add("one");
                    list.add("two");
                    Iterator it = list.iterator();
                    while (it.hasNext()) {
                        // intentionally throw a ClassCastException by trying to cast a String to an
                        // Integer (technically this is casting an Object to an Integer, where the Object 
                        // is really a reference to a String:
                        Integer i = (Integer)it.next();
                    }
                  }
                 public static void main(String[] args) {
                  new ClassCastExceptionExample();
                 }
                }
                

                如果你尝试运行这个 Java 程序,你会发现它会抛出以下 ClassCastException:

                Exception in thread "main" java.lang.ClassCastException: java.lang.String
                at ClassCastExceptionExample  (ClassCastExceptionExample.java:15)
                at ClassCastExceptionExample.main  (ClassCastExceptionExample.java:19)
                

                这里抛出异常的原因是,当我创建列表对象时,我存储在列表中的对象是字符串“one”,但后来当我尝试取出这个对象时,我故意制作了一个尝试将其转换为整数时出错。因为 String 不能直接转换为 Integer——Integer 不是 String 的类型——所以会抛出 ClassCastException。

                【讨论】:

                  【解决方案11】:

                  如果你想对对象进行排序,但如果类没有实现 Comparable 或 Comparator,那么你会得到 ClassCastException 例如

                  class Animal{
                     int age;
                     String type;
                  
                     public Animal(int age, String type){
                        this.age = age;
                        this.type = type;
                     }
                  }
                  public class MainCls{
                     public static void main(String[] args){
                         Animal[] arr = {new Animal(2, "Her"), new Animal(3,"Car")};
                         Arrays.sort(arr);
                     }
                  }
                  

                  上面的main方法会抛出下面的runtime class cast异常

                  线程“main”java.lang.ClassCastException 中的异常:com.default.Animal 无法转换为 java.lang.Comparable

                  【讨论】:

                    【解决方案12】:

                    Exception 不是 RuntimeException 的子类 -> ClassCastException

                        final Object  exception = new Exception();
                        final Exception data = (RuntimeException)exception ;
                        System.out.println(data);
                    

                    【讨论】: