[java] java : 한 유형에서 다른 유형으로 변수를 동적으로 캐스팅하려면 어떻게해야합니까?

Java 변수에 대한 동적 캐스팅을 수행하고 싶습니다. 캐스팅 유형은 다른 변수에 저장됩니다.

이것은 일반 캐스팅입니다.

 String a = (String) 5;

이것이 내가 원하는거야:

 String theType = 'String';
 String a = (theType) 5;

이것이 가능합니까? 그렇다면 어떻게해야합니까? 감사!

최신 정보

HashMap받은 클래스를 채우려 고합니다 .

이것은 생성자입니다.

public ConnectParams(HashMap<String,Object> obj) {

    for (Map.Entry<String, Object> entry : obj.entrySet()) {
        try {
            Field f =  this.getClass().getField(entry.getKey());
            f.set(this, entry.getValue()); /* <= CASTING PROBLEM */
        } catch (NoSuchFieldException ex) {
            log.error("did not find field '" + entry.getKey() + '"');
        } catch (IllegalAccessException ex) {
            log.error(ex.getMessage());
        }
    }

}

여기서 문제는 클래스의 일부 변수가 유형 Double이고 숫자 3이 수신되면 Integer유형 문제가 있다는 것입니다.



답변

업데이트와 관련하여 Java에서이 문제를 해결하는 유일한 방법은 많은 ifelseinstanceof표현식으로 모든 경우를 다루는 코드를 작성하는 것입니다 . 당신이 시도하는 것은 마치 동적 언어로 프로그래밍하는 데 익숙한 것처럼 보입니다. 정적 언어에서는 시도하는 것이 거의 불가능하며 시도하려는 작업에 대해 완전히 다른 접근 방식을 선택할 것입니다. 정적 언어는 동적 언어만큼 유연하지 않습니다. 🙂

Java 모범 사례의 좋은 예는 BalusC답변 (예 🙂ObjectConverterAndreas_D답변 (예 : Adapter아래)입니다.


말이 안 돼요

String a = (theType) 5;

의 유형 a은 정적으로 바인딩되어 있으므로이 정적 유형에 String대한 동적 캐스트를 갖는 것은 의미가 없습니다.

추신 : 예제의 첫 번째 줄은 다음과 같이 작성할 수 Class<String> stringClass = String.class;있지만 여전히 stringClass변수를 캐스팅 하는 데 사용할 수 없습니다 .


답변

Reflection을 사용하여 가능합니다.

Object something = "something";
String theType = "java.lang.String";
Class<?> theClass = Class.forName(theType);
Object obj = theClass.cast(something);

그러나 결과 객체는 Object유형 의 변수에 저장되어야하므로 그다지 의미가 없습니다 . 주어진 클래스의 변수가 필요한 경우 해당 클래스로 캐스트 할 수 있습니다.

Number예를 들어 , 주어진 클래스를 얻으려면 :

Object something = new Integer(123);
String theType = "java.lang.Number";
Class<? extends Number> theClass = Class.forName(theType).asSubclass(Number.class);
Number obj = theClass.cast(something);

하지만 여전히 그렇게 할 필요가 없습니다 Number..

개체를 캐스팅해도 아무것도 변경되지 않습니다. 그것은 단지 인 방법 컴파일러 취급 그것.
이와 같은 작업을 수행하는 유일한 이유는 객체가 주어진 클래스 또는 그 하위 클래스의 인스턴스인지 확인하는 것입니다. 그러나 instanceof또는 사용하는 것이 더 좋습니다 Class.isInstance().

최신 정보

마지막에 따라 업데이트가 진짜 문제는 당신이이 때문이다 Integer에서 HashMapA를 할당해야합니다 Double. 이 경우 할 수있는 일은 필드의 유형을 확인하고 다음 xxxValue()방법을 사용하는 것 입니다.Number

...
Field f =  this.getClass().getField(entry.getKey());
Object value = entry.getValue();
if (Integer.class.isAssignableFrom(f.getType())) {
    value = Integer.valueOf(((Number) entry.getValue()).intValue());
} else if (Double.class.isAssignableFrom(f.getType())) {
    value = Double.valueOf(((Number) entry.getValue()).doubleValue());
} // other cases as needed (Long, Float, ...)
f.set(this, value);
...

(내가에서 잘못된 유형을 갖는 아이디어를 좋아하는지 확실하지 않음 Map)


답변

이를 위해 일종의 작성이 필요합니다 ObjectConverter. 변환하려는 객체가 있고 변환 할 대상 클래스를 알고있는 경우이 작업을 수행 할 수 있습니다. 이 특별한 경우에는 Field#getDeclaringClass().

당신은 찾을 수 있습니다 여기에 이러한 예를 ObjectConverter. 기본 아이디어를 제공해야합니다. 더 많은 변환 가능성을 원한다면 원하는 인수와 반환 유형을 사용하여 더 많은 메서드를 추가하십시오.


답변

Class.cast()제공된 매개 변수를 보유한 클래스 인스턴스의 유형으로 동적으로 캐스트 하는 메소드를 사용하여이를 수행 할 수 있습니다. 특정 필드의 클래스 인스턴스를 얻으려면 getType()해당 필드에서 메서드 를 사용합니다 . 아래에 예제를 주었지만 모든 오류 처리를 생략하고 수정하지 않고 사용해서는 안됩니다.

public class Test {

    public String var1;
    public Integer var2;
}

public class Main {

    public static void main(String[] args) throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("var1", "test");
        map.put("var2", 1);

        Test t = new Test();

        for (Map.Entry<String, Object> entry : map.entrySet()) {
            Field f = Test.class.getField(entry.getKey());

            f.set(t, f.getType().cast(entry.getValue()));
        }

        System.out.println(t.var1);
        System.out.println(t.var2);
    }
}


