Java 如果在编译时没有检测到下面代码中的ClassCastException,即使在使代码成为泛型代码之后,泛型还有什么用处?

Java 如果在编译时没有检测到下面代码中的ClassCastException,即使在使代码成为泛型代码之后,泛型还有什么用处?,java,generics,polymorphism,type-safety,Java,Generics,Polymorphism,Type Safety,我已经读到泛型的全部要点是,泛型通过使更多的bug(本质上是当一个变量被分配了一个类型与变量类型不兼容的值时发生的bug)在编译时可检测,从而增加代码的稳定性 下面是一个非泛型类,我在其中得到一个运行时异常,ClassCastException发生在语句bforstoringreturnedoane=(B)框中我希望如果我将此代码设置为泛型,则不会发生此ClassCastException,因为泛型的使用会使导致异常的bug在编译时可检测到。 所以我也发布了这段代码的通用版本问题是在编译时没有检

我已经读到泛型的全部要点是,泛型通过使更多的bug(本质上是当一个变量被分配了一个类型与变量类型不兼容的值时发生的bug)在编译时可检测,从而增加代码的稳定性

下面是一个非泛型类,我在其中得到一个运行时异常,
ClassCastException
发生在语句
bforstoringreturnedoane=(B)框中我希望如果我将此代码设置为泛型,则不会发生此ClassCastException,因为泛型的使用会使导致异常的bug在编译时可检测到。

所以我也发布了这段代码的通用版本问题是在编译时没有检测到bug,我在同一条语句中得到了相同的ClassCastException。所以问题是有什么区别?仿制药有什么帮助?泛型存在的意义是什么?即使在使用泛型之后,在编译时仍然没有检测到错误/异常

非通用版本:

通用版本:

公共类另一类{
私有类A{}
私有类B扩展了{}
私有类C扩展了{}
私人舱位{
私人T法(T){
返回t;
}
}
公共静态void main(字符串[]args){
AnotherClass someClass=新的AnotherClass();
B=someClass.new B();
C=someClass.new C();
Box-Box=someClass.new-Box();
B B备用返回eda=(B)盒方法(B);
B B forstoringreturnedone=(B)box.aMethod(c);//*******ClassCastException
}
}

在您给出的示例中,泛型完美地完成了它们的工作

您创建了一个
,其中包含
aMethod
,它接收
a
,并返回
a
(在类型推断之后)

您将其传递为
B
,该方法将其作为
a
返回。然后将其强制转换为a
B
,这是因为对象实际上是a
B

然后将其传递为
C
,并将其作为
a
返回。然后将其强制转换为
B
,这会引发异常,因为该对象实际上不是
B

这与执行以下操作基本相同:

Box<A> box = someClass.new Box<>();

A a1 = box.aMethod(b);
A a2 = box.aMethod(c);

B b1 = (B) a1;
B b2 = (B) a2;
Box-Box=someClass.new-Box();
A a1=方盒法(b);
A a2=方盒法(c);
B b1=(B)a1;
b2=(B)a2;
我不明白你是如何期望泛型在这方面对你有所帮助的


但是,如果您制作了一个

Box-Box=someClass.new-Box();
B b1=盒子法(B);//好的,+不需要投
B b2=长方体法(c);//编译时错误
错误:类框中的方法aMethod无法应用于给定类型;
B b2=长方体法(c);//编译时错误
^
所需:B
发现:C
原因:参数不匹配;C不能转换为B
其中T是一个类型变量:
T扩展类框中声明的对象
1错误
编译器通过给出错误来正确保证类型安全

我希望如果我将此代码设置为泛型,则不会发生此ClassCastException,因为泛型的使用会使导致异常的bug在编译时可检测到

没有。显式类型转换不是编译时操作,而是运行时操作。任何时候,当您强制转换一个类型时,您基本上是在告诉编译器,您对运行时类型的了解比它对运行时类型的了解要多,并且编译器应该在这方面信任您

在上述两种情况下,编译器不知道的信息都是错误的。(当然,是有意的,为了你刚才的解释。)因此例外

泛型和其他类一样具有编译时类型安全性。它们背后没有魔力,它们无法在将来的运行时错误发生之前检测到它们

他们所做的是为各种类型提供一种“模板”。
Box
Box
是完全不同的类型,它本身具有Java提供的所有编译类型安全性<代码>框本身只是这些类型的一种模板,但在编译时特定类型必须仍然是已知的

基本上,
Box.aMethod()
的返回值是
a
。它不是动态的,它不是可变的,它是
A
。就像在非泛型版本中一样


泛型赋予您的是编写这些可重用的“模板”类型的能力,这些类型可以与许多其他类型组合,以形成实际的编译时结果类型。

如果您创建一个
,仍然删除强制类型转换,那将是安全的。泛型并不意味着删除类强制转换异常,它们有时可以删除强制转换的需要。这与泛型完全无关。例如,如果您有List并获取第一个元素,然后尝试将其转换为Cat,那么显然是错误的,并且会得到一个ClassCastException。关键是泛型将告诉您此返回类型的边界,或者参数在这两种情况下,您都在执行无效的强制转换。为什么在第二种情况下,您会期望其表现有所不同?泛型与类型转换没有任何关系。如果您想避免类CastException
,请不要执行无效的强制转换。@Solace:它们与泛型有关。强制转换是编译时未知类型的运行时解释。这基本上是一种告诉编译器您对类型的了解要比它多的方法。在发布的代码中,您对类型的了解(例如,故意)不正确。因此有例外。泛型不是对类型的运行时更改,而是
public class AnotherClass {

    private class A {}

    private class B extends A {}

    private class C extends A {}


    private class Box<T> {
        private T aMethod(T t) {
            return t;
        }
    }

    public static void main(String[] args) {
        AnotherClass someClass = new AnotherClass();

        B b = someClass.new B();

        C c = someClass.new C();

        Box<A> box = someClass.new Box<>();

        B bForStoringReturnedA = (B) box.aMethod(b);

        B bForStoringReturnedAOne = (B) box.aMethod(c);//*****ClassCastException

    }

}
Box<A> box = someClass.new Box<>();

A a1 = box.aMethod(b);
A a2 = box.aMethod(c);

B b1 = (B) a1;
B b2 = (B) a2;
Box<B> box = someClass.new Box<>();

B b1 = box.aMethod(b); // OK, + no need to cast
B b2 = box.aMethod(c); // Compile time error
error: method aMethod in class Box<T> cannot be applied to given types;
    B b2 = box.aMethod(c); // Compile time error
              ^
  required: B
  found: C
  reason: argument mismatch; C cannot be converted to B
  where T is a type-variable:
    T extends Object declared in class Box
1 error