자바에서 다운 캐스팅


179

Java에서는 업 캐스팅이 허용되지만 다운 캐스팅은 컴파일 오류를 발생시킵니다.

캐스트를 추가하여 컴파일 오류를 제거 할 수 있지만 런타임시 중단됩니다.

이 경우 Java가 런타임에 실행될 수없는 경우 다운 캐스팅을 허용하는 이유는 무엇입니까?
이 개념에 실용적인 용도가 있습니까?

public class demo {
  public static void main(String a[]) {
      B b = (B) new A(); // compiles with the cast, 
                         // but runtime exception - java.lang.ClassCastException
  }
}

class A {
  public void draw() {
    System.out.println("1");
  }

  public void draw1() {
    System.out.println("2");
  }
}

class B extends A {
  public void draw() {
    System.out.println("3");
  }
  public void draw2() {
    System.out.println("4");
  }
}

9
예제 코드 조각과 오류는 개념을 배우려는 사람들에게 더 나은 질문이 될 것입니다.
Bob Cross

3
Bob의 댓글에 +1 질문은 전혀 명확하지 않습니다.
Jon Skeet

위의 예는 velocityreviews.com/forums/t151266-downcasting-problem.html 에서 가져온 것으로 이미 좋은 답변이 있습니다.
PhiLho

2
@PhiLho-Joel의 주요 의도는 하나의 공통된 우산 아래에서 모든 위대한 질문과 답변을 얻는 것이 었습니다. 질문 / 코드 / 답변이 이미 다른 사이트에 게시되어 있는지는 중요하지 않습니다. 나는 당신이 요점을 얻길 바랍니다. 그렇지 않으면 Joel의 포드 캐스트를 들어보십시오.
전능성

코드 스 니펫이 모두 4 개의 공백으로 들여 쓰기되도록이를 수정하십시오. 서식이 수정됩니다.
슬림

답변:


298

런타임에 성공할 가능성이있는 경우 다운 캐스팅이 허용됩니다.

Object o = getSomeObject(),
String s = (String) o; // this is allowed because o could reference a String

경우에 따라 성공하지 못할 수도 있습니다.

Object o = new Object();
String s = (String) o; // this will fail at runtime, because o doesn't reference a String

캐스트 (이 마지막 것과 같은)가 런타임에 실패하면 a ClassCastException가 발생합니다.

다른 경우에는 작동합니다.

Object o = "a String";
String s = (String) o; // this will work, since o references a String

일부 캐스트는 전혀 성공하지 않기 때문에 컴파일 타임에 허용되지 않습니다.

Integer i = getSomeInteger();
String s = (String) i; // the compiler will not allow this, since i can never reference a String.

Object o = new Object(); String s = (String) o;그것은 나를 위해 잘 작동합니다 .. : O 어떻게?
Asif Mushtaq

@UnKnown :해서는 안됩니다. 실제로 해당 버전을 컴파일하고 실행했는지 다시 확인하고 여전히 재현 할 수있는 경우 별도의 질문 ( SSCCE 사용 )을 게시 하십시오.
Joachim Sauer

@JoachimSauer 그 버전의 의미는 무엇입니까? 나는 자바 8. 사용하고 있습니다
아시프 Mushtaq

1
@UnKnown : 게시 한 코드가 실행되어서는 안된다는 것을 의미합니다 (컴파일하지만 런타임에 예외가 발생합니다). 이 의견은 그것을 디버깅 할 공간이 아닙니다. 별도의 질문을 게시하십시오.
Joachim Sauer

런타임에 캐스팅이 어떻게 실패합니까? 대상 객체 참조를 null로 설정합니까? 예외가 발생합니까?
CygnusX1

17

예제를 사용하면 다음을 수행 할 수 있습니다.

public void doit(A a) {
    if(a instanceof B) {
        // needs to cast to B to access draw2 which isn't present in A
        // note that this is probably not a good OO-design, but that would
        // be out-of-scope for this discussion :)
        ((B)a).draw2();
    }
    a.draw();
}

방금 추상 클래스가 여러 클래스에 의해 확장 될 때 instanceof의 중요성을 배웠고 추상 클래스 유형을 참조하면서 해당 클래스의 독점 메소드를 사용하고 싶었습니다. instanceof를 사용하지 않고 클래스 캐스트 예외가 발생했습니다
Tarun

16

나는 이것이 정적으로 유형이 지정된 모든 언어에 적용된다고 생각합니다.

String s = "some string";
Object o = s; // ok
String x = o; // gives compile-time error, o is not neccessarily a string
String x = (String)o; // ok compile-time, but might give a runtime exception if o is not infact a String

