Java 다형성 객체의 유형 변환
여기서 언급되는 객체 유형 변환은 어떤 유형의 객체도 아닌 상속 관계를 갖는 객체를 의미합니다. 상속 관계가 없는 객체를 캐스팅할 때 Java 런타임은 java.lang.ClassCastException 예외를 발생시킵니다.
상속 체인에서는 하위 클래스를 상위 클래스로 변환하는 것을 '업캐스팅', 상위 클래스를 하위 클래스로 변환하는 것을 '다운캐스팅'이라고 합니다.
대부분의 경우 변수를 상위 클래스의 유형으로 정의하지만 하위 클래스의 객체를 참조하는 과정이 상향 변환입니다. 프로그램이 실행될 때 하위 클래스 메서드 호출은 다형성인 동적 바인딩을 통해 구현됩니다.
그러나 때로는 상위 클래스에 없는 일부 기능을 완성하기 위해 상향 변환 후 하위 클래스 객체를 하위 클래스로 변환하고 하위 클래스의 메서드를 호출해야 하는 경우가 있습니다.
참고: 상위 클래스의 개체를 하위 클래스 유형으로 직접 강제할 수는 없습니다. 업캐스트 하위 클래스 개체를 다시 하위 클래스 유형으로 변환할 수만 있습니다. 즉, 하위 클래스 객체를 아래쪽으로 변환하려면 먼저 위쪽으로 변환해야 합니다. 다음 코드를 살펴보세요.
public class Demo { public static void main(String args[]) { SuperClass superObj = new SuperClass(); SonClass sonObj = new SonClass(); // 下面的代码运行时会抛出异常,不能将父类对象直接转换为子类类型 // SonClass sonObj2 = (SonClass)superObj; // 先向上转型,再向下转型 superObj = sonObj; SonClass sonObj1 = (SonClass)superObj; } } class SuperClass{ } class SonClass extends SuperClass{ }
7행의 주석을 제거하세요. 실행 시 예외가 발생하지만 컴파일은 통과할 수 있습니다.
다운캐스팅에는 위험이 있으므로 상위 클래스로부터 참조를 받을 때 반드시 instanceof 연산자를 사용하여 해당 객체가 원하는 하위 클래스인지 확인하세요.
public class Demo { public static void main(String args[]) { SuperClass superObj = new SuperClass(); SonClass sonObj = new SonClass(); // superObj 不是 SonClass 类的实例 if(superObj instanceof SonClass){ SonClass sonObj1 = (SonClass)superObj; }else{ System.out.println("①不能转换"); } superObj = sonObj; // superObj 是 SonClass 类的实例 if(superObj instanceof SonClass){ SonClass sonObj2 = (SonClass)superObj; }else{ System.out.println("②不能转换"); } } } class SuperClass{ } class SonClass extends SuperClass{ }
실행 결과:
①不能转换
요약: 프로그램이 실행될 때 객체의 유형 변환이 확인되며 다운캐스트된 객체는 현재 참조여야 합니다. 유형.
Java 다형성 및 동적 바인딩
Java에서 상위 클래스의 변수는 상위 클래스의 인스턴스나 하위 클래스의 인스턴스를 참조할 수 있습니다.
먼저 코드를 읽어보세요:
public class Demo { public static void main(String[] args){ Animal obj = new Animal(); obj.cry(); obj = new Cat(); obj.cry(); obj = new Dog(); obj.cry(); } } class Animal{ // 动物的叫声 public void cry(){ System.out.println("不知道怎么叫"); } } class Cat extends Animal{ // 猫的叫声 public void cry(){ System.out.println("喵喵~"); } } class Dog extends Animal{ // 狗的叫声 public void cry(){ System.out.println("汪汪~"); } }
실행 결과:
不知道怎么叫 喵喵~ 汪汪~
위 코드는 세 가지 클래스를 정의합니다. Cat 및 Dog 클래스는 각각 Animal 클래스에서 상속됩니다. obj 변수는 Animal 유형이며 Animal 클래스의 인스턴스는 물론 Cat 및 Dog 클래스의 인스턴스도 가리킬 수 있습니다. 이는 맞습니다. 즉, 부모 클래스의 변수는 부모 클래스의 인스턴스나 하위 클래스의 인스턴스를 참조할 수 있습니다. 모든 고양이는 동물이지만 모든 동물이 고양이는 아니기 때문에 대화가 잘못되었습니다.
obj는 사람, 고양이, 개가 될 수 있다는 것을 알 수 있는데, 이를 다형성이라고 합니다. 다형성은 사물이 다른 표현이나 형태를 가지고 있음을 의미합니다.
또 다른 예는 '인간'이다. 표현이나 깨달음도 다양하다. TA는 운전사, 선생님, 의사 등이 될 수 있다. 인생", 그러면 당신은 다음 생에 운전사 또는 교사가 될 것입니다. , 의사는 그것을 할 수 있습니다. 우리는 단지 "인간"이 다형성을 가지고 있다고 말합니다.
다형성이 존재하려면 세 가지 필수 조건이 있습니다. 상속, 재정의, 상위 클래스 변수가 하위 클래스 객체를 참조합니다.
다형성을 사용하여 메서드를 호출하는 경우:
먼저 해당 메서드가 상위 클래스에 있는지 확인하고, 없으면 컴파일 오류가 발생합니다.
하위 클래스가 이 메서드를 재정의하는 경우 하위 클래스 메서드를 호출하고, 그렇지 않으면 상위 클래스 메서드를 호출합니다.
위의 예에서 볼 수 있듯이 다형성의 한 가지 이점은 하위 클래스가 많을 때 여러 변수를 정의할 필요가 없으며 참조할 상위 클래스 유형의 변수만 정의할 수 있다는 것입니다. 다른 하위 클래스. 다음 예를 다시 살펴보십시오.
public class Demo { public static void main(String[] args){ // 借助多态,主人可以给很多动物喂食 Master ma = new Master(); ma.feed(new Animal(), new Food()); ma.feed(new Cat(), new Fish()); ma.feed(new Dog(), new Bone()); } } // Animal类及其子类 class Animal{ public void eat(Food f){ System.out.println("我是一个小动物,正在吃" + f.getFood()); } } class Cat extends Animal{ public void eat(Food f){ System.out.println("我是一只小猫咪,正在吃" + f.getFood()); } } class Dog extends Animal{ public void eat(Food f){ System.out.println("我是一只狗狗,正在吃" + f.getFood()); } } // Food及其子类 class Food{ public String getFood(){ return "事物"; } } class Fish extends Food{ public String getFood(){ return "鱼"; } } class Bone extends Food{ public String getFood(){ return "骨头"; } } // Master类 class Master{ public void feed(Animal an, Food f){ an.eat(f); } }
실행 결과:
我是一个小动物,正在吃事物 我是一只小猫咪,正在吃鱼 我是一只狗狗,正在吃骨头
마스터 클래스의 피드 메소드에는 Animal이라는 두 개의 매개변수가 있습니다. Type 및 Food 유형은 상위 클래스이기 때문에 하위 클래스의 인스턴스를 전달할 수 있으므로 Master 클래스는 다른 동물에게 먹이를 주기 위해 여러 메서드가 필요하지 않습니다.
동적 바인딩
다형성의 본질을 이해하기 위해 Java에서 메소드를 호출하는 세부 과정에 대해 이야기해 보겠습니다.
1) 컴파일러는 객체의 선언된 유형과 메소드 이름을 살펴봅니다.
obj.func(param)이 호출되고, obj가 Cat 클래스의 객체라고 가정합니다. func라는 이름의 메서드가 여러 개 있을 수 있지만 매개변수 서명이 다를 수 있다는 점에 유의해야 합니다. 예를 들어 func(int) 및 func(String) 메서드가 있을 수 있습니다. 컴파일러는 Cat 클래스의 func라는 이름의 모든 메서드와 액세스 속성이 public인 상위 클래스 Animal의 func라는 메서드를 모두 열거합니다.
이러한 방식으로 컴파일러는 호출될 수 있는 모든 후보 메소드 목록을 얻습니다.
2) 다음으로 컴파일러는 메소드 호출 시 제공된 매개변수 서명을 확인합니다.
func라는 이름의 모든 메소드 중 제공된 매개변수 서명과 정확히 일치하는 메소드가 있으면 이 메소드가 선택됩니다. 이 프로세스를 오버로드 해결이라고 합니다. 예를 들어, func("hello")를 호출하면 컴파일러는 func(int) 대신 func(String)을 선택합니다. 예를 들어 자동 유형 변환이 있기 때문에 int는 double로 변환될 수 있습니다. 호출하는 메소드 매개변수와 동일한 시그니처를 가진 메소드가 없으면 유형 변환이 수행되고 검색이 계속됩니다. 결국 일치하는 유형이 없거나 일치하는 메서드가 여러 개 있는 경우 컴파일 오류가 발생합니다.
이런 방식으로 컴파일러는 호출해야 하는 메서드 이름과 매개변수 서명을 얻습니다.
3) 메서드의 수정자가 private, static, final(static 및 final은 나중에 설명함) 또는 생성자 메서드인 경우 컴파일러는 어떤 메서드를 호출해야 하는지 정확히 알 수 있습니다. 정적 바인딩이라고 합니다.
따라서 호출되는 메서드는 객체의 실제 유형에 따라 달라지며 런타임에 동적으로 바인딩됩니다. 예를 들어 func("hello")가 호출되면 편집기는 동적 바인딩을 사용하여 func(String)을 호출하는 명령을 생성합니다.
4) 프로그램이 실행 중일 때 동적 바인딩을 사용하여 메소드를 호출하면 JVM은 반드시 obj가 참조하는 객체의 실제 유형에 가장 적합한 클래스의 메소드를 호출합니다. obj의 실제 유형은 Animal의 하위 클래스인 Cat이라고 가정하고, Cat에 func(String)이 정의되어 있으면 호출되고, 그렇지 않으면 Animal 클래스와 그 상위 클래스에서 찾습니다.
메서드가 호출될 때마다 검색이 필요하므로 시간이 많이 소요되므로 JVM은 각 클래스에 대해 이름, 매개변수 서명이 나열된 메소드 테이블(메서드 레이블)을 미리 생성합니다. 그리고 그것이 속한 클래스. 이런 방식으로 메소드가 실제로 호출될 때 가상 머신은 이 테이블만 조회하면 됩니다. 위의 예에서 JVM은 Cat 클래스의 메소드 테이블에서 func("hello") 호출과 일치하는 메소드를 검색합니다. 이 메서드는 Cat.func(String) 또는 Animal.func(String)일 수 있습니다. super.func("hello")를 호출하면 컴파일러는 상위 클래스의 메소드 테이블을 검색합니다.
Animal 클래스에 세 가지 메소드(cry(), getName() 및 getAge())가 포함되어 있다고 가정하면 해당 메소드 테이블은 다음과 같습니다.
cry() ->
getName() -> Animal.getName()
getAge() -> Animal.getAge()
사실 Animal에는 기본 상위 클래스인 Object도 있습니다(나중에 설명함) )은 Object 메서드를 상속하므로 위에 나열된 메서드는 완전하지 않습니다.
Cat 클래스가 Animal 클래스의 cry() 메소드를 다루고 새로운 메소드 climbTree()를 추가한다고 가정하면 해당 매개변수 목록은 다음과 같습니다.
cry() ->
getName() -> Animal.getName()
getAge() -> Animal.getAge()
climbTree() -> Cat.climbTree()
실행 중 obj.cry() 메소드를 호출하는 과정은 다음과 같습니다.
JVM은 먼저 실제 obj 유형의 메소드 테이블에 액세스합니다. 이는 Animal 클래스의 메소드 테이블일 수도 있고, Animal 클래스의 메소드 테이블일 수도 있습니다. Cat 클래스와 그 하위 클래스.
JVM은 메소드 테이블에서 cry()와 일치하는 메소드를 검색합니다. 일단 발견되면 해당 메소드가 어떤 클래스에 속하는지 알 수 있습니다.
JVM이 이 메소드를 호출합니다.
Java 다형성 객체의 유형 변환 및 동적 바인딩에 대한 자세한 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!