CodeGym /Java Blog /무작위의 /참조 유형의 확대 및 축소
John Squirrels
레벨 41
San Francisco

참조 유형의 확대 및 축소

무작위의 그룹에 게시되었습니다
안녕! 지난 수업에서 우리는 원시 유형 캐스팅에 대해 논의했습니다. 논의 된 내용을 간단히 기억해 봅시다. 참조 유형의 확대 및 축소 - 1기본 유형(이 경우에는 숫자 유형)이 점유하는 메모리 양에 따라 크기가 달라지는 중첩 인형으로 상상했습니다. 기억하시겠지만 큰 인형 안에 작은 인형을 넣는 것은 실생활과 Java 프로그래밍 모두에서 간단합니다.

public class Main {
   public static void main(String[] args) {
       int bigNumber = 10000000;
       short smallNumber = (short) bigNumber;
       System.out.println(smallNumber);
   }
}
이것은 자동 변환 또는 확장 의 예입니다 . 자체적으로 발생하므로 추가 코드를 작성할 필요가 없습니다. 결국, 우리는 이상한 일을 하는 것이 아닙니다. 우리는 단지 더 큰 인형에 더 작은 인형을 넣는 것입니다. 우리가 그 반대를 시도하고 작은 인형에 더 큰 러시아 인형을 넣는 것은 또 다른 문제입니다. 실생활에서는 그렇게 할 수 없지만 프로그래밍에서는 할 수 있습니다. 그러나 한 가지 뉘앙스가 있습니다. int변수 에 an을 넣으려고 하면 short일이 순조롭게 진행되지 않습니다. 결국, short변수는 16비트 정보만 보유하지만 int32비트를 차지합니다! 결과적으로 전달된 값이 왜곡됩니다. 컴파일러는 우리에게 오류를 줄 것입니다(' Dude, 당신은 뭔가 의심스러운 일을 하고 있습니다!'). 그러나 값을 변환할 유형을 명시적으로 지정하면 계속해서 작업을 수행합니다.

public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
이것이 바로 위의 예에서 수행한 작업입니다. 작업을 수행했지만 변수가 32바이트 중 16바이트만 수용할 수 있기 때문에 최종 값이 왜곡되어 -27008short 이라는 숫자가 표시됩니다 . 이러한 작업을 명시적 변환 또는 축소 라고 합니다 .

참조 유형 확대 및 축소의 예

이제 원시 유형이 아닌 객체 및 참조 변수에 적용된 동일한 연산자에 대해 이야기해 봅시다 ! 이것은 Java에서 어떻게 작동합니까? 실제로 매우 간단합니다. 관련이 없는 개체가 있습니다. 명시적으로나 자동으로 서로 변환할 수 없다고 가정하는 것이 논리적입니다.

public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Dog(); // Error!

   }

}
물론 여기에서 오류가 발생합니다. 및 클래스 CatDog서로 관련이 없으며 서로 간에 이동하는 '변환기'를 작성하지 않았습니다. 우리가 이것을 할 수 없다는 것이 이치에 맞습니다. 컴파일러는 이러한 객체를 한 유형에서 다른 유형으로 변환하는 방법을 모릅니다. 객체가 관련되어 있다면 그건 또 다른 문제입니다! 관련된 방법? 무엇보다 상속을 통해. 작은 클래스 시스템을 만들기 위해 상속을 사용해 봅시다. 동물을 나타내는 공통 클래스가 있습니다.

public class Animal {

   public void introduce() {

       System.out.println("I'm Animal");
   }
}
동물이 길들여지거나(애완동물) 야생이 될 수 있다는 것은 누구나 알고 있습니다.

public class WildAnimal extends Animal {

   public void introduce() {

       System.out.println("I'm WildAnimal");
   }
}

public class Pet extends Animal {

   public void introduce() {

       System.out.println("I'm Pet");
   }
}
예를 들어 송곳니를 예로 들어 보겠습니다. 집에서 키우는 개와 코요테가 있습니다.

public class Dog extends Pet {

   public void introduce() {

       System.out.println("I'm Dog");
   }
}



public class Coyote extends WildAnimal {

   public void introduce() {

       System.out.println ("I'm Coyote");
   }
}
우리는 이해하기 쉽도록 가장 기본적인 수업을 특별히 선택했습니다. 필드가 실제로 필요하지 않으며 하나의 메서드로 충분합니다. 이 코드를 실행해 보겠습니다.

