2012-03-07 2 views
0

generics를 사용하여 Java에서 클래스 인스턴스를 어떻게 인스턴스화 할 수 있습니까?제네릭으로 java 클래스 인스턴스를 어떻게 인스턴스화 할 수 있습니까?

XML 파일에서 데이터를 읽은 다음 개체를 인스턴스화하여 개체의 다른 속성 (XML 파일에서 읽음)을 개체에 추가하려고합니다. 나는 (클래스 메소드 이름을 읽고 setter를 찾을 필요가 없도록) 생성자의 모든 값을 가진 객체를 인스턴스화하는 것이 가장 쉬운 방법이라고 생각했다. T obj = new Object()하지만 객체 클래스에게 조언을

private static final boolean string_field = true; 

    private static <T> T getObject(Element e, String[] fieldNames, boolean[] fieldTypes) { 
     Object[] values = new Object[fieldNames.length]; 
     for (int i=0; i<fieldNames.length; i++) { 
      values[i] = (fieldTypes[i]==string_field)? getStringValue(e, fieldNames[i]) 
        : getIntegerValue(e, fieldNames[i]); 
     } 
     return new T(values); 
    } 

감사를 얻을 : 나는 이런 식으로 뭔가를 할 노력하고있어

그래서 내가 좋아하는 뭔가를해야합니다.

는 편집 :

이 내 업데이트 된 코드 (테스트되지 않은)입니다 : 여러분 중 몇몇은 내가 할 노력하고있어 이해할 수 있도록

public static <T> List<T> populateObjectList(Document xmlDoc, String tagName, 
      Class clazz, String[] fieldNames, Class[] fieldTypes) { 
     List<T> objList = new ArrayList<T>(); 
     NodeList nl = xmlDoc.getElementsByTagName(tagName); 
     if (nl!=null && nl.getLength()>0) { 
      for (int i=0; i<nl.getLength(); i++) { 
       Element e = (Element) nl.item(i); 
       T t; 
       try { 
        t = getObject(e, clazz, fieldNames, fieldTypes); 
        objList.add(t); 
       } catch (InstantiationException ex) { 
       } catch (IllegalAccessException ex) { 
       } catch (IllegalArgumentException ex) { 
       } catch (InvocationTargetException ex) { 
       } catch (NoSuchMethodException ex) { 
       } 
      } 
     } 
     return objList; 
    } 

    private static <T> T getObject(Element e, Class clazz, String[] fieldNames, Class[] fieldTypes) 
      throws InstantiationException, IllegalAccessException, IllegalArgumentException, 
      InvocationTargetException, NoSuchMethodException { 
     Object[] initargs = new Object[fieldNames.length]; 
     for (int i=0; i<fieldNames.length; i++) { 
      initargs[i] = (fieldTypes[i].getName().equals("int"))? 
       getIntegerValue(e, fieldNames[i]) 
       : getStringValue(e, fieldNames[i]); 
     } 
     return (T) clazz.getConstructor(fieldTypes).newInstance(initargs); 
    } 

나는 이것을 기록했다.

모두에게 감사드립니다.

+0

소거에 문제가있을 수 있습니다 ...? – Steven

+0

이 코드가 잘못되었다는 것을 알고 있습니다. 나는 그것을 달성하기 위해 무엇을 설명하는지 설명했습니다. 값 배열에 매개 변수 값이있는 T 유형의 객체를 인스턴스화하려고합니다. – Ozzy

+0

@ user1031312 : 'T'가 어떤 유형인지 알고 계십니까? 어떻게 든 '요소'에 따라 결정됩니까? 그렇다면 클래스에 요소 이름을 매핑하는'Map >'이 당신이 원하는 것이다. Taymon의 대답에 따라 객체를 만들 수 있습니다. 또는, 아마도'getObject()'메소드는'Class '을 인수로 취해야한다. –

답변

4

제네릭 형식을 인스턴스화 할 수 없습니다. Java 제네릭은 타입 삭제라는 불쾌한 기능을 가지고 있습니다.은 기본적으로 JVM이 런타임시 일반 클래스 나 메소드에 어떤 유형이 사용되었는지 알지 못한다는 것을 의미합니다. 이는 콜렉션과 같은 일반 클래스의 사전 제네릭 버전과의 하위 호환성을위한 것입니다. 클래스가 사용하는 생성자가없는 경우는 예외가 발생합니다

