英文:
How to create an instance of an generic class in java?
问题
我在想是否有可能创建一个构造函数:
public <C, T> C newInstance(Class<C> constructor_class,
Class<T> type,
Object... parameters){
// 使用泛型类型和参数创建一个新实例
// 基本上就像这样,但是带有泛型和参数
return constructor_class.newInstance();
}
英文:
I was wondering if it is possible to create a construtor function:
public <C, T> C newInstance(Class<C> constructor_class,
Class<T> type,
Object...parameters){
// create a new Instance with the generic type and the paramters
//so basicly like this, but with generics and parameters
return constructor_class.newInstance();
}
答案1
得分: 1
你基本上是做不到的。你的示例有问题 - type
应该表示什么?
假设你想动态创建一个 HashMap<String, Integer>
。这将需要传递 HashMap.class
、String.class
和 Integer.class
,但我们立刻就遇到了很多问题:
- 我们怎么知道 HashMap 有 2 个参数?我们不知道,所以你需要通过 varargs 传递 2 个类引用,在运行时,如果你传递了错误数量的类,我猜我们会抛出异常。
- 如果你传递 Map,它根本无法被实例化怎么办?
- 但最重要的是,这是完全没有用的,泛型不会出现在方法/字段/类签名中,它们只存在于编译器的想象中:javac 在编译过程中使用它来发出警告或错误,以及生成不可见的强制转换操作,然后将这些信息丢弃。通过动态方式实现,所有在“编译时”的内容在定义上无法工作(我们正在编译,而不是运行,类型应该是动态的,所以 javac 无法执行),因此对于 javac 来说,它是无用的,然后信息被丢弃。所以这完全是无用的,对吧?
此外,Class
无法用于传递泛型参数。如果我想要一个 HashMap<List<String>, Integer>
呢?List<String>
在类文字中不存在,因此在这里无法使用 java.lang.Class<T>
。还有一些类对象(特别是 int.class
)在泛型中是不合法的。因此,?
、? super Foo
、A,B extends A,C extends A & Serializable
、List<String>
都是可以放在 <>
中的示例,但不能成为 java.lang.Class
的引用,而 int.class
是一个合法的类引用,但不能放在 <>
中。不能把一个方形桩放进圆洞里。更不用说即使你能做到,它也会完全没有任何作用(见第3点:这是无用的 - 大多数泛型,尤其是你在这里使用的泛型,会影响编译并在之后消失)。
在这个领域有一些疯狂的技巧(比如超类型标记),但如果你不完全了解泛型在幕后是如何工作的,那么你几乎不可能能够有用地使用这些技巧,所以在那之前最好不要尝试。而且问这个问题,尤其是带有那种伪代码,强烈暗示你对此了解不足。
英文:
You basically can't. Your example is broken - what is type
supposed to represent?
Let's say you want to dynamically create a HashMap<String, Integer>
. This would require that you pass in HashMap.class
, String.class
, and Integer.class
, but we run into a TON of problems right off the bat:
- How do we know that HashMap has 2 args? We don't, so you'd have to pass 2 class references via varargs and at runtime I guess we throw an exception if you passed the wrong number of classes.
- What if you pass Map, which cannot be instantiated at all?
- But most of all, this is completely useless, generics that do not show up in method/field/class signatures are figments of the compiler's imagination: javac uses it during compilation to warn or error, as well as to generate invisible caste operations, and then chucks this info away. By doing it dynamically, all that 'at compile time' stuff cannot work by definition (we're compiling, not running, the whole point is for the types to be dynamic, so javac cannot do), so to javac it is useless, and the info is then chucked. So that makes it fully useless, then, no?
Furthermore, Class
cannot be used to convey generics args. What if I wanted a HashMap<List<String>, Integer>
instead? List<String>
does not exist as a class literal, so java.lang.Class<T>
cannot be used here. There are also class objects (specifically, int.class
) that aren't legal in generics. So, we have ?
, ? super Foo
, A, B extends A, C extends A & Serializable
, List<String>
all as examples of things that can go in <>
but which cannot be a java.lang.Class
reference, and int.class
that is a legal class ref but which cannot go in <>
. You can't put a square peg in a round hole. Let alone the fact that even if you could, it would do literally absolutely nothing whatsoever (see point #3: This is useless - most generics, and definitely the generics you'd use here, affect compilation and cease to exist afterwards).
There are crazy hacks in this space (super type tokens, for example), but if you do not fully understand how generics work under the hood, there is 0.00001% or less chance you will be able to use such hacks usefully, so don't bother until then. And asking this question, especially with that pseudocode, strongly suggests you don't understand enough of it yet.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论