타입 캐스트는 효과적으로 말합니다 : 이것이 캐스트 클래스에 대한 참조라고 가정하고 그대로 사용하십시오. 이제 o가 실제로 는 정수라고 가정하면 o는 의미가 없으며 예기치 않은 결과를 초래하므로 런타임 환경에 무언가 잘못되었음을 알리기 위해 런타임 검사 및 예외가 필요합니다.

실제로는보다 일반적인 클래스에서 작동하는 코드를 작성할 수 있지만 서브 클래스가 무엇인지 알고이를 처리해야하는 경우 서브 클래스로 캐스트 할 수 있습니다. 일반적인 예는 Object.equals ()를 재정의하는 것입니다. 자동차 수업이 있다고 가정합니다.

@Override
boolean equals(Object o) {
    if(!(o instanceof Car)) return false;
    Car other = (Car)o;
    // compare this to other and return
}

나는 진짜라는 단어를 좋아하고 글을 더 명백하게하기 위해 글을 편집 할 것입니다
Charaf JRA

5

제공 한 코드가 런타임에 작동하지 않는 것을 모두 알 수 있습니다. 이는 표현식 new A()결코 유형의 객체가 될 수 없다는 것을 알고 있기 때문 B입니다.

그러나 이것이 컴파일러가 보는 방식이 아닙니다. 컴파일러가 캐스트가 허용되는지 여부를 확인하면 다음과 같이 표시됩니다.

variable_of_type_B = (B)expression_of_type_A;

그리고 다른 사람들이 보여 주듯이, 이런 종류의 캐스트는 완벽하게 합법적입니다. 오른쪽의 표현은 유형의 객체로 매우 잘 평가 될 수 B있습니다. 컴파일러는 것을보고 A하고 B그래서 코드, 캐스트 힘 작업의 "표현"볼 수있는 서브 타입 관계를 가지고있다.

컴파일러는 어떤 객체 유형 이 실제로 어떤 것인지 정확히 알고있을 때 특별한 경우를 고려하지 않습니다 expression_of_type_A. 정적 유형을보고 A동적 유형이 A또는를 A포함한 모든 하위 유형으로 간주합니다 B.


3

이 경우 Java가 런타임에 실행될 수없는 경우 다운 캐스팅을 허용하는 이유는 무엇입니까?

캐스트가 성공할지 여부는 컴파일러가 컴파일 타임에 알 수있는 방법이 없기 때문이라고 생각합니다. 예를 들어, 캐스트가 실패하는 것을 보는 것은 간단하지만 명확하지 않은 다른 시간이 있습니다.

예를 들어, 유형 B, C 및 D가 모두 유형 A를 확장 한 다음 public A getSomeA()임의 생성 된 숫자에 따라 메소드 가 B, C 또는 D의 인스턴스를 리턴한다고 가정하십시오. 컴파일러는이 메서드에서 어떤 정확한 런타임 유형을 반환할지 알 수 없으므로 나중에 결과를로 B캐스팅하면 캐스트가 성공 (또는 실패)하는지 알 수있는 방법이 없습니다. 따라서 컴파일러는 캐스트가 성공할 것이라고 가정해야합니다.


2

@ Original Poster-인라인 주석을 참조하십시오.

public class demo 
{
    public static void main(String a[]) 
    {
        B b = (B) new A(); // compiles with the cast, but runtime exception - java.lang.ClassCastException 
        //- A subclass variable cannot hold a reference to a superclass  variable. so, the above statement will not work.

        //For downcast, what you need is a superclass ref containing a subclass object.
        A superClassRef = new B();//just for the sake of illustration
        B subClassRef = (B)superClassRef; // Valid downcast. 
    }
}

class A 
{
    public void draw() 
    {
        System.out.println("1");
    }

    public void draw1() 
    {
        System.out.println("2");
    }
}

class B extends A 
{
    public void draw() 
    {
        System.out.println("3");
    }

    public void draw2() 
    {
        System.out.println("4");
    }
}

2

다운 캐스트는 업 캐스트 된 오브젝트를 처리 할 때 작동합니다. 업 캐스팅 :

int intValue = 10;
Object objValue = (Object) intvalue;

이제이 objValue변수 int는 캐스트 된 객체가 Integer,

int oldIntValue = (Integer) objValue;
// can be done 

그러나 objValueObject String이기 때문에 캐스트 할 수 없기 때문에 캐스트 할 int수 없습니다 String.


0

다운 캐스팅은이 코드를 항상 사용하는 다음 코드 스 니펫에서 매우 유용합니다. 따라서 다운 캐스팅이 유용하다는 것을 증명합니다.

