【问题标题】:Type Parameter Class with generic java使用泛型 java 类型参数类
【发布时间】:2020-10-23 08:37:12
【问题描述】:

我正在尝试通过以下代码使用 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);
    }
}

由于使用这个解决方案是相当多的代码,有没有更好的方法来做到这一点?

【问题讨论】:

  • 泛型在 Java 的运行时被删除,这就是为什么你不能使用T.class。您找到的解决方案通常是使用的解决方案(但请注意,即使解决方案也不是完全类型安全的,例如 List&lt;U&gt; 不能完全由 Class 对象表示)。
  • 原版 Java 中没有。您是否有机会使用 Spring?
  • 我正在使用 Micronaut 框架,抱歉没有使用 spring
  • 请注意,将泛型类型用作单例对我来说似乎很奇怪。它是泛型的事实暗示了不同的参数化,但将其设为单例仅暗示了一种参数化(在这种情况下,为什么要使类型泛型?)。
  • 除了@Slaw 关于在单例中使用泛型的评论之外,您找到的解决方案似乎是执行此操作的正确方法。与其将 this 传递给构造函数,不如将其传递给类型转换的方法。在这两者之间,最好看一下配置mongoClient 以使用main 作为数据库并调用其getCollection 的方法。这应该完全消除整个类

标签: java micronaut


【解决方案1】:

一个单例类,其唯一的构造函数接受参数,并且是参数化的?

您的代码毫无意义。您遇到的问题在其他情况下很重要,但不是这个。这个问题没有直接的解决方案(问题是:泛型被擦除),但是有不同的代码风格可以避免它。

问题是,因为这个问题甚至不适用于这种情况,所以很难解释如何重写这段代码,所以问题作为一般原则消失了。

在这里,您只需...删除类型参数,摆脱该接口(通常,如果您有 IFoo 闲逛,有些事情是不对的),就这么简单。

如果你想概括这个概念,这样你就可以做很多这样的事情(假设你有一个类来检索 Foos,另一个类来检索 Bars),你可以获取&lt;X&gt; in特别是public class FooFetcher implements GenericFetcher&lt;X&gt;,虽然它有点棘手(你可以使用你自己的java.lang.Class 中的getGenericSuper 并从那里获取它。在这种情况下有很多警告,所以我不会进一步扩展,只知道你可以这样做。

如果在不同的情况下,您确实需要以运行时可查询的方式传达泛型,那么您的风格问题是 a class objecta generics param 重叠但不一样。 int 有一个类对象 (int.class),但 List&lt;int&gt; 不是有效的 Java 代码。 List&lt;String&gt; 是有效的泛型(List&lt;List&lt;String&gt;&gt; x; 是有效的 java),但 List&lt;String&gt;.class 不是,也永远不会,只有 List.class 可以。 ?? extends Map&lt;?, List&lt;? extends Number&gt;&gt; &amp; Serializable 也是如此,它们是有效的泛型,但显然根本不是你可以用 java.lang.Class 类型表示的东西。因此,如果您确实希望泛型作为运行时可查询的概念,请在网络上搜索“超级类型标记”——但请注意,它们需要的代码比您这里的代码更多,而不是更少。它们实际上只是能够准确地表示泛型可以表示的内容。

作为一般经验法则,如果您依赖 java.lang.Class 的泛型将代码粘合在一起,那么您做错了什么,您可能需要工厂。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多