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上的完整源代码。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