Java 类 Class<T>
由于以下原因,通用会造成混淆。
想象一个类 Cake<T>{}
所以你可以创造
new Cake<Pineapple>
和 new Cake<Apple>
ETC
如果每个类(class) e.x Apple
有一个可参数化的类对象,如果类 Class
是通用的,那么似乎有可能创建 Apple<Something>
或 Integer<Something>
,这没有任何意义。
我不知道我在这里理解错了什么。看似inception,但更深的层次与上面的层次相同。
假设下面是通用类
public class Cake<T> {
T cakeType;
void setCakeType(T cakeArg){
this.cakeType = cakeArg;
}
void doStuff(){
System.out.println(cakeType.toString());
}
}
假设 Pineapple 是非泛型类作为 Cake 的参数类型
public class Pineapple {
@Override
public String toString() {
return "I am a Pineapple";
}
}
如果类Class
不是通用的,那么凭直觉,会有 Pineapple Class
目的
但是作为类Class<T>
本身是通用的。然后似乎有可能创建 Pineapple
的可参数化类对象即Pineapple<Something>
.
基本假设:只有一个 Class
每个类的对象。对其进行参数化有何意义?
最佳答案
我将尝试通过几种不同的方法来解决这个问题;我认为正在发生的事情之间存在根本性的脱节,因此分散式方法可能更有可能使其中一个点成为“点击”。
层次结构
因此,首先,不要认为 Apple 有类对象;相反,有一个 Apple 类,在它旁边还有一个描述它的 Class 对象。但是那个 Class 对象只是独立存在,而不是 Apple 层次结构的一部分。它不是 Apple 的母公司;它是它最好的 friend 。
所有类的基类都是Object,而不是Class。现在,如果 Object 被参数化,那么您将拥有与您所描述的内容一致的内容——但事实并非如此。由于 Class 不是 Apple 层次结构的一部分,因此从逻辑上讲,Class 被参数化并不会使 Apple 参数化。
类比其他泛型类
Class 对象的意义在于谈论其他对象——告诉我们诸如“这是一个 T”或“这是创建 T 的方式”之类的事情。那么,每个实例如何在编译时告诉我们它在谈论哪类事情呢?通过参数。
同样,List 对象的要点是谈论其他对象——将它们放在一个组中。它还使用通用参数来描述它所谈论的事物的种类。使用列表,您可以仅通过类型签名来判断其中的内容:a List<String>
在 List<Integer>
时关注字符串关注整数。好吧,以同样的方式,一个Class<String>
Class<Integer>
时谈论字符串谈论整数。 Class 参数化这一事实对 String 或 Integer 的影响并不比 List 参数化这一事实更大。
换句话说:在最高级别,List<String>
用字符串做事。 Class<String>
也是如此
一些用例
最后,思考为什么类是参数化的可能会有所帮助。 Class 上只有少数方法返回 T
类型。让我们来看看其中的两个:
T newInstance()
T cast(Object o);
如果 Class 没有参数化,这两个都将返回 Object。你必须做这样的事情:
Class<Apple> appleClass = ...;
Apple newApple = (Apple) appleClass.newInstance();
Apple existingApple = (Apple) appleClass.cast(existingObject);
好的,这样还算不错。但在这种情况下,我们已经知道我们感兴趣的事物类型(苹果)。这就是我们可以添加 Apple 类型转换的原因,但出于同样的原因,这也是使用 Class<Apple>
的原因。没有用。上面的代码片段最好按以下方式完成:
Apple newApple = new Apple();
Apple existingApple = (Apple) existingObject;
相反,当您使用本身是通用的方法时,类的通用方面通常很有用。例如:
<T> T tryConsume(Consumer<T> consumer, Object item, Class<T> consumeClass) {
T itemCasted = consumeClass.cast(item);
consumer.consume(itemCasted);
}
诚然,这个例子不是很有趣。但我要指出的一件事是,如果没有 consumeClass,您将不得不将 item 转换为 (T)
.由于type erasure ,这在运行时实际上是一个空操作,如果该项目属于错误的类,则 ClassCastException 将来自 consumer
中一个奇怪的生成行代码 -- 不是来自 tryConsume 内部,它很好而且清晰。做到这一点 cast
方法实际上做 转换,并且有用,你需要 consumeClass.cast(item)
返回 T
.为此,consumeClass
必须是 Class<T>
类型.
关于java - Class<T> 怎么可能是通用的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44170999/