Инстанцирование дженериков вводит в Java

Дубликат: дженерики Java, почему это не будет работать

Дубликат: Инстанцирование универсального класса в Java

Я хотел бы создать объект Типа Дженериков в Java. Предложите, как я могу достигнуть того же.

Примечание: Это может казаться тривиальной проблемой Дженериков. Но я держал пари.. это не. :)

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

public class Abc {
    public T getInstanceOfT() {
       // I want to create an instance of T and return the same.
    }
}
57
задан buræquete 28 November 2017 в 04:02
поделиться

11 ответов

public class Abc<T> {
    public T getInstanceOfT(Class<T> aClass) {
       return aClass.newInstance();
    }
}

Вам нужно будет добавить обработку исключений.

Фактический тип необходимо передать во время выполнения, поскольку он не является частью байтового кода после компиляции, поэтому невозможно узнать его без явного указания.

69
ответ дан 24 November 2019 в 19:29
поделиться
Abc<String> abcInstance = new Abc<String> ();

.. например

-3
ответ дан 24 November 2019 в 19:29
поделиться

Прежде всего, вы не можете получить доступ параметр типа T в статическом основном методе только для нестатических членов класса (в данном случае).

Во-вторых, вы не можете создать экземпляр T , потому что Java реализует универсальные шаблоны с стиранием типа . Почти вся общая информация стирается во время компиляции.

В принципе, вы не можете этого сделать:

T member = new T();

Вот хороший учебник по дженерикам .

3
ответ дан 24 November 2019 в 19:29
поделиться

Я реализовал то же самое, используя следующий подход.

public class Abc<T>
{
   T myvar;

    public T getInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException
    {
        return clazz.newInstance();
    }
}

Я пытался найти лучший способ добиться того же.

Разве это невозможно?

1
ответ дан 24 November 2019 в 19:29
поделиться

Похоже, вы пытаетесь создать класс, который служит точкой входа в ваше приложение в качестве универсального, и это не сработает ... JVM не будет знать, какой тип предполагается использовать, когда он создается при запуске приложения.

Однако, если бы это был более общий случай, то вы искали бы что-то вроде:

public MyGeneric<MyChoiceOfType> getMeAGenericObject(){
   return new MyGeneric<MyChoiceOfType>();
}

или, возможно,:

MyGeneric<String> objMyObject = new MyGeneric<String>();
0
ответ дан 24 November 2019 в 19:29
поделиться

В опубликованном вами коде невозможно создать экземпляр T , так как вы не знаете, что это за тип:

public class Abc<T>
{
       public T getInstanceOfT()
       {
           // There is no way to create an instance of T here
           // since we don't know its type
       }
} 

Конечно, это возможно, если у вас есть ссылка на ] Class и T имеет конструктор по умолчанию, просто вызовите newInstance () для объекта Class .

Если вы создаете подкласс Abc , вы даже можете обойти проблему стирания типа и вам не придется передавать какие-либо ссылки Class вокруг:

import java.lang.reflect.ParameterizedType;

public class Abc<T>
{
    T getInstanceOfT()
    {
        ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass();
        Class<T> type = (Class<T>) superClass.getActualTypeArguments()[0];
        try
        {
            return type.newInstance();
        }
        catch (Exception e)
        {
            // Oops, no default constructor
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args)
    {
        String instance = new SubClass().getInstanceOfT();
        System.out.println(instance.getClass());
    }
}

class SubClass
    extends Abc<String>
{
}
26
ответ дан 24 November 2019 в 19:29
поделиться

Кажется, вы не понимаете, как работают Generics. Вы можете посмотреть http: //java.sun .com / j2se / 1.5.0 / docs / guide / language / generics.html В основном то, что вы могли бы сделать, это что-то вроде

public class Abc<T>
{
  T someGenericThing;
  public Abc(){}
  public T getSomeGenericThing()
  {
     return someGenericThing;
  }

  public static void main(String[] args)
  {
     // create an instance of "Abc of String"
        Abc<String> stringAbc = new Abc<String>();
        String test = stringAbc.getSomeGenericThing();
  }

} 
2
ответ дан 24 November 2019 в 19:29
поделиться

Вам нужно получить информацию о типе статически. Попробуйте это:

public class Abc<T> {
    private Class<T> clazz;

    public Abc(Class<T> clazz) {
        this.clazz = clazz;
    }

    public T getInstanceOfT()
            throws InstantiationException, IllegalAccessException {
        return clazz.newInstance();
    }
}

Используйте это так:

