转换和泛型如何工作?
How does casting and Generics work?
在阅读了一些示例之后,我仍然不太明白什么是泛型。
到目前为止我找到的最好的解释是 What does <> (angle brackets) mean in Java?
据我了解,如果您使用泛型,则无需将 return 值转换为类型。
但是泛型实际上做了什么?据我了解,确保(?)returned 值已转换为括号中定义的类型。
但这意味着,Java 需要对每个赋值进行强制转换。
String str = (String) otherstring;
是正确的,
String str = otherstring;
不合适。
据我了解,泛型 <String>
会确保值在赋值之前进行转换,所以我们不必转换它?
是否 Java 需要转换每个值,即使它已经是相同的类型?
转换和使用泛型之间的区别在于,它们是一种编译时机制。意思是,下面的代码不会得到运行时异常,而是根本无法编译:
Clazz <T> c = new Clazz <U> ();
如果 T 不能转换为 U。
PHP 在某种意义上更容易,但这只是因为它不关心其中的一些问题。使用 PHP,您稍后会处理这些问题。
投射基本上是在两个方向之一(向上或向下)。向上转换表明您更愿意仅通过它继承自(或继承其接口)的 class 的接口来使用该对象。
例如,如果我有一个 FileInputStream,我可以将其更改为 "just" 一个 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 类型,那么您将在 运行 时得到一个 class 转换异常。如果它确实具有适当的类型,则会分配 fileInput2。
使用这种类型系统的主要原因是您可以轻松编写可重用的组件。 "higher" 类型(向上转换类型)指定通用合同,而 "lower" 类型(向下转换类型)指定特定细节,这些细节在其超类型指定的通用合同中有所不同。
泛型;然而,是不同的蜡球。基本上在处理 Collections 以及与 Collections 相关的事物时,规则是相似的(但由于多种原因必须有所不同)。
泛型行为不同的原因之一是向后兼容性。将 "extra" 类型信息添加到已经存在的类型(如 java.util.List)的设计目标意味着对于泛型和非泛型的混合使用,该类型实际上不能在 运行 时存在。在 运行 时间不被认为存在的泛型类型 属性 称为 "erasure"。简而言之,当你写
List<Student> students = new ArrayList<Student>();
你正在有效地编译
List students = new ArrayList();
但是您的编译器会做 "extra" 工作以确保在您编写的任何源代码中,您只能添加一个 "Student" 对象。同样,当您阅读整个列表时,您不需要强制转换为 "Student" 对象,因为编译器会假定列表中只能包含 "Student" 个对象。
请注意,要让这样的系统运行,它只是编译时。这意味着它们不适用类型层次结构和 运行 时间转换的详细信息。这反映在泛型添加的新类型约束中。
T extends Student
表示 T 可以转换为 Student(向上转换)
T super Student
表示 T 是 Student 的超 class 后一个很棘手,但在某些情况下很有用。
如果CollegeStudent、HighSchoolStudent、GradeSchoolStudent都继承自Student,那么这三种Student都可以存储在一个List。
如果需要保证一个 Collection 至少 提供 Students,你可以给出一个 List.
public void studentProcessor(Collection<? super Student> students);
可以处理 List、List、List 等
通用 class 为您可以想象的任何对象提供功能 - 这个 处理的 class 有时称为您的 参数。例如 java.util.List
接口及其实现 classes,例如ArrayList<E>
为任意类型 E 提供列表功能(添加元素、删除元素、元素计数等...)(它可用于管理您自己类型的列表 Maroun
) .泛型类型的实现必须独立于它处理的参数。在示例中 - List
独立于 Maroun
所以泛型的概念与类型转换几乎没有任何关系,如您所见;)
当您有一个 class 实例可以通过 type 参数化时使用泛型。常见的例子是集合。
在泛型出现之前,Collection
包含许多 class 化的对象,Object
s。虽然这些对象有可能具有编译器无法识别的更具体的类型,因此需要危险的运行时转换为实际类型。
现在您可以参数化 Collection<E>
,其中 E
是元素类型。现在编译器可以确保 Collection<Foo>
只添加了 Foo
个实例,并且它可以 return 键入 Foo
个实例而无需强制转换。
在阅读了一些示例之后,我仍然不太明白什么是泛型。 到目前为止我找到的最好的解释是 What does <> (angle brackets) mean in Java?
据我了解,如果您使用泛型,则无需将 return 值转换为类型。
但是泛型实际上做了什么?据我了解,确保(?)returned 值已转换为括号中定义的类型。
但这意味着,Java 需要对每个赋值进行强制转换。
String str = (String) otherstring;
是正确的,
String str = otherstring;
不合适。
据我了解,泛型 <String>
会确保值在赋值之前进行转换,所以我们不必转换它?
是否 Java 需要转换每个值,即使它已经是相同的类型?
转换和使用泛型之间的区别在于,它们是一种编译时机制。意思是,下面的代码不会得到运行时异常,而是根本无法编译:
Clazz <T> c = new Clazz <U> ();
如果 T 不能转换为 U。
PHP 在某种意义上更容易,但这只是因为它不关心其中的一些问题。使用 PHP,您稍后会处理这些问题。
投射基本上是在两个方向之一(向上或向下)。向上转换表明您更愿意仅通过它继承自(或继承其接口)的 class 的接口来使用该对象。
例如,如果我有一个 FileInputStream,我可以将其更改为 "just" 一个 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 类型,那么您将在 运行 时得到一个 class 转换异常。如果它确实具有适当的类型,则会分配 fileInput2。
使用这种类型系统的主要原因是您可以轻松编写可重用的组件。 "higher" 类型(向上转换类型)指定通用合同,而 "lower" 类型(向下转换类型)指定特定细节,这些细节在其超类型指定的通用合同中有所不同。
泛型;然而,是不同的蜡球。基本上在处理 Collections 以及与 Collections 相关的事物时,规则是相似的(但由于多种原因必须有所不同)。
泛型行为不同的原因之一是向后兼容性。将 "extra" 类型信息添加到已经存在的类型(如 java.util.List)的设计目标意味着对于泛型和非泛型的混合使用,该类型实际上不能在 运行 时存在。在 运行 时间不被认为存在的泛型类型 属性 称为 "erasure"。简而言之,当你写
List<Student> students = new ArrayList<Student>();
你正在有效地编译
List students = new ArrayList();
但是您的编译器会做 "extra" 工作以确保在您编写的任何源代码中,您只能添加一个 "Student" 对象。同样,当您阅读整个列表时,您不需要强制转换为 "Student" 对象,因为编译器会假定列表中只能包含 "Student" 个对象。
请注意,要让这样的系统运行,它只是编译时。这意味着它们不适用类型层次结构和 运行 时间转换的详细信息。这反映在泛型添加的新类型约束中。
T extends Student
表示 T 可以转换为 Student(向上转换)
T super Student
表示 T 是 Student 的超 class 后一个很棘手,但在某些情况下很有用。
如果CollegeStudent、HighSchoolStudent、GradeSchoolStudent都继承自Student,那么这三种Student都可以存储在一个List。
如果需要保证一个 Collection 至少 提供 Students,你可以给出一个 List.
public void studentProcessor(Collection<? super Student> students);
可以处理 List
通用 class 为您可以想象的任何对象提供功能 - 这个 处理的 class 有时称为您的 参数。例如 java.util.List
接口及其实现 classes,例如ArrayList<E>
为任意类型 E 提供列表功能(添加元素、删除元素、元素计数等...)(它可用于管理您自己类型的列表 Maroun
) .泛型类型的实现必须独立于它处理的参数。在示例中 - List
独立于 Maroun
所以泛型的概念与类型转换几乎没有任何关系,如您所见;)
当您有一个 class 实例可以通过 type 参数化时使用泛型。常见的例子是集合。
在泛型出现之前,Collection
包含许多 class 化的对象,Object
s。虽然这些对象有可能具有编译器无法识别的更具体的类型,因此需要危险的运行时转换为实际类型。
现在您可以参数化 Collection<E>
,其中 E
是元素类型。现在编译器可以确保 Collection<Foo>
只添加了 Foo
个实例,并且它可以 return 键入 Foo
个实例而无需强制转换。