클래스 변수와 관련하여 업 캐스팅과 다운 캐스팅의 차이점은 무엇입니까?


138

클래스 변수와 관련하여 업 캐스팅과 다운 캐스팅의 차이점은 무엇입니까?

예를 들어 다음 프로그램 클래스 Animal에는 하나의 메서드 만 포함되어 있지만 Dog 클래스에는 두 가지 메서드가 포함되어 있습니다. 그러면 Dog 변수를 Animal 변수로 캐스팅하는 방법이 있습니다.

캐스팅이 완료되면 Animal 변수를 사용하여 Dog의 또 다른 메소드를 어떻게 호출 할 수 있습니까?

class Animal 
{ 
    public void callme()
    {
        System.out.println("In callme of Animal");
    }
}


class Dog extends Animal 
{ 
    public void callme()
    {
        System.out.println("In callme of Dog");
    }

    public void callme2()
    {
        System.out.println("In callme2 of Dog");
    }
}

public class UseAnimlas 
{
    public static void main (String [] args) 
    {
        Dog d = new Dog();      
        Animal a = (Animal)d;
        d.callme();
        a.callme();
        ((Dog) a).callme2();
    }
}

A Dog는입니다 Animal. 오버로드 된 특정 방법을 사용하지 않는 한 대부분의 시간 업 캐스팅은 불필요합니다. 와 callme에 모두 존재합니다 . 에서만 존재 는 캐스팅하는 하는 것이 작업 할 수 있습니다. AnimalDogcallme2DogaDog
Brian

코드의 출력은 무엇입니까?
Malwinder Singh

흥미로운 것은 d.callme가 d를 동물에게 캐스트했지만 'Dog of dog'을 반환한다는 것입니다!
Chris311

4
@ Chris311 'd'와 'a'는 모두 같은 객체를 가리키고 있습니다 ... 이것은 Dog이지만 'a'는 런타임에 다운 캐스트 될 때 Dog 특정 메소드에만 액세스 할 수 있습니다. 사실 : 동물 a = (동물) d; 불필요합니다. 동물 a = d 만 있으면됩니다. 업 캐스트 할 때
Mark Keen

답변:


223

업 캐스팅은 수퍼 타입으로 캐스트되고 다운 캐스팅은 서브 타입으로 캐스트됩니다. 업 캐스팅은 항상 허용되지만 다운 캐스팅에는 유형 검사가 필요하며를 던질 수 있습니다 ClassCastException.

귀하의 경우,에서 주조 Dog로는 AnimalA가 있기 때문에 업 캐스팅입니다 Dog입니다-A Animal. 일반적으로 두 클래스간에 관계가있을 때마다 상향 변환 할 수 있습니다.

다운 캐스팅은 다음과 같습니다.

Animal animal = new Dog();
Dog castedDog = (Dog) animal;

기본적으로 수행중인 작업은 컴파일러에게 객체의 런타임 유형이 실제로 무엇인지 알고 있음을 알리는 입니다. 컴파일러는 변환을 허용하지만 변환이 의미가 있는지 확인하기 위해 런타임 온 전성 검사를 계속 삽입합니다. 런타임에 있기 때문에이 경우, 캐스트가 가능하다 animal사실이다 Dog의 경우에도 정적 유형 animal입니다 Animal.

그러나 이렇게하려면 다음을 수행하십시오.

Animal animal = new Animal();
Dog notADog = (Dog) animal;

당신은 얻을 것이다 ClassCastException. 때문에 그 이유는 왜 animal의 실행시의 형태가 Animal, 당신이 캐스트를 수행하기 위해 런타임을 말할 때 그래서 그보고 animal정말없는 Dog및 때문에 발생합니다 ClassCastException.

수퍼 클래스의 메소드를 호출하려면 super.method()업 캐스트를 수행하거나 수행하십시오.

서브 클래스의 메소드를 호출하려면 다운 캐스트를 수행해야합니다. 위에 표시된 것처럼 일반적 ClassCastException으로이 작업을 수행하면 위험 할 수 있습니다 . 그러나 instanceof캐스트를 수행하기 전에 연산자를 사용하여 객체의 런타임 유형을 확인할 수 있습니다 ClassCastException.

Animal animal = getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal?
if (animal instanceof Dog) {
    // Guaranteed to succeed, barring classloader shenanigans
    Dog castedDog = (Dog) animal;
}