        Abc<String> abc = new Abc<String>(String.class);
        abc.getInstanceOfT();

В зависимости от ваших потребностей, вы можете захотеть использовать Class вместо этого.

5
ответ дан 24 November 2019 в 19:29
поделиться

Единственный способ заставить его работать - использовать Reified Generics . И это не поддерживается в Java (пока? Это было запланировано для Java 7, но было отложено). В C #, например, это поддерживается при условии, что T имеет конструктор по умолчанию . Вы даже можете получить тип среды выполнения с помощью typeof (T) и получить конструкторы с помощью Type.GetConstructor () . Я не использую C #, поэтому синтаксис может быть недопустимым, но примерно он выглядит следующим образом:

public class Foo<T> where T:new() {
    public void foo() {
        T t = new T();
    }
}

Лучшее «обходное решение» для этого в Java - передать вместо этого Class в качестве аргумента метода как уже указывалось в нескольких ответах.

4
ответ дан 24 November 2019 в 19:29
поделиться

То, что вы написали, не имеет никакого смысла, дженерики в Java предназначены для добавления функциональности параметрического полиморфизма к объектам.

Что это значит? Это означает, что вы хотите оставить неопределенными некоторые переменные типа ваших классов, чтобы иметь возможность использовать ваши классы с множеством различных типов.

Но ваша переменная типа T является атрибутом, который разрешается во время выполнения, компилятор Java скомпилирует ваш класс, проверяя безопасность типов, не пытаясь узнать, что это за объект T , поэтому он не может позволить вам использовать переменную типа в статическом методе. Тип связан с экземпляром объекта во время выполнения, в то время как public void static main (..) связан с определением класса и в этой области T ничего не означает .

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

class SandBox
{
  public static <T> void myMethod()
  {
     T foobar;
  }
}

это работает, но, конечно, не с методом main , поскольку нет способа вызвать его обычным способом.

РЕДАКТИРОВАТЬ : Проблема в том, что из-за стирания типа только один общий класс компилируется и передается JVM. Средство проверки типов просто проверяет безопасность кода, а затем, поскольку она доказала, что вся общая информация отбрасывается.

Чтобы создать экземпляр T , вам необходимо знать тип T , но это может быть много типов одновременно, поэтому одно решение требует минимального отражения. использовать Class для создания экземпляров новых объектов:

public class SandBox<T>
{
    Class<T> reference;

    SandBox(Class<T> classRef)
    {
        reference = classRef;
    }

    public T getNewInstance()
    {
        try
        {
            return reference.newInstance();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args)
    {
        SandBox<String> t = new SandBox<String>(String.class);

        System.out.println(t.getNewInstance().getClass().getName());
    }
}

Конечно, это означает, что тип, который вы хотите создать:

  • не является примитивным типом
  • , он имеет конструктор по умолчанию

] Чтобы работать с различными типами конструкторов, вам нужно глубже изучить рефлексию.

14
ответ дан 24 November 2019 в 19:29
поделиться

Обходной путь стирания типа

Вдохновленный ответом @martin , я написал вспомогательный класс, который позволяет мне обойти проблему стирания типа. Используя этот класс (и небольшой уродливый трюк), я могу создать новый экземпляр из типа шаблона:

public abstract class C_TestClass<T > {
    T createTemplateInstance() {
        return C_GenericsHelper.createTemplateInstance( this, 0 );
    }

    public static void main( String[] args ) {
        ArrayList<String > list = 
            new C_TestClass<ArrayList<String > >(){}.createTemplateInstance();
    }
}

Уродливый трюк состоит в том, чтобы сделать класс абстрактным , чтобы пользователь класса вынужден подтипировать его. Здесь я создаю подклассы, добавляя {} после вызова конструктора. Это определяет новый анонимный класс и создает его экземпляр.

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


public class C_GenericsHelper {
    /**
     * @param object instance of a class that is a subclass of a generic class
     * @param index index of the generic type that should be instantiated
     * @return new instance of T (created by calling the default constructor)
     * @throws RuntimeException if T has no accessible default constructor
     */
    @SuppressWarnings( "unchecked" )
    public static <T> T createTemplateInstance( Object object, int index ) {
        ParameterizedType superClass = 
            (ParameterizedType )object.getClass().getGenericSuperclass();
        Type type = superClass.getActualTypeArguments()[ index ];
        Class<T > instanceType;
        if( type instanceof ParameterizedType ) {
            instanceType = (Class<T > )( (ParameterizedType )type ).getRawType();
        }
        else {
            instanceType = (Class<T > )type;
        }
        try {
            return instanceType.newInstance();
        }
        catch( Exception e ) {
            throw new RuntimeException( e );
        }
    }
}
1
ответ дан 24 November 2019 в 19:29
поделиться
Другие вопросы по тегам:

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