PHP 在某种意义上更容易,但这只是因为它不关心其中的一些问题。使用 PHP,您可以稍后处理这些问题。
铸造基本上是在两个方向之一(向上或向下)。向上转换表示您希望仅通过它继承自(或继承其接口)的类的接口来处理该对象。
例如,如果我有一个 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。
这种类型系统的主要原因是您可以轻松编写可重用的组件。 “更高”类型(向上类型)指定一般合同,而“较低”类型(向下类型)指定在其超类型指定的一般合同中变化的特定细节。
泛型;但是,是不同的蜡球。基本上在处理 Collections 以及与 Collections 相关的事情时,规则是相似的(但由于多种原因必须有所不同)。
泛型行为不同的原因之一是向后兼容性。将“额外”类型信息添加到已经存在的类型(如 java.util.List)的设计目标意味着对于混合泛型和非泛型使用,该类型实际上不能在运行时存在。这种在运行时不被认为存在的泛型类型的属性称为“擦除”。总之,当你写
List<Student> students = new ArrayList<Student>();
你正在有效地编译
List students = new ArrayList();
但是您的编译器会做“额外”工作以确保在您编写的任何源代码中,您只能添加一个“学生”对象。同样,当您阅读列表时,不需要强制转换为“Student”对象,因为编译器会假定列表中只能包含“Student”对象。
请注意,要使这样的系统工作,它只是编译时的。这意味着它们的类型层次结构和运行时转换的详细信息不适用。这反映在泛型添加的新类型约束中。
T extends Student
表示可以将 T 转换为 Student(向上转换)
T super Student
表示 T 是 Student 的一个超类,后者比较棘手,但在某些场景中很有用。
如果CollegeStudent、HighSchoolStudent和GradeSchoolStudent都扩展了Student,那么这三种Student都可以存储在一个List中。
如果需要确保一个集合至少提供学生,那么你可以给出一个列表.
public void studentProcessor(Collection<? super Student> students);
可以处理 List、List、List 等