Class<?>[] paramTypes = new Class[values.length]; 
for (int i = 0; i < paramTypes.length; i++) { 
    paramTypes[i] = values[i].getClass(); 
} 
return clazz.getConstructor(paramTypes).newInstance(values); 

:

은 당신이 할 수있는 일은 다음이와 방법의 끝을 교체하여 매개 변수 목록에 Class<T> clazz를 추가입니다 인수의 올바른 유형과 수를 올바른 순서로 지정하십시오.

주의 : 생성자의 매개 변수 유형은 정확히 개체 유형과 같은 경우이에만 작동합니다. 예를 들어 values{ "Hello", new Integer(2) }으로 구성된 경우 SomeClass(Object, Object) 인 서명이 아닌 생성자가 SomeClass(String, Integer) 인 생성자 만 찾습니다.

+0

고마워요, 예를 들어 주시거나 리플렉션을 사용하여 생성자를 호출하는 방법을 올바른 방향으로 가르쳐 주시겠습니까? – Ozzy

+0

런타임시 유형의 클래스를 가져올 수 있습니다. 단지 불필요하게 복잡합니다. – Terraego

+0

특이성을 위해 편집 됨. – Taymon

0

정말 문제가 보이지 않습니다. obj.getClass를 사용할 수 없습니까?

+0

무슨 뜻인지 예를 들어 주시겠습니까? 이전에 클래스를 매개 변수로 전달하려고 시도했지만 다른 문제가 생겼습니다. 이'getObject (..., class clazz)'를 실행 한 다음 필드 이름과 필드 형식을 얻으려고했지만 거기에 갇혀서 값을 설정하려는 필드 이름을 쉽게 전달할 수있을 것이라고 생각했습니다. XML 파일 – Ozzy

+0

신경 쓰지 마라. 내가 지금하려고하는 것을 보아라, 나는 단지 여기에있는 객체들의 집합을 반환하는 것이 더 좋다고 생각한다. 또는 단지 두 개의 다른 메소드를 사용한다. 하나는 int의 집합을 반환하고, 하나는 문자열의 집합을 반환한다. . 또 다른 방법은 래퍼 객체 일 것입니다. – Terraego

1

런타임에 T이 실제로 단지 Object이기 때문에 new T()을 수행 할 수 없습니다. 컴파일러는 유형 확인을 위해 제네릭을 사용하지만 (예 : 에 Integer을 넣을 수는 없지만) 제네릭 정보를 버립니다. 모든 인수 유형에 대해 메소드의 컴파일 된 사본이 하나 있으므로 인스턴스화 할 것으로 예상되는 유형을 알 수있는 방법이 없습니다.

자세한 내용은 type erasure을 참조하십시오.

2

T에 단일 Object[] 인수를 취한 생성자가 포함되어 있다는 것을 어떻게 알았습니까? 이 문제를 해결하는 방법은 추상적 인 공장을 통과하는 것입니다.

interface ThingFactory { // Choose an appropriate name. 
    T create(Object[] values); 
} 

private static <T> T getObject(
    ThingFactory<T> factory, Element e, String[] fieldNames, boolean[] fieldTypes 
) { 
    ... 
    return factory.create(values); 
} 

지금 T 심지어 오히려 이상한 Object[] 생성자가되지 않을 수도 있습니다. T은 추상적 인 유형 일 수 있습니다. 팩토리는 인수에 따라 다른 형식을 반환 할 수 있습니다. 때때로 이러한 제품은 캐시 될 수있는 변경 불가능한 객체입니다.

+0

오, IDE에서 매개 변수가 "Object ... initargs"로 나타나고 javadoc이 말하기 때문에 객체 배열이 매개 변수 목록에 대해 varargs와 같은 역할을한다고 생각했습니다. '생성자 객체에 의해 생성 된이 생성자 객체를 사용하여 지정된 초기화 매개 변수를 사용하여 생성자의 선언 클래스의 새 인스턴스를 초기화하십시오. ' – Ozzy

+0

@ user1031312 실제로 필요하지 않으면 반사를 사용하지 않을 것입니다. –

+0

이렇게하면 내 프로세스 속도가 빨라질 수 있습니다. 앞으로 더 많은 시간을 가질 때 변경할 수 있습니다. – Ozzy

관련 문제