我如何传递一个类作为参数并在 Java 中返回一个泛型集合?

新手上路,请多包涵

我正在为我的 Java 应用程序设计一个简单的数据访问对象。我有几个类(记录)代表表中的一行,例如 UserFruit

我想要一种方法来获取特定类型的所有记录。

目前我是这样的:

 public List<User> getAllUsers() {
 ...
}

public List<Fruit> getAllFruits() {
 ...
}

....

但我想有一个像这样的单一多态方法(错误):

 public List<T> getAllRecords(Class<T> type) {
    if(type instanceof User) {
        // Use JDBC and SQL SELECT * FROM user
    } else if(type instanceof Fruit) {
        // Use JDBC and SQL SELECT * FROM fruit
    }
    return collection;
}

使用示例:

 List<Fruit> fruits = myDataAccessObject.getAllRecrods(Fruit.class);
List<User> users = myDataAccessObject.getAllRecords(User.class);

我如何在 Java 中执行此操作?

原文由 Jonas 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 635
2 个回答

既然你说你不希望不同类中的数据访问方法(在对 anish 的回答的评论中),我想为什么不尝试这样的事情。

 public class Records {

    public interface RecordFetcher<T>{
        public List<T> getRecords();
    }
    static RecordFetcher<Fruit> Fruit=new RecordFetcher<Fruit>(){
        public List<Fruit> getRecords() {
            ...
        }
    };

    static RecordFetcher<User> User=new RecordFetcher<User>(){
        public List<User> getRecords() {
            ...
        }
    };

    public static void main(String[] args) {
        List<Fruit> fruitRecords=Records.Fruit.getRecords();
        List<User> userRecords=Records.User.getRecords();

    }
}

编辑:

我想再添加一个我的实现。

 public class Test
{
    public static void main(String[] args)
    {
       Test dataAccess=new Test();
       List<Fruit> FruitList=dataAccess.getAllRecords(Fruit.myType);
       List<User> UserList=dataAccess.getAllRecords(User.myType);
    }
    <T> List<T> getAllRecords(T cl)
    {
        List<T> list=new ArrayList<T>();
        if(cl instanceof Fruit)
        {
             // Use JDBC and SQL SELECT * FROM fruit
        }
        else if(cl instanceof User)
        {
            // Use JDBC and SQL SELECT * FROM user
        }
        return list;
    }
}
class Fruit
{
    static final Fruit myType;
    static {myType=new Fruit();}
}
class User
{
    static final User myType;
    static {myType=new User();}
}

编辑

我认为这个实现就像你问的那样

public class Test
{
    public static void main(String[] args) throws InstantiationException, IllegalAccessException
    {
       Test dataAccess=new Test();

       List<Fruit> FruitList=dataAccess.getAllRecords(Fruit.class);

       List<User> UserList=dataAccess.getAllRecords(User.class);

    }
    <T> List<T> getAllRecords(Class<T> cl) throws InstantiationException, IllegalAccessException
    {
        T inst=cl.newInstance();
        List<T> list=new ArrayList<T>();
        if(inst instanceof Fruit)
        {
             // Use JDBC and SQL SELECT * FROM fruit
        }
        else if(inst instanceof User)
        {
            // Use JDBC and SQL SELECT * FROM user
        }
        return list;
    }
}

原文由 Emil 发布,翻译遵循 CC BY-SA 4.0 许可协议

看起来你想要适应 Josh Bloch 所说的类型安全 异构容器 模式:你正在传递一个类型标记 Class<T> ,你想要返回一个 List<T>

普通的旧 THC 可以以类型安全的方式将 — Class<T> 映射到 T ,但是因为你实际上想要一个 List<T> 在你想要使用什么之后,Neal G–调用 _超类型令牌_。

以下片段改编自 Crazy Bob Lee 在 Neal Gafter 的博客中发布的代码:

 public abstract class TypeReference<T> {
    private final Type type;

    protected TypeReference() {
        Type superclass = getClass().getGenericSuperclass();
        if (superclass instanceof Class<?>) {
            throw new RuntimeException("Missing type parameter.");
        }
        this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
    }
    public Type getType() {
        return this.type;
    }
}

现在你可以像这样创建一个 _超类型令牌_:

     TypeReference<String> stringTypeRef =
            new TypeReference<String>(){};

    TypeReference<Integer> integerTypeRef =
            new TypeReference<Integer>(){};

    TypeReference<List<Boolean>> listBoolTypeRef =
            new TypeReference<List<Boolean>>(){};

本质上,您传递的是 TypeReference<T> 而不是 Class<T> 。区别在于没有 List<String>.class ,但是你可以制作一个 TypeReference<List<String>>

所以现在我们可以按如下方式制作我们的容器(以下内容改编自 Josh Bloch 的原始代码):

 public class Favorites {
    private Map<Type, Object> favorites =
        new HashMap<Type, Object>();

    public <T> void setFavorite(TypeReference<T> ref, T thing) {
        favorites.put(ref.getType(), thing);
    }
    public <T> T getFavorite(TypeReference<T> ref) {
        @SuppressWarnings("unchecked")
        T ret = (T) favorites.get(ref.getType());
        return ret;
    }
}

现在我们可以把两者放在一起:

     Favorites f = new Favorites();
    f.setFavorite(stringTypeRef, "Java");
    f.setFavorite(integerTypeRef, 42);
    f.setFavorite(listBoolTypeRef, Arrays.asList(true, true));

    String s = f.getFavorite(stringTypeRef);
    int i = f.getFavorite(integerTypeRef);
    List<Boolean> list = f.getFavorite(listBoolTypeRef);

    System.out.println(s);    // "Java"
    System.out.println(i);    // "42"
    System.out.println(list); // "[true, true]"

Neal Gafter 在他的博客中争辩说,如果有更多的花里胡哨, TypeReference 超级类型令牌将值得包含在 JDK 中。

附件

参考

原文由 polygenelubricants 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题