private static String printAll(LinkedList c)
{
    Object arr[]=c.toArray();
    String list_string="";
    for(int i=0;i<c.size();i++)
    {
        String mn=(String)arr[i];
        list_string+=(mn);
    }
    return list_string;
}

Linked List에 String을 저장합니다. 연결된 목록의 요소를 검색하면 객체가 반환됩니다. 요소를 문자열 (또는 다른 클래스 객체)로 액세스하려면 다운 캐스팅이 도움이됩니다.

Java를 사용하면 잘못된 일을하고 있다는 사실을 신뢰하는 다운 캐스트 코드를 컴파일 할 수 있습니다. 그래도 사람이 실수하면 런타임에 잡 힙니다.


Java에서 제네릭이 아닌 컬렉션을 사용하는 것은 void*C ++ 의 포인터 와 같습니다 . 좋은 생각처럼 들리지 않습니다.
Jezor

0

아래 예를 고려하십시오

public class ClastingDemo {

/**
 * @param args
 */
public static void main(String[] args) {
    AOne obj = new Bone();
    ((Bone) obj).method2();
}
}

class AOne {
public void method1() {
    System.out.println("this is superclass");
}
}


 class Bone extends AOne {

public void method2() {
    System.out.println("this is subclass");
}
}

여기서 우리는 서브 클래스 Bone의 객체를 생성하고 그것을 슈퍼 클래스 AOne 참조에 할당했고 이제 슈퍼 클래스 참조는 서브 클래스의 메소드 method2, 즉 컴파일 타임 동안 Bone 메소드에 대해 알지 못합니다. 결과 참조는 서브 클래스, 즉 Bone에 메소드의 존재에 대해 알 수 있습니다.


AOne은 다소 혼란스러워 보입니다. 학급 이름을 개와 동물 등으로 변경하십시오
Kartik Chugh

0

Java에서 다운 캐스팅을 수행하고 런타임 예외를 피하려면 다음 코드를 참조하십시오.

if (animal instanceof Dog) {
  Dog dogObject = (Dog) animal;
}

여기서 Animal은 부모 클래스이고 Dog는 자식 클래스입니다.
instanceof 는 참조 변수에 지정된 유형의 객체 참조가 포함되어 있는지 확인하는 데 사용되는 키워드입니다.


0

객체의 다운 캐스팅 변환은 불가능합니다. 뿐

DownCasting1 _downCasting1 = (DownCasting1)((DownCasting2)downCasting1);

가능하다

class DownCasting0 {
    public int qwe() {
        System.out.println("DownCasting0");
        return -0;
    }
}

class DownCasting1 extends DownCasting0 {
    public int qwe1() {
        System.out.println("DownCasting1");
        return -1;
    }
}

class DownCasting2 extends DownCasting1 {
    public int qwe2() {
        System.out.println("DownCasting2");
        return -2;
    }
}

public class DownCasting {

    public static void main(String[] args) {

        try {
            DownCasting0 downCasting0 = new DownCasting0();
            DownCasting1 downCasting1 = new DownCasting1();
            DownCasting2 downCasting2 = new DownCasting2();

            DownCasting0 a1 = (DownCasting0) downCasting2;
            a1.qwe(); //good

            System.out.println(downCasting0 instanceof  DownCasting2);  //false
            System.out.println(downCasting1 instanceof  DownCasting2);  //false
            System.out.println(downCasting0 instanceof  DownCasting1);  //false

            DownCasting2 _downCasting1= (DownCasting2)downCasting1;     //good
            DownCasting1 __downCasting1 = (DownCasting1)_downCasting1;  //good
            DownCasting2 a3 = (DownCasting2) downCasting0; // java.lang.ClassCastException

            if(downCasting0 instanceof  DownCasting2){ //false
                DownCasting2 a2 = (DownCasting2) downCasting0;
                a2.qwe(); //error
            }

            byte b1 = 127;
            short b2 =32_767;
            int b3 = 2_147_483_647;
//          long _b4 = 9_223_372_036_854_775_807; //int large number max 2_147_483_647
            long b4 = 9_223_372_036_854_775_807L;
//          float _b5 = 3.4e+038; //double default
            float b5 = 3.4e+038F; //Sufficient for storing 6 to 7 decimal digits
            double b6 = 1.7e+038;
            double b7 = 1.7e+038D; //Sufficient for storing 15 decimal digits

            long c1 = b3;
            int c2 = (int)b4;

            //int       4 bytes     Stores whole numbers from -2_147_483_648 to 2_147_483_647
            //float     4 bytes     Stores fractional numbers from 3.4e−038 to 3.4e+038. Sufficient for storing 6 to 7 decimal digits
            float c3 = b3; //logic error
            double c4 = b4; //logic error


        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.