적절한 다운 캐스팅이 아니 ClassCastException거나하지 않습니까? 첫 번째 경우처럼?
Malwinder Singh 5

@MS "적절한"은 무슨 뜻입니까?
awksp

2
@awksp 이것은 훌륭하고 명료 한 답변입니다. 캐스팅에 대해 알아야 할 모든 것을 요약합니다.
Gautham Honnavara

당신은 동물이 개인 경우 수업을하지 않았습니까? 왜 당신은 그것을 확인하고 있습니까?
barlop

62

다운 캐스팅 및 업 캐스팅은 다음과 같습니다.
여기에 이미지 설명을 입력하십시오

Upcasting : Sub 클래스를 Super 클래스로 캐스팅하려면 Upcasting (또는 widening)을 사용합니다. 명시 적으로 아무것도 할 필요가 없으며 자동으로 발생합니다.

다운 캐스팅 : Super 클래스를 Sub 클래스로 캐스팅하려면 다운 캐스팅 (또는 축소)을 사용하며 Java에서는 다운 캐스팅을 직접 수행 할 수 없으므로 명시 적으로 수행해야합니다.

Dog d = new Dog();
Animal a = (Animal) d; //Explicitly you have done upcasting. Actually no need, we can directly type cast like Animal a = d; compiler now treat Dog as Animal but still it is Dog even after upcasting
d.callme();
a.callme(); // It calls Dog's method even though we use Animal reference.
((Dog) a).callme2(); // Downcasting: Compiler does know Animal it is, In order to use Dog methods, we have to do typecast explicitly.
// Internally if it is not a Dog object it throws ClassCastException

따라서 메서드의 부모를 호출하기 위해 업 캐스팅을 수행하는 방법이 있습니까?
karlihnos

32

업 캐스팅 및 다운 캐스팅은 Java의 중요한 부분으로, 간단한 구문을 사용하여 복잡한 프로그램을 작성할 수 있으며 다형성 또는 다른 객체 그룹화와 같은 큰 이점을 제공합니다. Java는 서브 클래스 유형의 오브젝트가 모든 수퍼 클래스 유형의 오브젝트로 처리되도록합니다. 이를 업 캐스팅이라고합니다. 업 캐스팅은 자동으로 수행되지만 다운 캐스팅은 프로그래머가 수동으로 수행해야하며 그 이유를 설명하기 위해 최선을 다할 것입니다.

업 캐스팅 및 다운 캐스팅은 프리미티브를 서로 캐스팅하는 것과 같지 않으며 프로그래머가 객체 캐스팅을 배우기 시작할 때 많은 혼란을 초래하는 것이라고 생각합니다.

다형성 : 자바의 모든 메소드는 기본적으로 가상입니다. 즉, 메소드가 final 또는 static으로 선언되지 않은 경우 상속에 사용될 때 모든 메소드를 대체 할 수 있습니다 .

아래 예제 getType();는 object (Dog, Pet, Police Dog) 유형에 따라 어떻게 작동 하는지 볼 수 있습니다 .

세 마리의 개가 있다고 가정

  1. 개-슈퍼 클래스입니다.

  2. 애완견-애완견은 개를 연장합니다.

  3. 경찰견-경찰견은 애완견을 연장합니다.

    public class Dog{ 
       public String getType () {
          System.out.println("NormalDog");
          return "NormalDog";
       }
     }
    
    /**
     * Pet Dog has an extra method dogName()
     */   
    public class PetDog extends Dog{ 
       public String getType () {
          System.out.println("PetDog");
          return "PetDog";
       }
       public String dogName () {
          System.out.println("I don't have Name !!");
          return "NO Name";
       }
     }
    
    /**
     * Police Dog has an extra method secretId()
     */
    public class PoliceDog extends PetDog{
    
     public String secretId() {
        System.out.println("ID");
        return "ID";
     }
    
     public String getType () {
         System.out.println("I am a Police Dog");
         return "Police Dog";
     }
    }

다형성 : 자바의 모든 메소드는 기본적으로 가상입니다. 즉, 메서드가 final 또는 static으로 선언되지 않은 경우 상속에 사용될 때 모든 메서드를 재정의 할 수 있습니다. (설명은 가상 테이블 개념에 속함)

