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 Fruit
.
I would like to have a single method for getting all records of a specific type.
For the moment I have it like this:
public List<User> getAllUsers() { ... } public List<Fruit> getAllFruits() { ... } ....
But I would like to have a single polymorphic method like this (wrong):
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; }
Example for uses:
List<Fruit> fruits = myDataAccessObject.getAllRecrods(Fruit.class); List<User> users = myDataAccessObject.getAllRecords(User.class);
How can I do this in Java?
(Yes, this is legal code; see Java Generics: Generic type defined as return type only.) The return type will be inferred from the caller. However, note the @SuppressWarnings annotation: that tells you that this code isn't typesafe. You have to verify it yourself, or you could get ClassCastExceptions at runtime.
We have a method coypObject() which accepts an object of the current class and initializes the instance variables with the variables of this object and returns it. In the main method we are instantiating the Student class and making a copy by passing it as an argument to the coypObject() method.
Which of these type parameters is used for a generic methods to return and accept any type of object? Explanation: T is used for type, A type variable can be any non-primitive type you specify: any class type, any interface type, any array type, or even another type variable.
It looks like you want to adapt what Josh Bloch calls a Typesafe Heterogenous Container pattern: you are passing a type token Class<T>
, and you want back a List<T>
.
Plain old THC can map a Class<T>
to a T
in a typesafe manner, but since you actually want a List<T>
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<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; } }
Now you can create a super type token like these:
TypeReference<String> stringTypeRef = new TypeReference<String>(){}; TypeReference<Integer> integerTypeRef = new TypeReference<Integer>(){}; TypeReference<List<Boolean>> listBoolTypeRef = new TypeReference<List<Boolean>>(){};
Essentially you pass a TypeReference<T>
instead of a Class<T>
. The difference is that there is no List<String>.class
, but you can make a TypeReference<List<String>>
.
So now we can make our container as follows (the following is adapted from Josh Bloch's original code):
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; } }
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<Boolean> 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With