Java에서 제네릭 유형 인스턴스화
Java에서 Generics Type의 개체를 만들고 싶습니다. 내가 어떻게 똑같이 얻을 수 있는지 제안하십시오.
참고 : 이것은 사소한 Generics 문제로 보일 수 있습니다. 하지만 .. 아니에요. :)
클래스 선언이 다음과 같다고 가정합니다.
public class Abc<T> {
public T getInstanceOfT() {
// I want to create an instance of T and return the same.
}
}
public class Abc<T> {
public T getInstanceOfT(Class<T> aClass) {
return aClass.newInstance();
}
}
예외 처리를 추가해야합니다.
어떤 방식으로 제공되지 않는 방법이 없습니다.
게시 한 코드에서는 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>
하고 T
기본 생성자 가 방금 전화 newInstance()
온 Class
수업입니다.
클래스 Abc<T>
를 사용하면 유형 삭제 하위 문제를 사용할 수도 있고 Class<T>
참조 를 필요가 없습니다 .
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>
{
}
당신이 동의하지 않는다 . 자바의 제네릭 은 착색 에 파라 메다 형성 의 기능을 추가하기 위한 것입니다.
무슨 뜻이에요? 이는 클래스의 일부 유형 변수 를 결정하지 않은 상태로 유지 하여 다양한 유형의 클래스를 사용할 수 있음을 의미합니다.
그러나 유형 변수 T
는 실행에 해결되는 속성입니다. 자바는 어떤 종류 컴파일러의 object-인지 줄 알지 않고 유형 안전성을 증명하는 클래스를 컴파일 T
하므로 정적 메서드에서 유형 변수 를 사용하는 [해석] 불가능합니다. . 형식은 개체의 실행 인스턴스에 public void static main(..)
연결되고 클래스 정의에 연결되어 있고 해당 범위에서 T
의미가 없습니다.
메서드 내 정적 에서 형식 변수 를 사용 하려면 메서드를 제네릭으로 선언해야 우리합니다 (이는 템플릿 클래스의 설명 된 형식 변수 가 클래스가 아닌 런타임 인스턴스 와 관련 이 있기 때문입니다 ).
class SandBox
{
public static <T> void myMethod()
{
T foobar;
}
}
이 작동하지만 main
일반적인 방식으로 호출 할 수있는 방법이 없기 때문에 물론 메서드를 사용하지 않습니다 .
편집 :는 문제 유형 삭제로 인해 하나의 또는 일반 클래스가 컴파일되어 JVM에 전달된다는 것입니다. 유형 검사기는 코드가 안전한지 확인한 다음 모든 종류의 일반 정보 가 폐기 된다는 것을 증명 합니다.
하려면 인스턴스화 T
의 유형을 알아야 T
하지만 동시에 여러 유형이 될 수 있으므로 최소한의 리플렉션 만 필요한 솔루션 중 하나는 Class<T>
새 object-를 인스턴스화하는 데 사용 하는을 구석으로입니다.
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());
}
}
물론 이것은 인스턴스화하려는 유형을 의미합니다.
- 기본 유형이 아닙니다.
- 기본 생성자가 있습니다.
다른 종류의 생성자로 작동 예상 더 깊이 리플렉션해야합니다.
유형 정보를 정적으로 가져와야합니다. 이 시도 :
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<? extends T>
대신 사용할 수 있습니다 .
작동하도록하는 유일한 방법은 Reified Generics 를 사용하는 것입니다 . 그리고 이것은 자바에서 지원되지 않습니다 (아직 자바 7 용 으로 계획 되었지만 연기되었습니다). 예를 들어 C #에서는 기본 생성자 T
가 있다고 가정하여 지원됩니다 . 으로 가동 유형을 가져오고 생성 할 수도 있습니다. C #을 사용하지 않을 구문이 유효하지 않을 수 있습니다.typeof(T)
Type.GetConstructor()
public class Foo<T> where T:new() {
public void foo() {
T t = new T();
}
}
Java에서 이에 대한 가장 좋은 "해결 방법"은 Class<T>
이미 여러 답변이 지적한 대신 메소드 인수 를 전달하는 것입니다.
우선 T
, 정적이 아닌 클래스 멤버 (이 경우) 정적 정적 기본 메소드 의 형식 변수 에 액세스 할 수 없습니다 .
둘째, T
Java가 Type Erasure로 제네릭을 구현하기 때문에 인스턴스화 할 수 없습니다 . 거의 모든 일반 정보는 시간에 지워집니다.
기본적으로 다음과 같이 할 수 없습니다.
T member = new T();
여기 제네릭 에 대한 멋진 튜토리얼이 있습니다 .
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();
}
}
다음 접근 방식을 사용하여 동일하게 구현했습니다.
public class Abc<T>
{
T myvar;
public T getInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException
{
return clazz.newInstance();
}
}
나는 더 나은 방법을 구축하고 노력했다.
가능하지 않나요?
유형 삭제 해결 방법
@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();
}
}
여기서 추악한 트릭은 클래스를 만들어 클래스 abstract
의 사용자가 강제로 하위 유형을 지정하도록하는 것입니다. 여기 {}
에서는 생성자에 대한 호출 뒤에 추가하여 서브 클래 싱합니다 . 이것은 새로운 익명 클래스를 정의하고 그 인스턴스를 생성합니다.
제네릭 클래스가 구체적인 템플릿 유형으로 하위 유형이 지정되면 템플릿 유형을 검색 할 수 있습니다.
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 );
}
}
}
응용 프로그램에 대한 진입 점 역할을하는 클래스를 제네릭으로 생성하려고하는데 작동하지 않는 것 같습니다. JVM은 다음과 같이 인스턴스화 될 때 어떤 유형을 사용해야하는지 알지 못합니다. 응용 프로그램을 시작합니다.
그러나 이것이 더 일반적인 경우라면 다음과 같은 것을 찾고 있습니다.
public MyGeneric<MyChoiceOfType> getMeAGenericObject(){
return new MyGeneric<MyChoiceOfType>();
}
또는 아마도 :
MyGeneric<String> objMyObject = new MyGeneric<String>();
정말로해야 할 때이 문제를 해결하는 방법이 있습니다.
다음은 제가 매우 유용하다고 생각하는 변환 방법의 예입니다. 제네릭의 구체적인 클래스를 결정하는 한 가지 방법을 제공합니다.
이 메서드는 개체 컬렉션을 입력으로 받아들이고 각 요소가 입력 컬렉션의 각 개체에 대해 필드 getter를 호출 한 결과 인 배열을 반환합니다. 예를 들어, a가 List<People>
있고 String[]
모든 사람의 성을 포함하는를 원한다고 가정합니다 .
getter가 반환하는 필드 값의 유형은 generic에 의해 지정되며 반환 값을 저장하기 위해 E
유형의 배열을 인스턴스화해야 E[]
합니다.
메서드 자체는 약간 못 생겼지 만이를 사용하는 코드는 훨씬 더 깔끔 할 수 있습니다.
이 기술은 입력 인수의 어딘가에 유형이 반환 유형과 일치하는 객체가있을 때만 작동하며이를 결정적으로 파악할 수 있습니다. 입력 매개 변수 (또는 하위 객체)의 구체적인 클래스가 제네릭에 대해 아무 것도 알려주지 않으면이 기술은 작동하지 않습니다.
public <E> E[] array (Collection c) {
if (c == null) return null;
if (c.isEmpty()) return (E[]) EMPTY_OBJECT_ARRAY;
final List<E> collect = (List<E>) CollectionUtils.collect(c, this);
final Class<E> elementType = (Class<E>) ReflectionUtil.getterType(c.iterator().next(), field);
return collect.toArray((E[]) Array.newInstance(elementType, collect.size()));
}
Abc<String> abcInstance = new Abc<String> ();
.. 예 :
참조 URL : https://stackoverflow.com/questions/2434041/instantiating-generics-type-in-java
'ProgramingTip' 카테고리의 다른 글
MySQL에서 누계 계산 (0) | 2020.12.29 |
---|---|
읽기 메모리 장벽과 인증서를 이해하는 방법 (0) | 2020.12.29 |
증가 / 누름시 ImageButton의 축적을 변경하는 방법 (0) | 2020.12.29 |
예외 처리를 위해 printStackTrace ()를 사용하는 것이 나쁜 생각입니까? (0) | 2020.12.29 |
메뉴에 추가하지 않고 WordPress (0) | 2020.12.29 |