가상 테이블 / 디스패치 테이블 : 객체의 디스패치 테이블에는 객체의 동적으로 바인딩 된 메서드의 주소가 포함됩니다. 메소드 호출은 오브젝트의 디스패치 테이블에서 메소드 주소를 페치하여 수행됩니다. 디스패치 테이블은 동일한 클래스에 속하는 모든 객체에 대해 동일하므로 일반적으로 객체간에 공유됩니다.

public static void main (String[] args) {
      /**
       * Creating the different objects with super class Reference
       */
     Dog obj1 = new Dog();
`         /**
           *  Object of Pet Dog is created with Dog Reference since                
           *  Upcasting is done automatically for us we don't have to worry about it 
           *  
           */
     Dog obj2 = new PetDog();
`         /**
           *  Object of Police Dog is created with Dog Reference since                
           *  Upcasting is done automatically for us we don't have to worry       
           *  about it here even though we are extending PoliceDog with PetDog 
           *  since PetDog is extending Dog Java automatically upcast for us 
           */
      Dog obj3 = new PoliceDog();
}



 obj1.getType();

인쇄물 Normal Dog

  obj2.getType();

인쇄물 Pet Dog

 obj3.getType();

인쇄물 Police Dog

다운 캐스팅은 프로그래머가 수동으로 수행해야합니다.

당신이 호출 할 때 secretID();의 방법 obj3되는 PoliceDog object하지만를 기준으로 Dog하는을하기 때문에이 오류가 발생합니다 계층 구조의 슈퍼 클래스 obj3에 대한 액세스 권한이없는 secretId()방법. 해당 메소드를 호출하려면 해당 obj3을 수동으로 다운 캐스트해야합니다. PoliceDog

  ( (PoliceDog)obj3).secretID();

인쇄 ID

인보 할 수있는 유사한 방법 dogName();으로 방법을 PetDog클래스는 다운 캐스트 필요 obj2PetDogobj2보다가 참조되기 때문에 Dog과에 액세스 할 수없는 dogName();방법을

  ( (PetDog)obj2).dogName();

왜 그렇게해서 업 캐스팅이 자동이지만 다운 캐스팅이 수동이어야합니까? 글쎄, 업 캐스팅은 결코 실패 할 수 없다. 당신이 다른 개 그룹이 자신의 유형에에 그들 모두를 다운 캐스트 싶은 경우, 다음 기회는 이러한 개 중 일부는 실제로 다른 유형의 수 있습니다 즉 것을, 거기 PetDog, PoliceDog및 프로세스가 던져 실패 ClassCastException.

객체를 수퍼 클래스 유형으로 참조한 경우 객체를 수동으로 다운 캐스트 해야하는 이유 입니다.

참고 : 여기에서 참조한다는 것은 다운 캐스트 할 때 객체의 메모리 주소를 변경하지 않고 여전히이 경우 특정 유형으로 그룹화하는 것과 동일하게 유지함을 의미합니다 Dog


'다형성은 메소드 호출 중에 자동 다운 캐스트를 사용합니다.' 아닙니다. 사용 된 메커니즘은 지정되어 있지 않지만 가장 일반적인 메커니즘 인 vtable은 그러한 기능을 수행하지 않습니다. 객체 코드를 확인하십시오. 다운 캐스트가 없습니다.
Lorne의 후작

왜 안돼? 이것이 제대로 작동하지 않는 예를 줄 수 있습니까?
Nagarjuna Yelisetty

1
왜 안돼? 이것이 바로 발생하는 일입니다. '다형성이 메소드 호출 중에 자동 다운 캐스트를 사용하는'문장을 예로들 수 있습니다. 실패하거나 사실을 지키지 않습니까?
Nagarjuna Yelisetty

당신의 경합입니다. 그것을 증명하는 것은 당신에게 달려 있습니다. 오브젝트 코드에서 다운 캐스트가 발생하는 위치를 표시하십시오. '왜 안 되겠는가?'라는 질문에 대한 대답은 '필요하지 않기 때문에'입니다. vtable은 메소드 디스패치를 ​​처리하고 변수는 이미 전체 객체를 가리 킵니다.
Lorne의 후작

1
'내 지식에 따르면 내 진술은 사실이며 모든 경우에 적용됩니다'는 증거가 아닙니다. 단순한 주장입니다. 나는 당신에게 당신 진술 을 증명하도록 요구하고 있습니다 . 당신은 그렇게하지 않습니다. 사실상 당신은 자신을 반복하고 있습니다. 그리고 나는 이미 여러 가지 반박을 제공했습니다. 나는 또한 결정 절차를 제공했습니다. 메소드 호출에 대한 객체 코드에서 다운 캐스트를 찾을 수 있다면 옳습니다. 이것이 과학이 이루어지는 방식입니다. 해. 그리고 내가 '문서에 크게 의존하고있다'고 주장하는 것은 명백한 허위 진술입니다. 하지마
Lorne의 후작