public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
콘솔에 무엇이 표시될 것이라고 생각하십니까? 클래스 또는 클래스 introduce의 메소드가 호출 됩니까 ? 계속 읽기 전에 대답을 정당화하십시오. 결과는 다음과 같습니다! 나는 애완 동물입니다 왜 우리가 그것을 얻었습니까? 모두 간단합니다. 부모 변수와 자손 개체가 있습니다. 글을 써서, PetAnimal

Animal animal = new Pet();
참조 를 확장Pet 하고 변수에 할당 했습니다 Animal. 기본 유형과 마찬가지로 참조 유형은 Java에서 자동으로 확장됩니다. 이를 구현하기 위해 추가 코드를 작성할 필요가 없습니다. 이제 상위 참조에 할당된 하위 개체가 있습니다. 결과적으로 자손 클래스에서 메소드 호출이 이루어지는 것을 볼 수 있습니다. 이 코드가 작동하는 이유를 여전히 완전히 이해하지 못하는 경우 일반 언어로 다시 작성하십시오.

Animal animal = new DomesticatedAnimal();
이건 문제가 없겠죠? 이것이 실생활이고 레퍼런스가 단순히 'Animal'이 적힌 종이 라벨이라고 상상해보세요. 그 종이를 가져가 애완 동물의 목줄에 붙이면 모든 것이 정확할 것입니다. 결국 모든 애완 동물은 동물입니다! 상속 트리에서 후손으로 이동하는 역 과정은 다음과 같이 좁혀지고 있습니다.

public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
보시다시피 여기에서 개체를 변환하려는 클래스를 명확하게 나타냅니다. 이전에는 변수가 있었고 이제는 상속 트리에서 더 낮은 가 WildAnimal있습니다 . Coyote명시적인 표시가 없으면 컴파일러가 그러한 작업을 허용하지 않지만 괄호 안에 유형을 표시하면 모든 것이 작동합니다. 참조 유형의 확대 및 축소 - 2또 다른 흥미로운 예를 살펴보겠습니다.

public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal(); // Error!
   }
}
컴파일러가 오류를 생성합니다! 하지만 왜? 하위 참조에 상위 개체를 할당하려고 하기 때문입니다. 즉, 다음과 같이 하려고 합니다.

DomesticatedAnimal domesticatedAnimal = new Animal();
음, 변환하려는 유형을 명시적으로 지정하면 모든 것이 제대로 작동할까요? 그것은 숫자와 함께 작동했습니다. 시도해 봅시다! :)

public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
"main" 스레드의 예외 java.lang.ClassCastException: Animal을 Pet 오류로 캐스팅할 수 없습니다 ! 이번에는 컴파일러가 우리에게 소리를 지르지 않았지만 결국 예외가 발생했습니다. 우리는 이미 그 이유를 알고 있습니다. 우리는 부모 객체를 자손 참조에 할당하려고 합니다. 그런데 왜 그렇게 할 수 없습니까? 모든 동물이 길들여진 동물은 아니기 때문입니다. 개체를 생성 Animal하고 변수에 할당하려고 합니다 Pet. 코요테도 Animal이지만 Pet. 다시 말해 글을 쓸 때

Pet pet = (Pet) new Animal();
new Animal()반드시 애완 동물이 아닌 모든 동물을 나타낼 수 있습니다! 당연히 귀하의 Pet pet변수는 애완 동물(및 그 자손)을 저장하는 데만 적합하며 어떤 유형의 동물도 저장하지 않습니다. 그렇기 때문에 ClassCastException클래스를 캐스팅하는 동안 오류가 발생하는 경우에 대해 특별한 Java 예외인 가 생성되었습니다. 더 명확하게 하기 위해 다시 검토해 보겠습니다. 상위 참조는 하위 클래스의 인스턴스를 가리킬 수 있습니다.

public class Main {

   public static void main(String[] args) {

       Pet pet = new Pet();
       Animal animal = pet;

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
예를 들어 여기에는 문제가 없습니다. Pet변수 가 참조하는 개체가 있습니다 Pet. 나중에 Animal참조는 동일한 개체를 가리켰습니다. 그 후, 우리 animalPet. 그건 그렇고, 왜 그것이 우리에게 효과가 있었습니까? 지난 번에 우리는 예외를 얻었습니다! 이번에는 원래 객체가 Pet!

Pet pet = new Pet();
그러나 마지막 예에서는 개체였습니다 Animal.

Pet pet = (Pet) new Animal();
조상 객체를 자손 변수에 할당할 수 없습니다. 반대로 할 수 있습니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION