在阅读了一些例子后,我仍然无法得到Generics的内容。 我到目前为止找到的最佳解释是What does <> (angle brackets) mean in Java?
根据我的阅读,如果您使用泛型,则不需要将返回值转换为类型。
但是Generics究竟做了什么?根据我的理解,确保(?)返回的值已经转换为括号中定义的类型。
但这意味着,Java要求每个分配都被强制转换。
String str = (String) otherstring;
是正确的,
String str = otherstring;
不合适。
因此,根据我的理解,通用<String>
将确保在分配之前投射该值,因此我们不必投射它?
Java是否需要投射每个值,即使它已经是相同类型的?
答案 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
的实例,而不需要强制转换。