How can I pass a Class as parameter and return a generic collection in Java?

后端 未结 7 1106
悲哀的现实
悲哀的现实 2020-12-24 05:18

I am designing a simple Data Access Object for my Java application. I have a few classes (records) that represents a single row in tables like User and Fr

7条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-24 06:02

    It looks like you want to adapt what Josh Bloch calls a Typesafe Heterogenous Container pattern: you are passing a type token Class, and you want back a List.

    Plain old THC can map a Class to a T in a typesafe manner, but since you actually want a List instead, then you want to use what Neal Gafter calls the super type tokens.

    The following snippet is adapted from Crazy Bob Lee's code posted in Neal Gafter's blog:

    public abstract class TypeReference {
        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;
        }
    }
    

    Now you can create a super type token like these:

        TypeReference stringTypeRef =
                new TypeReference(){};
    
        TypeReference integerTypeRef =
                new TypeReference(){};
    
        TypeReference> listBoolTypeRef =
                new TypeReference>(){};
    

    Essentially you pass a TypeReference instead of a Class. The difference is that there is no List.class, but you can make a TypeReference>.

    So now we can make our container as follows (the following is adapted from Josh Bloch's original code):

    public class Favorites {
        private Map favorites =
            new HashMap();
    
        public  void setFavorite(TypeReference ref, T thing) {
            favorites.put(ref.getType(), thing);
        }
        public  T getFavorite(TypeReference ref) {
            @SuppressWarnings("unchecked")
            T ret = (T) favorites.get(ref.getType());
            return ret;
        }
    }
    

    Now we can put the two together:

        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 list = f.getFavorite(listBoolTypeRef);
    
        System.out.println(s);    // "Java"
        System.out.println(i);    // "42"
        System.out.println(list); // "[true, true]"
    

    Neal Gafter argued in his blog that with some more bells and whistles, TypeReference for super type tokens will make a worthy inclusion in the JDK.

    Attachments

    • Complete source code on ideone.com

    References

    • Neal Gafter's Blog - Super Type Tokens

提交回复
热议问题