안녕! 지난 수업에서 우리는 원시 유형 캐스팅에 대해 논의했습니다. 논의 된 내용을 간단히 기억해 봅시다. 기본 유형(이 경우에는 숫자 유형)이 점유하는 메모리 양에 따라 크기가 달라지는 중첩 인형으로 상상했습니다. 기억하시겠지만 큰 인형 안에 작은 인형을 넣는 것은 실생활과 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비트 정보만 보유하지만 int
32비트를 차지합니다! 결과적으로 전달된 값이 왜곡됩니다. 컴파일러는 우리에게 오류를 줄 것입니다(' 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!
}
}
물론 여기에서 오류가 발생합니다. 및 클래스 Cat
는 Dog
서로 관련이 없으며 서로 간에 이동하는 '변환기'를 작성하지 않았습니다. 우리가 이것을 할 수 없다는 것이 이치에 맞습니다. 컴파일러는 이러한 객체를 한 유형에서 다른 유형으로 변환하는 방법을 모릅니다. 객체가 관련되어 있다면 그건 또 다른 문제입니다! 관련된 방법? 무엇보다 상속을 통해. 작은 클래스 시스템을 만들기 위해 상속을 사용해 봅시다. 동물을 나타내는 공통 클래스가 있습니다.
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
의 메소드가 호출 됩니까 ? 계속 읽기 전에 대답을 정당화하십시오. 결과는 다음과 같습니다! 나는 애완 동물입니다 왜 우리가 그것을 얻었습니까? 모두 간단합니다. 부모 변수와 자손 개체가 있습니다. 글을 써서, Pet
Animal
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
명시적인 표시가 없으면 컴파일러가 그러한 작업을 허용하지 않지만 괄호 안에 유형을 표시하면 모든 것이 작동합니다. 또 다른 흥미로운 예를 살펴보겠습니다.
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
참조는 동일한 개체를 가리켰습니다. 그 후, 우리 animal
는 Pet
. 그건 그렇고, 왜 그것이 우리에게 효과가 있었습니까? 지난 번에 우리는 예외를 얻었습니다! 이번에는 원래 객체가 Pet
!
Pet pet = new Pet();
그러나 마지막 예에서는 개체였습니다 Animal
.
Pet pet = (Pet) new Animal();
조상 객체를 자손 변수에 할당할 수 없습니다. 반대로 할 수 있습니다.
더 읽어보기: |
---|
GO TO FULL VERSION