Cast和Generics如何工作?

时间:2015-02-16 09:33:44

标签: java generics casting

在阅读了一些例子后,我仍然无法得到Generics的内容。 我到目前为止找到的最佳解释是What does <> (angle brackets) mean in Java?

根据我的阅读,如果您使用泛型,则不需要将返回值转换为类型。

但是Generics究竟做了什么?根据我的理解,确保(?)返回的值已经转换为括号中定义的类型。

但这意味着,Java要求每个分配都被强制转换。

String str = (String) otherstring;

是正确的,

String str = otherstring;

不合适。

因此,根据我的理解,通用<String>将确保在分配之前投射该值,因此我们不必投射它?

Java是否需要投射每个值,即使它已经是相同类型的?

4 个答案:

答案 0 :(得分:1)

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

施法基本上是两个方向之一(向上或向下)。 up-cast表示你更愿意只通过它继承的类的接口来处理对象(或者继承接口)。

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

FileInputStream fileInput = ...
InputStream input = (InputStream)fileInput;

请注意,这对可达方法的实现没有任何影响;但有时会隐藏以前可用的方法。

fileInput.getFileName();  // let's pretend this works
input.getFileName(); // this shouldn't work, as any InputStream doesn't have a file name.

向下倾斜是不同的(也是危险的)。你基本上声明即使你有一个InputStream,你知道它应该被视为一个FileInputStream

InputStream input2 = ...;
FileInputStream fileInput2 = (FileInputStream)input2;

如果此场景中的input2没有相应类型的FileInputStream,那么您将在运行时获得类转换异常。如果它具有适当的类型,则将分配fileInput2。

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

泛型;然而,是一个不同的蜡球。基本上在处理集合以及与集合相关的事情时,规则是相似的(但由于多种原因必须不同)。

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

List<Student> students = new ArrayList<Student>();

你正在有效地编译

List students = new ArrayList();

但是你的编译器会做“额外的”工作,以确保在你编写的任何源代码中,你只能添加一个“Student”对象。同样,当您阅读List时,您不需要转换为“Student”对象,因为编译器将假定只有“Student”对象可以在列表中。

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

T extends Student

表示T可以投射到学生(向上演员)

T super Student

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

如果CollegeStudent,HighSchoolStudent和GradeSchoolStudent都延伸学生,那么所有三种类型的学生都可以存储在List&lt;?扩展学生&gt;在同一时间。

如果有什么需要确保收藏品至少为学生提供,那么你可以给出一个List&lt;?超级学生&gt;。

public void studentProcessor(Collection<? super Student> students);

可以处理列表&lt; Student&gt ;, List&lt; CollegeStudent&gt ;, List&lt; GradeSchoolStudent&gt;等

答案 1 :(得分:0)

转换和使用泛型之间的区别在于它们是编译时机制。这意味着,下面的代码不会得到运行时异常,而是根本无法编译:

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

如果T不能投射到U.

答案 2 :(得分:0)

泛型类为您可以想象的任何对象提供功能 - 此处理的类有时称为参数。例如java.util.List接口及其实现类,例如ArrayList<E>为任意类型E提供列表功能(添加元素,删除元素,元素计数等等)(它可用于管理您自己的类型Maroun的列表) 。泛型类型的实现必须独立于它处理的参数。在示例中,List独立于Maroun

所以泛型的概念与类型转换几乎没有任何关系,正如你所看到的那样;)

答案 3 :(得分:0)

如果您的类可以通过类型进行参数化,则使用泛型。常见的例子是集合。

在泛型之前,Collection包含许多被归类为Object s的对象。虽然对象有可能具有编译器无法识别的更具体类型,因此需要对实际类型进行危险的运行时转换。

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