12

나는이 질문이 오래 전에 요청되었지만이 질문의 새로운 사용자를 위해 알고 있습니다. instanceof 연산자 의 업 캐스팅, 다운 캐스팅 및 사용에 대한 전체 설명이 포함 된이 기사를 읽으십시오.

  • 수동으로 상향 변환 할 필요가 없으며 자체적으로 발생합니다.

    Mammal m = (Mammal)new Cat(); ~와 같다 Mammal m = new Cat();

  • 그러나 다운 캐스팅은 항상 수동으로 수행해야합니다.

    Cat c1 = new Cat();      
    Animal a = c1;      //automatic upcasting to Animal
    Cat c2 = (Cat) a;    //manual downcasting back to a Cat

왜 그렇게해서 업 캐스팅이 자동이지만 다운 캐스팅이 수동이어야합니까? 글쎄, 업 캐스팅은 결코 실패 할 수 없다. 그러나 다른 동물 그룹이 있고 모두 고양이로 다운 캐스트하려는 경우 이러한 동물 중 일부는 실제로 개이며 ClassCastException을 발생시켜 프로세스가 실패 할 가능성이 있습니다. 여기서는 "instanceof" 라는 유용한 기능을 소개해야합니다.이 기능 은 객체가 일부 클래스의 인스턴스인지 테스트합니다.

 Cat c1 = new Cat();         
    Animal a = c1;       //upcasting to Animal
    if(a instanceof Cat){ // testing if the Animal is a Cat
        System.out.println("It's a Cat! Now i can safely downcast it to a Cat, without a fear of failure.");        
        Cat c2 = (Cat)a;
    }

자세한 내용은 이 기사 를 읽으십시오


좋은 점 : 포유류 m = (포유류) new Cat (); Mammal과 같습니다. m = new Cat ();
Catbuilts

6

업 캐스팅을 위해이 방법을 더 잘 시도하면 이해하기 쉽습니다.

/* upcasting problem */
class Animal
{ 
    public void callme()
    {
        System.out.println("In callme of Animal");
    }
}

class Dog extends Animal 
{ 
    public void callme()
    {
        System.out.println("In callme of Dog");
    }

    public void callme2()
    {
        System.out.println("In callme2 of Dog");
    }
}

public class Useanimlas 
{
    public static void main (String [] args) 
    {
        Animal animal = new Animal ();
        Dog dog = new Dog();
        Animal ref;
        ref = animal;
        ref.callme();
        ref = dog;
        ref.callme();
    }
}

마지막 줄에서 다음과 같습니다. ((Dog) ref) .callme2 (); // 다운 캐스팅 / 좁히기와 Dog 클래스의 callme2 () 메서드 액세스
udarH3

6

아마도이 테이블이 도움이 될 것입니다. callme()class Parent또는 class 의 메소드를 호출합니다 Child. 원칙적으로 :

UPCASTING-> 숨기기

DOWNCASTING-> 공개

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오


4

업 캐스팅.

업 캐스팅을 수행하면 하위 유형의 객체를 가리키는 일부 유형의 태그를 정의합니다 (더 편안하다고 느끼면 유형 및 하위 유형을 클래스 및 하위 클래스라고 할 수 있음).

Animal animalCat = new Cat();

이러한 태그 인 animalCat은 Cat 유형이 아닌 Animal 유형으로 선언 되었기 때문에 Animal 유형의 기능 (방법) 만 갖습니다.

우리는 "자연 / 암시 적 / 자동"방식으로 컴파일 타임이나 런타임에이를 수행 할 수 있습니다. 주로 Cat은 일부 기능을 Animal에서 상속하기 때문입니다. 예를 들어 move ()입니다. (적어도 고양이는 동물이 아닌가?)

다운 캐스팅.

그러나 Animal 태그 유형에서 Cat의 기능을 사용하려면 어떻게됩니까?

Cat 객체를 가리키는 animalCat 태그를 만들었으므로 animalCat 태그에서 Cat 객체 메서드를 스마트하게 호출하는 방법이 필요합니다.