답변

아래와 같이 간단한 castMethod를 작성할 수 있습니다.

private <T> T castObject(Class<T> clazz, Object object) {
  return (T) object;
}

귀하의 방법에서 다음과 같이 사용해야합니다.

public ConnectParams(HashMap<String,Object> object) {

for (Map.Entry<String, Object> entry : object.entrySet()) {
    try {
        Field f =  this.getClass().getField(entry.getKey());
        f.set(this, castObject(entry.getValue().getClass(), entry.getValue()); /* <= CASTING PROBLEM */
    } catch (NoSuchFieldException ex) {
        log.error("did not find field '" + entry.getKey() + '"');
    } catch (IllegalAccessException ex) {
        log.error(ex.getMessage());
    }
}

}


답변

작동하며 접근 방식에 대한 일반적인 패턴 인 어댑터 패턴도 있습니다. 그러나 물론 (1) 자바 프리미티브를 객체로 캐스팅하는 데는 작동하지 않으며 (2) 클래스는 적응 가능해야합니다 (보통 사용자 정의 인터페이스를 구현하여).

이 패턴으로 다음과 같이 할 수 있습니다.

Wolf bigBadWolf = new Wolf();
Sheep sheep = (Sheep) bigBadWolf.getAdapter(Sheep.class);

Wolf 클래스의 getAdapter 메소드 :

public Object getAdapter(Class clazz) {
  if (clazz.equals(Sheep.class)) {
    // return a Sheep implementation
    return getWolfDressedAsSheep(this);
  }

  if (clazz.equals(String.class)) {
    // return a String
    return this.getName();
  }

  return null; // not adaptable
}

당신에게 특별한 아이디어는 불가능합니다. 캐스팅에 문자열 값을 사용할 수 없습니다.


답변

당신의 문제는 “동적 캐스팅”의 부족이 아닙니다. 주조 Integer로하는 것은 Double전혀 불가능하다. Java에 한 유형의 객체, 호환되지 않을 수있는 유형의 필드를 제공하고 유형간에 변환하는 방법을 자동으로 파악하도록하는 것 같습니다.

이런 종류의 것은 Java 및 IMO와 같은 강력한 유형의 언어에 대한 혐오입니다.

실제로 무엇을하려고합니까? 반사의 모든 사용은 꽤 비린내처럼 보입니다.