英文:
Type Parameter Class with generic java
问题
以下是翻译好的内容:
我尝试在Java 15中使用以下代码中的通用类:
@Singleton
public class GenericRepository<T> implements IGenericRepository<T>{
private final MongoClient mongoClient;
public GenericRepository(MongoClient mongoClient) {
this.mongoClient = mongoClient;
}
public MongoCollection<T> getCollection(String collectionName) {
return mongoClient
.getDatabase("main")
.getCollection(collectionName, T.class);
}
}
我无法使用 T.class
,我该如何解决这个问题?
我找到的解决方案是:
@Singleton
public class GenericRepository<T> implements IGenericRepository<T>{
private final MongoClient mongoClient;
private final Class<T> typeParameterClass;
public GenericRepository(MongoClient mongoClient, Class<T> typeParameterClass) {
this.mongoClient = mongoClient;
this.typeParameterClass = typeParameterClass;
}
public MongoCollection<T> getCollection(String collectionName) {
return mongoClient
.getDatabase("main")
.getCollection(collectionName, this.typeParameterClass);
}
}
由于使用这个解决方案需要额外的代码,是否有更好的方法来解决这个问题?
英文:
I am trying to use the generic class in java 15 with the below code
@Singleton
public class GenericRepository<T> implements IGenericRepository<T>{
private final MongoClient mongoClient;
public GenericRepository(MongoClient mongoClient) {
this.mongoClient = mongoClient;
}
public MongoCollection<T> getCollection(String collectionName) {
return mongoClient
.getDatabase("main")
.getCollection(collectionName, T.class);
}
}
I can't use T.class, how can I solve this
Solution I found
@Singleton
public class GenericRepository<T> implements IGenericRepository<T>{
private final MongoClient mongoClient;
private final Class<T> typeParameterClass;
public GenericRepository(MongoClient mongoClient, Class<T> typeParameterClass) {
this.mongoClient = mongoClient;
this.typeParameterClass = typeParameterClass;
}
public MongoCollection<T> getCollection(String collectionName) {
return mongoClient
.getDatabase("main")
.getCollection(collectionName, this.typeParameterClass);
}
}
Since using this solution is quite extra code, is there any better way to do this ?
答案1
得分: 2
一个只有构造函数带有参数,并且是参数化的单例类?
你的代码毫无意义。你遇到的问题在其他情况下很重要,但在这种情况下却不重要。对于这个问题(问题是:泛型被擦除),没有直接的解决方案,但有不同的代码风格可以避免这个问题。
问题是,因为这个问题甚至不适用于这种情况,很难解释如何重写这段代码,使问题作为一般原则消失。
在这种情况下,你只需要... 移除类型参数,摆脱那个接口(通常如果你有一个名为IFoo
的接口,有些地方不对劲),就是这么简单。
如果你想要概括这个概念,使你可以创建很多这样的类(比如说你有一个用来检索Foo的类,另一个用来检索Bar的类),你可以在public class FooFetcher implements GenericFetcher<X>
中获取<X>
,虽然有点棘手(你会从你自己的java.lang.Class
中使用getGenericSuper
,然后从那里开始处理。在这种情况下有很多注意事项,所以我不会在这方面做更多展开,只需知道这样做是如何的。
如果在另一种情况下,你确实需要以可在运行时查询的方式传达泛型,你的风格问题在于“类对象”和“泛型参数”重叠但并不相同。int
有一个类对象(int.class
),但List<int>
不是有效的Java代码。List<String>
是有效的泛型(List<List<String>> x;
是有效的Java代码),但List<String>.class
不是一个存在的东西,而且永远也不会是,只有List.class
可以。对于?
、? extends Map<?, List<? extends Number>> & Serializable
,这是有效的泛型,但很明显无法用java.lang.Class
类型表示。因此,如果你确实希望泛型作为一种可在运行时查询的概念,可以在网络上搜索“超类型标记”(super type tokens) - 但请注意,它们需要比你这里的代码更多的代码,而不是更少。它们实际上能够精确地表示泛型所能表示的内容。
作为一个一般的经验法则,如果你依赖于java.lang.Class
的泛型来将你的代码粘合在一起,你肯定做错了什么,你可能需要使用工厂模式。
英文:
A singleton class, whose only constructor takes parameters, and is parameterized?
Your code makes no sense. The problem you're running into is significant in other contexts, but not this one. There is no direct solution to this problem (the problem being: Generics are erased), but there are different code styles that avoid it.
The problem is, because the problem doesn't even apply to this situation, it's hard to explain how one would rewrite this code so the problem goes away as a general principle.
Here, you'd just... remove the type param, get rid of that interface (in general if you have IFoo
hanging around, something's not right), simple as that.
If you want to generalize this concept, so that you can make a lot of these (Let's say you have one of these classes to retrieve the Foos, and another to retrieve the Bars), you CAN fetch the <X>
in specifically public class FooFetcher implements GenericFetcher<X>
, though it's a bit tricky (you'd use getGenericSuper
from your own java.lang.Class
and take it from there. There's a ton of caveats in this situation, so I won't expand any further on this, just know that's how you could do it.
If, in a different situation, you do need to convey generics in a runtime-queryable way, the problem with your style is that a class object
and a generics param
overlap but aren't the same. int
has a class object (int.class
), but List<int>
is not valid java code. List<String>
is valid generics (List<List<String>> x;
is valid java), but List<String>.class
isn't a thing and never will be, only List.class
can be. Same goes for ?
, ? extends Map<?, List<? extends Number>> & Serializable
, which is valid generics, but rather obviously not at all something you can represent with a java.lang.Class
type. Therefore, if you do want generics as a runtime queryable concept, search the web for 'super type tokens' - but note that they require MORE code than what you have here, not less. They're just actually capable of representing exactly what generics can represent.
As a general rule of thumb if you're relying on the generics of java.lang.Class to glue your code together you've done something wrong, and you probably want factories.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论