Один из вариантов - передать Bar.class
(или любой другой тип, который вас интересует, любым способом указания соответствующей ссылки Class<T>
) и сохранить это значение как поле:
public class Test
{
public static void main(String [] args)
throws Exception // Just for simplicity!
{
Generic<Bar> x = new Generic<Bar>(Bar.class);
Bar y = x.buildOne();
}
}
public class Generic<T>
{
private Class<T> clazz;
public Generic(Class<T> clazz)
{
this.clazz = clazz;
}
public T buildOne() throws InstantiationException,
IllegalAccessException
{
return clazz.newInstance();
}
}
public class Bar
{
public Bar()
{
System.out.println("Constructing");
}
}
Другой вариант - иметь «фабричный» интерфейс, и вы передаете фабрику конструктору универсального класса. Это более гибко, и вам не нужно беспокоиться об исключениях отражения.
Для Java 8 ....
В https://stackoverflow.com/a/36315051/2648077 есть хорошее решение.
Используется функциональный интерфейс Java 8 Supplier
Из https://stackoverflow.com/a/2434094/848072 . Для класса T вам нужен конструктор по умолчанию.
import java.lang.reflect.ParameterizedType;
class Foo {
public bar() {
ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass();
Class type = (Class) superClass.getActualTypeArguments()[0];
try {
T t = type.newInstance();
//Do whatever with t
} catch (Exception e) {
// Oops, no default constructor
throw new RuntimeException(e);
}
}
}
<T>
есть <Bar>
), то рефлексивно создание экземпляра Bar с Class<Bar> token = Bar.class;
и Bar newBar = token.newInstance();
представляется мне гораздо менее подробным.
– scottb
15 August 2013 в 21:25
Мне действительно нужно создать экземпляр T в Foo, используя конструктор без параметров
blockquote>. Простой ответ: «вы не можете этого сделать». java использует стирание типа для импликации генериков, которые
Как можно работать с ограничениями Java?
blockquote>Один из способов (могут быть другие) - передать объект, который вы передал бы экземпляр T в конструктор
Foo<T>
. Или у вас может быть методsetBar(T theInstanceofT);
, чтобы получить ваш T вместо создания экземпляра в своем классе.
Вот довольно надуманный способ сделать это без явного использования аргумента конструктора. Вам необходимо расширить параметризованный абстрактный класс.
public class Test {
public static void main(String [] args) throws Exception {
Generic g = new Generic();
g.initParameter();
}
}
import java.lang.reflect.ParameterizedType;
public abstract class GenericAbstract<T extends Foo> {
protected T parameter;
@SuppressWarnings("unchecked")
void initParameter() throws Exception, ClassNotFoundException,
InstantiationException {
// Get the class name of this instance's type.
ParameterizedType pt
= (ParameterizedType) getClass().getGenericSuperclass();
// You may need this split or not, use logging to check
String parameterClassName
= pt.getActualTypeArguments()[0].toString().split("\\s")[1];
// Instantiate the Parameter and initialize it.
parameter = (T) Class.forName(parameterClassName).newInstance();
}
}
public class Generic extends GenericAbstract<Foo> {
}
public class Foo {
public Foo() {
System.out.println("Foo constructor...");
}
}
T toArray()
!
– Aquarius Power
17 November 2016 в 20:10
new ArrayList<Foo>(){}
не знаю, почему ...
– Aquarius Power
18 November 2016 в 00:12
Я мог бы сделать это в JUnit Test Setup.
Я хотел протестировать фасад Hibernate, поэтому я искал общий способ сделать это. Обратите внимание, что фасад также реализует общий интерфейс. Здесь T - класс базы данных, а U - первичный ключ. Ifacade<T,U>
- это фасад для доступа к объекту базы данных T с первичным ключом U.
public abstract class GenericJPAController<T, U, C extends IFacade<T,U>>
{
protected static EntityManagerFactory emf;
/* The properties definition is straightforward*/
protected T testObject;
protected C facadeManager;
@BeforeClass
public static void setUpClass() {
try {
emf = Persistence.createEntityManagerFactory("my entity manager factory");
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory object." + ex);
throw new ExceptionInInitializerError(ex);
}
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
/* Get the class name*/
String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[2].getTypeName();
/* Create the instance */
try {
facadeManager = (C) Class.forName(className).newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
Logger.getLogger(GenericJPAController.class.getName()).log(Level.SEVERE, null, ex);
}
createTestObject();
}
@After
public void tearDown() {
}
/**
* Test of testFindTEntities_0args method, of class
* GenericJPAController<T, U, C extends IFacade<T,U>>.
* @throws java.lang.ClassNotFoundException
* @throws java.lang.NoSuchMethodException
* @throws java.lang.InstantiationException
* @throws java.lang.IllegalAccessException
*/
@Test
public void testFindTEntities_0args() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException {
/* Example of instance usage. Even intellisense (NetBeans) works here!*/
try {
List<T> lista = (List<T>) facadeManager.findAllEntities();
lista.stream().forEach((ct) -> {
System.out.println("Find all: " + stringReport());
});
} catch (Throwable ex) {
System.err.println("Failed to access object." + ex);
throw new ExceptionInInitializerError(ex);
}
}
/**
*
* @return
*/
public abstract String stringReport();
protected abstract T createTestObject();
protected abstract T editTestObject();
protected abstract U getTextObjectIndex();
}
Быстрое решение, которое сработало для меня. Я вижу, что для этого уже есть ответ, и это может быть даже не лучшим способом. Кроме того, для моего решения вам понадобится Gson .
Однако я столкнулся с ситуацией, когда мне нужно было создать экземпляр универсального класса типа java.lang.reflect.Type
.
Следующий код создаст экземпляр класса, который вы хотите, с нулевыми переменными экземпляра.
T object = new Gson().fromJson("{}", myKnownType);
Где myKnownType
известно заранее и получено через TypeToken.getType()
.
Теперь вы можете установить соответствующие свойства для этого объекта. Опять же, это может быть не лучший способ сделать это, но он работает как быстрое решение, если это то, что вам нужно.
Дженерики в Java, как правило, более мощные, чем в C #.
Если вы хотите построить объект, но без аппаратного конструктора / статического метода, используйте абстрактную фабрику. Вы должны иметь возможность находить подробную информацию и учебные пособия по шаблону абстрактной фабрики в любой базовой книге шаблонов дизайна, введении в ООП или во всех средах. Здесь не стоит дублировать код, кроме упоминания о том, что синтаксис закрытия Java засасывает.
IIRC, C # имеет специальный случай для указания, что общий тип имеет конструктор no-args. Эта нерегулярность, по определению, предполагает, что клиентский код хочет использовать эту конкретную форму построения и поощряет изменчивость.
Использование отражения для этого просто неверно. Генераторы в Java - это функция статического ввода времени компиляции. Попытки использовать их во время выполнения - это четкое указание на то, что что-то происходит не так. Отражение вызывает подробный код, ошибки выполнения, необработанные зависимости и уязвимости безопасности. (Class.forName
особенно злой.)
И это реализация Factory, поскольку предложил Jon Skeet :
interface Factory<T> {
T factory();
}
class Araba {
//static inner class for Factory<T> implementation
public static class ArabaFactory implements Factory<Araba> {
public Araba factory() {
return new Araba();
}
}
public String toString() { return "Abubeee"; }
}
class Generic<T> {
private T var;
Generic(Factory<T> fact) {
System.out.println("Constructor with Factory<T> parameter");
var = fact.factory();
}
Generic(T var) {
System.out.println("Constructor with T parameter");
this.var = var;
}
T get() { return var; }
}
public class Main {
public static void main(String[] string) {
Generic<Araba> gen = new Generic<Araba>(new Araba.ArabaFactory());
System.out.print(gen.get());
}
}
Выход:
Constructor with Factory<T> parameter
Abubeee
<T>
есть <Bar>
), то рефлексивно создание экземпляра Bar с Class<Bar> token = Bar.class;
и Bar newBar = token.newInstance();
представляется мне гораздо менее подробным.
– scottb
15 August 2013 в 21:25
new Foo()
в качестве аргумента? – fastcodejava 12 March 2010 в 13:04