Java 铸造和仿制药是如何工作的?

Java 铸造和仿制药是如何工作的?,java,generics,casting,Java,Generics,Casting,在阅读了一些例子之后,我仍然不太明白泛型是什么。 到目前为止,我找到的最好的解释是 据我所知,如果使用泛型,则不需要将返回值强制转换为类型 T extends Student 但是泛型实际上做什么呢?从我的理解来看,确保(?)返回值已经转换为括号中定义的类型 但这意味着Java需要强制转换每个赋值 String str = (String) otherstring; 是恰当的,并且 String str = otherstring; 这是不恰当的 根据我的理解,generic会确保在赋值之

在阅读了一些例子之后,我仍然不太明白泛型是什么。 到目前为止,我找到的最好的解释是

据我所知,如果使用泛型,则不需要将返回值强制转换为类型

T extends Student
但是泛型实际上做什么呢?从我的理解来看,确保(?)返回值已经转换为括号中定义的类型

但这意味着Java需要强制转换每个赋值

String str = (String) otherstring;
是恰当的,并且

String str = otherstring;
这是不恰当的

根据我的理解,generic
会确保在赋值之前对值进行强制转换,所以我们不必强制转换它


Java是否需要强制转换每一个值,即使它已经是相同的类型?

强制转换与泛型的区别在于它们是一种编译时机制。这意味着,下面的代码不会编译,而不会获得运行时异常:

Clazz <T> c = new Clazz <U> ();
Clazz c=newclazz();

如果不能将T转换为U.

PHP在某种意义上更容易,但这只是因为它不关心这些问题。使用PHP,您可以稍后处理这些问题

铸造基本上是在两个方向之一(向上或向下)。向上转换表示您希望仅通过对象继承的类(或继承对象的接口)的接口来处理对象

例如,如果我有一个FileInputStream,我可以将其更改为“只是”一个InputStream

FileInputStream fileInput = ...
InputStream input = (InputStream)fileInput;
InputStream input2 = ...;
FileInputStream fileInput2 = (FileInputStream)input2;
注意,这对可到达方法的实现没有任何影响;但is有时会隐藏以前可用的方法

fileInput.getFileName();  // let's pretend this works
input.getFileName(); // this shouldn't work, as any InputStream doesn't have a file name.
向下投射是不同的(也是危险的)。您基本上声明,即使您有一个InputStream,但不知何故您知道它应该被视为一个FileInputStream

FileInputStream fileInput = ...
InputStream input = (InputStream)fileInput;
InputStream input2 = ...;
FileInputStream fileInput2 = (FileInputStream)input2;
如果此场景中的input2没有适当类型的FileInputStream,则在运行时将出现类强制转换异常。如果它确实具有适当的类型,则将分配fileInput2

使用这种类型系统的主要原因是,您可以轻松编写可重用组件。“较高”类型(向上转换类型)指定一般合同,而“较低”类型(向下转换类型)指定在其超级类型指定的一般合同内变化的特定细节

仿制药;然而,它们是一个不同的蜡球。基本上,在处理集合以及与集合相关的事物时,规则是相似的(但由于许多原因必须不同)

泛型行为不同的原因之一是向后兼容性。将“额外”类型信息添加到已经存在的类型(如java.util.List)的设计目标意味着,对于混合泛型和非泛型使用,该类型在运行时不能有效存在。这种在运行时不被认为存在的泛型类型的属性称为“擦除”。简而言之,当你写作的时候

List<Student> students = new ArrayList<Student>();
但是您的编译器将进行“额外”工作,以确保在您编写的任何源代码中,您只能添加一个“Student”对象。同样,当您阅读整个列表时,不需要强制转换为“Student”对象,因为编译器将假定列表中只能有“Student”对象

请注意,对于这样一个系统来说,它只在编译时工作。这意味着它们不适用于类型层次结构和运行时强制转换的详细信息。这反映在泛型添加的新类型约束中

T extends Student
意味着T可以投射给学生(向上投射)

这意味着T是一个超级学生班。后一个很棘手,但在某些情况下很有用


如果CollegestStudent、HighSchoolStudent和GradeSchoolStudent都扩展了Student,那么所有三种类型的Student都可以存储在一个列表中一个泛型类为您可以想象的任何对象提供功能-这个处理过的类有时称为您的参数。例如,
java.util.List
接口及其实现类,例如,
ArrayList
为任意类型e提供列表功能(添加元素、删除元素、元素计数等)(它可以用于管理您自己类型的列表
Maroun
)。泛型类型的实现必须独立于它处理的参数。在示例中-
List
独立于
Maroun


因此,泛型的概念与类型转换几乎没有任何关系,如您所见;)

如果类的实例可以由类型参数化,则使用泛型。常见的例子是一个集合

在泛型之前,
集合
包含许多对象,这些对象被分类为,
对象
s。虽然对象可能具有编译器无法识别的更特定类型,因此需要对实际类型进行危险的运行时强制转换


现在您可以参数化
Collection
,其中
E
是元素类型。现在编译器可以确保
集合
只添加了
Foo
实例,并且可以返回类型化的
Foo
实例,而不需要强制转换。

泛型的主要思想是克服运行时异常并提供编译时警告。Java通常不需要任何类型强制转换,除非是在特殊情况下,应避免向下浇铸。如果您必须使用泛型强制转换,这是因为您使用的库不使用泛型,但您使用泛型。或者,您正在做一些可能不安全的事情,或者您正试图将一个为泛型设计的类弯曲到它本来不打算做的事情。有时这样的场景是有效的(但并不经常),所以对于这些拐角情况,可以进行铸造操作。尽量不要使用它们。我这里有一个游标装载机返回。但在定义上是存在的。这意味着我将在返回之前将游标装载器剥离到游标上?@Gacek在你的情况下是我