슈퍼클래스에서 서브클래스로의 명시적 캐스팅
public class Animal {
public void eat() {}
}
public class Dog extends Animal {
public void eat() {}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = (Dog) animal;
}
}
★★Dog dog = (Dog) animal;
오류를 시 합니다.ClassCastException
컴파일러가 이 에러를 검출할 수 없는 이유는 무엇입니까?
깁스를 사용한다는 것은 컴파일러에게 "나를 믿어라"라고 말하는 것입니다. 하고 수는 이건animal
"라고 말합니다."
를 할 수 .Animal animal = new Dog();
(고객이 신뢰관계를 위반했기 때문에 VM이 런타임에 예외를 발생시킵니다) (컴파일러에게 모든 것이 정상이고, 그렇지 않다고 말씀하셨습니다!)
컴파일러는 모든 것을 맹목적으로 받아들이는 것보다 조금 더 똑똑합니다.여러분이 다른 상속 계층에서 오브젝트를 캐스팅하려고 하면(예를 들어 Dog to a String), 컴파일러는 그것이 결코 작동하지 않을 것을 알기 때문에 그것을 다시 당신에게 던집니다.
할 때마다 ''가 합니다.ClassCastException
를 사용하여instanceof
스테이트먼트 그것)로 합니다.
이론적으로 말하면Animal animal
개가 될 수 있다:
Animal animal = new Dog();
일반적으로 다운캐스팅은 좋은 생각이 아니다.피해야 해요.사용하는 경우는, 다음의 체크 마크를 붙이는 것이 좋습니다.
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}
이러한 종류의 ClassCastException을 피하기 위해 다음과 같은 경우:
class A
class B extends A
A의 개체를 사용하는 생성자를 B에서 정의할 수 있습니다.이렇게 하면 "캐스트"를 할 수 있습니다. 예:
public B(A a) {
super(a.arg1, a.arg2); //arg1 and arg2 must be, at least, protected in class A
// If B class has more attributes, then you would initilize them here
}
마이클 베리의 답변을 자세히 설명하다.
Dog d = (Dog)Animal; //Compiles but fails at runtime
여기에서는 컴파일러에게 다음과 같이 말합니다. '이렇게 하다'는 알고 있다d
는, 는 「의」를 하고 있습니다.Dog
'오브젝트'는 아니지만요.다운캐스트를 할 때 컴파일러는 우리를 믿어야 한다는 것을 기억하라.
컴파일러는 선언된 참조 유형만 인식합니다.런타임의 JVM은 개체의 실제 상태를 인식합니다.
실행 시이 "JVM"이 "JVM"을Dog d
는, 는 「」, 「」를 하고 있습니다.Animal
한 푼도 없다Dog
이의를 제기합니다.... 넌 컴파일러에게 거짓말을 하고 큰소리쳤잖아ClassCastException
.
그래서 다운캐스트를 할 때는instanceof
테스트에 실패하지 않도록 주의해 주세요.
if (animal instanceof Dog) { Dog dog = (Dog) animal; }
이제 우리 머릿속에 질문이 떠오른다.으로 Hell 다운캐스트를 왜 합니까?java.lang.ClassCastException
가 할 수 은 두 이 같은 트리에 입니다. 전에 "Downcast"가 될 수 따라서 다운캐스트 전에 어떤 코드가 나왔는지에 따라서는 다음 중 하나가 될 수 있습니다.animal
은 「」입니다.dog
컴파일러는 실행 시 동작할 수 있는 것을 허용해야 합니다.
다음 코드 스니펫에 대해 생각해 보겠습니다.
public static void main(String[] args)
{
Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog
Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :)
d.eat();
}
private static Animal getMeAnAnimal()
{
Animal animal = new Dog();
return animal;
}
그러나 컴파일러가 캐스트가 작동하지 않는다고 확신하면 컴파일은 실패합니다.즉, 다른 상속 계층에 객체를 캐스팅하려고 하는 경우
String s = (String)d; // ERROR : cannot cast for Dog to String
다운캐스트와는 달리 업캐스트는 암묵적으로 기능합니다.업캐스트를 할 때 호출할 수 있는 메서드의 수를 암묵적으로 제한하기 때문입니다.다운캐스트는 나중에 보다 구체적인 메서드를 호출하는 것을 의미합니다.
Dog d = new Dog(); Animal animal1 = d; // Works fine with no explicit cast Animal animal2 = (Animal) d; // Works fine with n explicit cast
위의 두 업캐스트 모두 개 IS-A Animal, Anithing an Animal이 할 수 있기 때문에 예외 없이 잘 작동합니다.하지만 그것은 진짜 vica-versa가 아닙니다.
@Caumons의 답변을 작성하려면:
한 아버지 반에 많은 아이들이 있고 그 반에 공통 분야를 추가할 필요가 있다고 상상해 보세요.전술한 접근방식을 고려할 경우 각 자녀 클래스로 하나씩 이동하여 새로운 필드의 컨스트럭터를 리팩터링해야 합니다.따라서 이 시나리오에서 그 해결책은 유망한 해결책이 아니다.
이제 이 솔루션을 살펴보겠습니다.
아버지는 각 자녀로부터 자기 물건을 받을 수 있다.다음은 아버지 클래스입니다.
public class Father {
protected String fatherField;
public Father(Father a){
fatherField = a.fatherField;
}
//Second constructor
public Father(String fatherField){
this.fatherField = fatherField;
}
//.... Other constructors + Getters and Setters for the Fields
}
다음은 아버지 컨스트럭터 중 하나를 구현해야 하는 자녀 클래스입니다.이 경우 앞에서 언급한 컨스트럭터입니다.
public class Child extends Father {
protected String childField;
public Child(Father father, String childField ) {
super(father);
this.childField = childField;
}
//.... Other constructors + Getters and Setters for the Fields
@Override
public String toString() {
return String.format("Father Field is: %s\nChild Field is: %s", fatherField, childField);
}
}
이제 애플리케이션을 테스트합니다.
public class Test {
public static void main(String[] args) {
Father fatherObj = new Father("Father String");
Child child = new Child(fatherObj, "Child String");
System.out.println(child);
}
}
그 결과는 다음과 같습니다.
아버지 필드: 아버지 스트링
하위 필드: 하위 문자열
이제 자녀 코드가 깨질 염려 없이 아버지 클래스에 새 필드를 쉽게 추가할 수 있습니다.
인스턴스 유형이 Animal이기 때문에 코드가 컴파일 오류를 생성합니다.
Animal animal=new Animal();
Java에서는 다운캐스팅이 허용되지 않는 몇 가지 이유가 있습니다.자세한 내용은 여기를 참조해 주세요.
설명대로 그것은 불가능합니다.서브클래스의 메서드를 사용하는 경우 슈퍼클래스에 메서드를 추가할 수 있는지 여부를 평가하여(공백일 수 있음), 다형성을 통해 원하는 동작을 얻을 수 있는 서브클래스로부터의 콜(서브클래스)을 실시합니다.따라서 d.method()를 호출하면 콜은 캐스팅으로 성공하지만 객체가 개가 아닌 경우에는 문제가 없습니다.
앞에서 설명한 바와 같이 오브젝트가 처음부터 서브클래스에서 인스턴스화되지 않는 한 슈퍼클래스에서 서브클래스로 캐스팅할 수 없습니다.
단, 회피책이 있습니다.
컨스트럭터 세트와 편리한 방법만 있으면 오브젝트를 Dog에 캐스팅하거나 동일한 Animal 속성을 가진 새로운 Dog 오브젝트를 반환할 수 있습니다.
다음으로 그 예를 제시하겠습니다.
public class Animal {
public Animal() {}
public Animal(Animal in) {
// Assign animal properties
}
public Dog toDog() {
if (this instanceof Dog)
return (Dog) this;
return new Dog(this);
}
}
public class Dog extends Animal {
public Dog(Animal in) {
super(in);
}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = animal.toDog();
}
}
언급URL : https://stackoverflow.com/questions/4862960/explicit-casting-from-super-class-to-subclass
'programing' 카테고리의 다른 글
Vuex 이거.$store는 함수가 아니라 이것입니다.$store.syslog가 실행됩니다. (0) | 2022.07.27 |
---|---|
Vuex는 'createStore'라는 이름의 내보내기를 제공하지 않습니다. (0) | 2022.07.27 |
Vue에서 메서드를 호출하는 동안 괄호 (0) | 2022.07.27 |
LocalDateTime(Java 8)을 해석할 때 TemporalAccessor에서 LocalDateTime을 가져올 수 없습니다. (0) | 2022.07.27 |
C 표준 라이브러리의 어떤 기능이 일반적으로 나쁜 관행을 장려합니까? (0) | 2022.07.27 |