이러한 절차는 다운 캐스팅이라고하며 런타임에만 수행 할 수 있습니다.

일부 코드 시간 :

public class Animal {
    public String move() {
        return "Going to somewhere";
    }
}

public class Cat extends Animal{
    public String makeNoise() {
        return "Meow!";
    }   
}

public class Test {

    public static void main(String[] args) {
        
    //1.- Upcasting 
    //  __Type_____tag________object
        Animal animalCat = new Cat();
    //Some animal movement
        System.out.println(animalCat.move());
        //prints "Going to somewhere"
        
    //2.- Downcasting   
    //Now you wanna make some Animal noise.
        //First of all: type Animal hasn't any makeNoise() functionality.
        //But Cat can do it!. I wanna be an Animal Cat now!!
        
        //___________________Downcast__tag_____ Cat's method
        String animalNoise = ( (Cat) animalCat ).makeNoise();
        
        System.out.println(animalNoise);
        //Prints "Meow!", as cats usually done.
        
    //3.- An Animal may be a Cat, but a Dog or a Rhinoceros too.
        //All of them have their own noises and own functionalities.
        //Uncomment below and read the error in the console:
        
    //  __Type_____tag________object
        //Cat catAnimal = new Animal();
        
    }

}

2

부모 : Car
Child : Figo
Car c1 = new Figo ();

=====
업 캐스팅 :-
메소드 : "Figo"클래스가 "new"로 지정되어 있으므로 객체 c1은 클래스의 메소드 ( Figo- 메소드를 대체해야 함)를 참조합니다.
인스턴스 변수 : 객체 c1은 선언 클래스 ( "Car")의 인스턴스 변수를 참조합니다.

선언 클래스가 부모이고 개체가 자식으로 만들어지면 "업 캐스팅"이라는 암시 적 캐스팅이 발생합니다.

======
다운 캐스팅 :-Figo
f1 = (Figo) c1; //
메소드 : 초기 오브젝트 c1이 "Figo"클래스로 작성되므로 오브젝트 f1은 클래스 메소드 (figo)를 참조합니다. 그러나 다운 캐스팅이 완료되면 "Figo"클래스에만있는 메소드는 변수 f1으로도 참조 할 수 있습니다.
인스턴스 변수 : 객체 f1은 객체 c1의 선언 클래스 (c1의 선언 클래스는 CAR 임)의 인스턴스 변수를 참조하지 않지만 다운 캐스팅에서는 피코 클래스의 인스턴스 변수를 참조합니다.

======
사용 : 개체가 자식 클래스이고 선언 클래스가 부모이고 자식 클래스가 부모 클래스가 아닌 자체 클래스의 인스턴스 변수에 액세스하려고하면 "다운 캐스팅"을 사용하여 수행 할 수 있습니다.


1

업 캐스팅은 객체를 수퍼 타입으로 캐스팅하는 것을 의미하고, 다운 캐스팅은 서브 타입으로 캐스팅하는 것을 의미합니다.

Java에서는 자동으로 수행되므로 업 캐스팅이 필요하지 않습니다. 일반적으로 암시 적 캐스팅이라고합니다. 다른 사람에게 명확하게 보이도록 지정할 수 있습니다.

따라서 쓰기

Animal a = (Animal)d;

또는

Animal a = d;

정확히 같은 지점으로 연결되며 두 경우 모두 callme()from에서 실행 됩니다 Dog.

a동물의 객체로 정의했기 때문에 다운 캐스팅이 대신 필요 합니다. 현재는 그것이 알고 Dog있지만 java는 보장하지 않습니다. 실제로 런타임에 다를 수 있으며 java는을 던질 ClassCastException것입니다. 물론 샘플 예제의 경우에는 그렇지 않습니다. 당신이 캐스팅하지 않을 경우 aAnimal때문에, 자바 심지어 응용 프로그램을 컴파일 할 수있는 Animal방법이 없습니다 callme2().

귀하의 예제에서는의 코드에 도달 할 수없는 callme()의를 Animal에서 UseAnimlas(때문에 Dog방법은 다음과 같이 될 것이다 않는 한 덮어 쓰기) :

class Dog extends Animal 
{ 
    public void callme()
    {
        super.callme();
        System.out.println("In callme of Dog");
    }
    ... 
} 

0

다운 캐스팅에 객체를 만들 수 있습니다. 이 유형에서도. : 기본 클래스 메소드 호출

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