Как я могу передать Класс как параметр и возвратить универсальный набор в Java?

Я разрабатываю простой Объект Доступа к данным для своего JAVA-приложения. У меня есть несколько классов (записи), который представляет одну строку в таблицах как User и Fruit.

Я хотел бы иметь отдельный метод для получения всех записей определенного типа.

В настоящий момент у меня есть он как это:

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?

37
задан Jonas 3 August 2010 в 22:11
поделиться

5 ответов

Поскольку вы говорите, что не хотите использовать методы доступа к данным в разных классах (в комментарии к ответу Аниша), я подумал, почему бы не попробовать что-то подобное.

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 user
        }
        else if(inst instanceof User)
        {
            // Use JDBC and SQL SELECT * FROM fruit
        }
        return list;
    }
}
25
ответ дан 27 November 2019 в 04:35
поделиться

В зависимости от того, как вы на самом деле извлекаете данные, вы можете сделать что-то вроде этого:

private static <T> List<T> getAll(Class<T> cls){
  List<T> fromSql = (List<T>) sql.query("SELECT * FROM objects WHERE type="+cls.getName());
  return fromSql;
}

Это требует, чтобы ваш объект sql возвращал правильный тип списка, который O / R мапперы, такие как iBatis.

Если вам нужно различать переданные типы, вы все равно можете сделать переключатель / регистр на cls .

4
ответ дан 27 November 2019 в 04:35
поделиться

Похоже, вы хотите адаптировать то, что Джош Блох называет Шаблон безопасного гетерогенного контейнера : вы передаете токен типа Class и хотите вернуть List .

Обычный старый THC может сопоставить Class с T безопасным способом, но поскольку вам действительно нужен List вместо , то вы хотите использовать то, что Нил Гафтер назвал токенами супертипа .

Следующий фрагмент адаптирован из кода Сумасшедшего Боба Ли, опубликованного в блоге Нила Гафтера:

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 вместо Class . Разница в том, что нет List .class , но вы можете создать TypeReference > .

Итак, теперь мы можем сделать наш контейнер следующим образом (следующий текст адаптирован из исходного кода Джоша Блоха):

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]"

Нил Гафтер утверждал в своем блоге, что с еще несколькими колокольчиками и свистки, TypeReference для токенов супертипов будет достойным включением в JDK.

Вложения

Ссылки

27
ответ дан 27 November 2019 в 04:35
поделиться

Вы очень близки.

public <T> LinkedList<T> getAllRecords(List<T> list) {
 ...
}

Это называется Общий метод .

Вам нужно указать такой параметр, как List . Затем, основываясь на типе переданного вами списка, Java определит возвращаемый универсальный тип.

Изменить:

Поли ответил очень хорошо. Вам должно быть достаточно легко сделать следующее и не создавать класс TypeReference .

List<Fruit> fruit = myDataAccessObject.getAllRecrods(new LinkedList<Fruit>());
List<User> users = myDataAccessObject.getAllRecords(new LinkedList<User>());
13
ответ дан 27 November 2019 в 04:35
поделиться

Я правда не знаю, нужно ли вам это в таком виде. Но вот полиморфный подход. Это может где-то помочь.

Создавайте разные объекты для разных таблиц, все реализующие общий интерфейс. Это означает, что вы представляете каждую таблицу как объект.

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<Type> list1 = myDataAccessObject.getAllRecords(type1);
        LinkedList<Type> list2 = myDataAccessObject.getAllRecords(type2);
        LinkedList<Type> list3 = myDataAccessObject.getAllRecords(new Fruit());
        LinkedList<Type> list4 = myDataAccessObject.getAllRecords(new User());
    }
}

class DataAccess
{
    public LinkedList<Type> getAllRecords(Type type)
    {
        return type.getAllRecords();
    }
}

interface Type
{
    public LinkedList<Type> getAllRecords();
}

class Fruit implements Type
{
    public LinkedList<Type> getAllRecords()
    {
        LinkedList<Type> list = new LinkedList<Type>();
        list.add(new Fruit());
        return list;
    }
}

class User implements Type
{
    public LinkedList<Type> getAllRecords() 
    {
        LinkedList<Type> list = new LinkedList<Type>();
        list.add(new User());
        return list;
    }
}
3
ответ дан 27 November 2019 в 04:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: