2012-01-31 5 views
4

Я новичок в java, так что извиняюсь, если у меня есть совершенно неправильный конец палки.Java и generics

Я пытаюсь написать общий (в английском смысле слова!) Класс доступа к данным. например, я в настоящее время:

public class DA<T> { 
public static Dao getAccountDao() throws NamingException, SQLException { 
    Context ctx = new InitialContext(); 
    DataSource dataSource = (DataSource)ctx.lookup("java:comp/env/jdbc/test"); 
    ConnectionSource connectionSource = new DataSourceConnectionSource(dataSource, new MysqlDatabaseType());    
    Dao<Account, Integer> accountDao = DaoManager.createDao(connectionSource, Account.class); 
    return accountDao; 
} 
} 

И я могу назвать это с:

Dao<Account, Integer> accountDao = DA.getAccountDao(); 

Но я нужна версия этого для каждого Dao/модели. Поэтому я пытаюсь сделать что-то, что можно назвать следующим:

Dao<SomeClass, Integer> someClassDao = DA.getDao(SomeClass); 

Возможно ли это?

Я пытался что-то вроде:

public class DA { 
public static Dao getDao(<T>) throws NamingException, SQLException { 
    Context ctx = new InitialContext(); 
    DataSource dataSource = (DataSource)ctx.lookup("java:comp/env/jdbc/test"); 
    ConnectionSource connectionSource = new DataSourceConnectionSource(dataSource, new MysqlDatabaseType());    
    Dao<T, Integer> accountDao = DaoManager.createDao(connectionSource, T.class); 
    return accountDao; 
} 

}

но Netbeans дает ошибку: illegal start of type

Мой мозг борется с обобщениями, это то, что они могут сделать ?!

EDIT: С помощью постов ниже я должен:

public class DA<T> { 
public static Dao<T, Integer> getDao(T daoType) throws NamingException, SQLException { 
    Dao<T, Integer> accountDao = DaoManager.createDao(T.class); 
    return accountDao; 
} 

}

, который генерирует две ошибки: non-static type variable T cannot be referenced from a static context и если я удалить static ключевое слово, я получаю: cannot select from a type variable Мне нужно узнать о том, как общие и статические работы работают вместе, но второй выглядит как следствие стирания (http://www.coderanch.com/t/386358/java/java/Converting-type-parameters-class), поэтому не уверен, что это происходит возможно.

Следует упомянуть ранее, что материал Dao использует библиотеку ORM под названием ORMLite, поэтому createDao и т. Д. Не мой код.

+0

мне нужно для достижения тех же целей твоего и шел по тому же маршруту как и ты. но библиотека ORMLite, которую вы используете, предлагает другой способ сделать это. Этот комментарий не отвечает на ваш вопрос, но, вероятно, поможет вам лучше достичь своей общей цели. См. Этот вопрос [SO для более подробной информации] (http://stackoverflow.com/questions/8273675/how-to-extend-the-basedaoimpl-class-of-ormlite-on-android-to-extend-functionalit). Надеюсь, поможет. –

ответ

2

чтобы получить доступ, что вы имеете в виду T.class, вы должны передать объект класса в метод:

class Account {} 

class Dao<TEntity, TId> {} 

class DA { 
    // your DaoManager.createDao() will also need a similar signature 
    public static <TEntity> Dao<TEntity, Integer> getDao(Class<TEntity> daoType) { 
     /// yadda blah, create DAO as appropriate 
     return new Dao<TEntity, Integer>(); 
    } 
} 

public class Test { 
    public static void main(String[] args) { 
     // Pass the class literal for what you want TEntity to be as a parameter 
     Dao<Account, Integer> dao = DA.getDao(Account.class); 
    } 
} 
+2

Почему это так? Компилятор знает, что такое тип T. Зачем передавать другой параметр? В C# вы можете использовать 'typeof (T)' и не нуждаетесь в этом лишнем бесполезном параметре. –

+0

@GregEnnis ** Абсолютная принципиальная разница между реализацией дженериков Java и C# заключается в том, что в Java 'typeof (T)' не существует. Java сознательно, в интересах обратной совместимости, генерирует код для общего метода после выполнения стирания типа. Компилятор знает только, что означает 'T' на сайте вызова' getDao() '- эта информация никак не распространяется на этот вызов метода. – millimoose

+0

@GregEnnis Что C# делает по-другому в этой конкретной ситуации, так это то, что она каким-то образом автоматически передает значение * runtime * 'typeof (T)' от вызывающего абонента к вызываемому. (Это может быть сделано путем автоматической вставки параметра «Тип» в этот метод, или он может сделать это, создавая другой код для каждого необходимого экземпляра типа/метода или что-то еще. Механизм не очень важен.) Это, однако, сильно нарушает совместимость - «ненарушенный» код не может вызывать генерируемые API. – millimoose

2

Вы хотите, чтобы ваш класс DA имел два типа (например, <Account, Integer>), но в объявлении вашего класса вы указываете только один тип <T>.Посмотрите на некоторые документы и примеры, такие как эти:

http://en.wikipedia.org/wiki/Generics_in_Java#Generic_class_definitions
http://docs.oracle.com/javase/tutorial/java/generics/index.html

+0

Кажется, он просто хочет, чтобы второй параметр всегда был целым. Я предполагаю, что это тип первичного ключа объекта, в котором Integer или Long - это разумная вещь для жесткого кода в такой утилите. – millimoose

+0

@Inerdial - Правильно! – Mark

-1

Если вам необходимо указать метод, который принимает параметр типа шаблона, шаблон приходит перед типом возвращаемого значения:

<T> void foo(T param) { ... } 
+0

«параметр шаблона» - ужасное имя для этого. Дженерики и шаблоны - это совершенно разные концепции, которые частично перекрывают то, что они достигают. – millimoose

+0

Кроме того, просто добавление параметра типа к методу не будет делать то, что хочет OP. – millimoose

1

Вы должны будете сделать это следующим образом:

public class DA { 
     public static <T> Dao<T,Integer> getDao(Class<T> clazz) throws NamingException, SQLException { 
      Context ctx = new InitialContext(); 
      DataSource dataSource = (DataSource)ctx.lookup("java:comp/env/jdbc/test"); 
      ConnectionSource connectionSource = new DataSourceConnectionSource(dataSource, new MysqlDatabaseType());    
      Dao<T, Integer> accountDao = DaoManager.createDao(connectionSource, clazz); 
      return accountDao; 
     } 
    } 

Также createDao метода будет иметь подпись, как это:

public static <T> Dao<T,Integer> createDao(ConnectionSource source,Class<T> clazz) { 
... 
}