java传递class参数_如何将Class作为参数传递并在Java中返回泛型集合?
7 个答案:答案 0 :(得分:27)看起来您想要调整Josh Bloch所谓的Typesafe异类容器模式:您传递的是类型标记Class,并且您想要返回List。普通的旧THC可以以类型安全的方式将Class映射到T,但由于您实际上想要List,所以您想要使用Neal Gafter所称的< em>超级型令牌。以下片段改编自Nezy Gafter博客中发布的Crazy Bob Lee的
7 个答案:
答案 0 :(得分:27)
看起来您想要调整Josh Bloch所谓的Typesafe异类容器模式:您传递的是类型标记Class,并且您想要返回List。
普通的旧THC可以以类型安全的方式将Class映射到T,但由于您实际上想要List,所以您想要使用Neal Gafter所称的< em>超级型令牌。
以下片段改编自Nezy Gafter博客中发布的Crazy Bob Lee的代码:
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;
}
}
现在您可以创建一个超类型令牌,如下所示:
TypeReference stringTypeRef =
new TypeReference(){};
TypeReference integerTypeRef =
new TypeReference(){};
TypeReference> listBoolTypeRef =
new TypeReference>(){};
基本上你传递的是TypeReference而不是Class。区别在于没有List.class,但您可以制作TypeReference>。
所以现在我们可以按如下方式制作我们的容器(以下内容改编自Josh Bloch的原始代码):
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;
}
}
现在我们可以将两者放在一起:
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在他的博客中指出,对于超级类型令牌而言,TypeReference更多的花哨和口哨将成为JDK中值得包含的内容。
附件
参考
答案 1 :(得分:22)
既然你说你不希望你在不同的类中使用数据访问方法(在对anish的答案的评论中),我想为什么不尝试这样的事情。
public class Records {
public interface RecordFetcher{
public List getRecords();
}
static RecordFetcher Fruit=new RecordFetcher(){
public List getRecords() {
...
}
};
static RecordFetcher User=new RecordFetcher(){
public List getRecords() {
...
}
};
public static void main(String[] args) {
List fruitRecords=Records.Fruit.getRecords();
List userRecords=Records.User.getRecords();
}
}
修改强>
我想再添加一个我的实现。
public class Test
{
public static void main(String[] args)
{
Test dataAccess=new Test();
List FruitList=dataAccess.getAllRecords(Fruit.myType);
List UserList=dataAccess.getAllRecords(User.myType);
}
List getAllRecords(T cl)
{
List list=new ArrayList();
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 FruitList=dataAccess.getAllRecords(Fruit.class);
List UserList=dataAccess.getAllRecords(User.class);
}
List getAllRecords(Class cl) throws InstantiationException, IllegalAccessException
{
T inst=cl.newInstance();
List list=new ArrayList();
if(inst instanceof Fruit)
{
// Use JDBC and SQL SELECT * FROM user
}
else if(inst instanceof User)
{
// Use JDBC and SQL SELECT * FROM fruit
}
return list;
}
}
答案 2 :(得分:12)
你非常接近。
public LinkedList getAllRecords(List list) {
...
}
您需要指定List之类的参数。然后,根据您传入的列表的类型,Java将推断返回的泛型类型。
修改强>
保利的回答非常好。您应该很容易执行以下操作,而不必创建TypeReference类。
List fruit = myDataAccessObject.getAllRecrods(new LinkedList());
List users = myDataAccessObject.getAllRecords(new LinkedList());
答案 3 :(得分:4)
根据您实际检索数据的方式,您可以执行以下操作:
private static List getAll(Class cls){
List fromSql = (List) sql.query("SELECT * FROM objects WHERE type="+cls.getName());
return fromSql;
}
这需要您的sql对象返回正确类型的列表,这些O / R映射器就像iBatis一样。
如果您需要区分传递的类型,您仍然可以在cls上执行切换/案例。
答案 4 :(得分:3)
好吧,我真的不知道你是否需要这种方式。
但这是一种多态方法。它可能会以某种方式帮助某个地方。
为实现通用接口的不同表创建不同的对象。这意味着您将每个表表示为一个对象。
import java.util.LinkedList;
public class DataAccessTest
{
/**
* @param args
*/
public static void main(String[] args)
{
DataAccess myDataAccessObject = new DataAccess();
Type type1 = new Fruit();
Type type2 = new User();
LinkedList list1 = myDataAccessObject.getAllRecords(type1);
LinkedList list2 = myDataAccessObject.getAllRecords(type2);
LinkedList list3 = myDataAccessObject.getAllRecords(new Fruit());
LinkedList list4 = myDataAccessObject.getAllRecords(new User());
}
}
class DataAccess
{
public LinkedList getAllRecords(Type type)
{
return type.getAllRecords();
}
}
interface Type
{
public LinkedList getAllRecords();
}
class Fruit implements Type
{
public LinkedList getAllRecords()
{
LinkedList list = new LinkedList();
list.add(new Fruit());
return list;
}
}
class User implements Type
{
public LinkedList getAllRecords()
{
LinkedList list = new LinkedList();
list.add(new User());
return list;
}
}
答案 5 :(得分:1)
我相信你想做的事情可能会带有一些仿制魔法。我刚才必须解决同样的问题,这就是我所做的:
public class ListArrayUtils{
@SuppressWarnings("unchecked") // It is checked.
public static List filterByType(List aList, Class aClass){
List ans = new ArrayList<>();
for(E e: aList){
if(aClass.isAssignableFrom(e.getClass())){
ans.add((T)e);
}
}
return ans;
}
}
单元测试:
public class ListArrayUtilsTest{
interface IfA{/*nothing*/}
interface IfB{/*nothing*/}
class A implements IfA{/*nothing*/}
class B implements IfB{/*nothing*/}
class C extends A implements IfB{/*nothing*/}
@Test
public void testFilterByType(){
List data = new ArrayList<>();
A a = new A();
B b = new B();
C c = new C();
data.add(a);
data.add(b);
data.add(c);
List ans = ListArrayUtils.filterByType(data, IfB.class);
assertEquals(2, ans.size());
assertSame(b, ans.get(0));
assertSame(c, ans.get(1));
}
}
答案 6 :(得分:0)
我实际上是在通用数据访问库中完成此操作。见Norm。 Github上的完整源代码。
更多推荐
所有评论(0)