누구나 Java에서 동적 다형성 과 정적 다형성 의 차이점을 설명하는 간단한 예를 제공 할 수 있습니까 ?
누구나 Java에서 동적 다형성 과 정적 다형성 의 차이점을 설명하는 간단한 예를 제공 할 수 있습니까 ?
답변:
다형성
1. 정적 바인딩 / 컴파일 타임 바인딩 / Early 바인딩 / 메소드 오버로딩. (동일 클래스)
2. 동적 바인딩 / 런타임 바인딩 / 늦은 바인딩 / 메소드 재정의 (다른 클래스에서)
class Calculation {
void sum(int a,int b){System.out.println(a+b);}
void sum(int a,int b,int c){System.out.println(a+b+c);}
public static void main(String args[]) {
Calculation obj=new Calculation();
obj.sum(10,10,10); // 30
obj.sum(20,20); //40
}
}
class Animal {
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move();//output: Animals can move
b.move();//output:Dogs can walk and run
}
}
Animal reference but Dog object
궁금합니다. 왜 사용할 수 Dog reference and dog object
없습니까?
동적 (런타임) 다형성 은 런타임에 존재하는 다형성입니다. 여기서 Java 컴파일러는 컴파일 시간에 호출되는 메서드를 이해하지 못합니다. JVM만이 런타임에 호출되는 메소드를 결정합니다. 인스턴스 메서드를 사용한 메서드 오버로딩 및 메서드 재정의는 동적 다형성의 예입니다.
예를 들면
여러 유형의 문서를 직렬화 및 역 직렬화하는 애플리케이션을 고려하십시오.
기본 클래스로 'Document'를 가질 수 있으며 여기에서 파생되는 다른 문서 유형 클래스를 가질 수 있습니다. 예 : XMLDocument, WordDocument 등
문서 클래스는 'Serialize ()'및 'De-serialize ()'메서드를 가상으로 정의하고 각 파생 클래스는 문서의 실제 내용을 기반으로 자체 방식으로 이러한 메서드를 구현합니다.
서로 다른 유형의 문서를 직렬화 / 비 직렬화해야하는 경우 문서 객체는 'Document'클래스 참조 (또는 포인터)에 의해 참조되고 'Serialize ()'또는 'De-serialize ()'메서드가 호출 될 때 그 위에 적절한 버전의 가상 메서드가 호출됩니다.
정적 (컴파일 시간) 다형성 은 컴파일 시간에 나타나는 입니다. 여기서 Java 컴파일러는 호출되는 메소드를 알고 있습니다. 정적 메서드를 사용한 메서드 오버로딩 및 메서드 재정의 private 또는 final 메서드를 사용한 메서드 재정의는 정적 다형성의 예입니다.
예를 들면
직원 객체에는 두 개의 print () 메서드가있을 수 있습니다. 하나는 인수를 사용하지 않고 다른 하나는 직원 데이터와 함께 표시 할 접두사 문자열을 사용합니다.
이러한 인터페이스가 주어지면 print () 메서드가 인수없이 호출 될 때 컴파일러는 함수 인수를보고 어떤 함수가 호출되어야하는지 알고 그에 따라 객체 코드를 생성합니다.
자세한 내용은 "What is Polymorphism"(Google it)을 참조하십시오.
바인딩은 메서드 호출과 메서드 정의 간의 링크를 나타냅니다.
이 그림은 구속력이있는 것을 명확하게 보여줍니다.
이 그림에서“a1.methodOne ()”호출은 해당 methodOne () 정의에 바인딩되고“a1.methodTwo ()”호출은 해당 methodTwo () 정의에 바인딩됩니다.
모든 메서드 호출에는 적절한 메서드 정의가 있어야합니다. 이것은 자바의 규칙입니다. 컴파일러가 모든 메서드 호출에 대해 적절한 메서드 정의를 보지 못하면 오류가 발생합니다.
이제 java의 정적 바인딩 및 동적 바인딩에 대해 알아보십시오.
자바의 정적 바인딩 :
정적 바인딩은 컴파일 중에 발생하는 바인딩입니다. 프로그램이 실제로 실행되기 전에 바인딩이 발생하기 때문에 초기 바인딩이라고도합니다.
.
정적 바인딩은 아래 그림과 같이 설명 할 수 있습니다.
이 그림에서 'a1'은 클래스 A의 객체를 가리키는 클래스 A의 참조 변수입니다. 'a2'는 클래스 A의 참조 변수이지만 클래스 B의 객체를 가리키는 것입니다.
컴파일하는 동안 바인딩하는 동안 컴파일러는 특정 참조 변수가 가리키는 개체의 유형을 확인하지 않습니다. 메소드가 호출되는 참조 변수의 유형을 확인하고 해당 유형에 대한 메소드 정의가 있는지 확인합니다.
예를 들어 위 그림의“a1.method ()”메서드 호출의 경우 컴파일러는 Class A에 method ()에 대한 메서드 정의가 있는지 확인합니다. 'a1'은 Class A 타입이기 때문입니다. 마찬가지로“a2.method ()”메서드 호출의 경우 Class A에 method ()에 대한 메서드 정의가 있는지 확인합니다. 'a2'도 Class A 타입이기 때문입니다. 'a1'과 'a2'가 가리키는 개체는 확인하지 않습니다. 이러한 유형의 바인딩을 정적 바인딩이라고합니다.
자바의 동적 바인딩 :
동적 바인딩은 런타임 중에 발생하는 바인딩입니다. 프로그램이 실제로 실행 중일 때 바인딩이 발생하기 때문에 후기 바인딩이라고도합니다.
런타임 동안 실제 개체가 바인딩에 사용됩니다. 예를 들어 위의 그림에서“a1.method ()”를 호출하면 'a1'이 가리키는 실제 객체의 method ()가 호출됩니다. “a2.method ()”호출의 경우 'a2'가 가리키는 실제 객체의 method ()가 호출됩니다. 이러한 유형의 바인딩을 동적 바인딩이라고합니다.
위 예제의 동적 바인딩은 아래와 같이 설명 할 수 있습니다.
다형성 : 다형성은 개체가 다양한 형태를 취하는 능력입니다. OOP에서 다형성의 가장 일반적인 사용은 부모 클래스 참조가 자식 클래스 개체를 참조하는 데 사용될 때 발생합니다.
동적 바인딩 / 런타임 다형성 :
메서드 재정의라고도하는 런타임 다형성. 이 메커니즘에서는 재정의 된 함수에 대한 호출이 런타임에 해결됩니다.
public class DynamicBindingTest {
public static void main(String args[]) {
Vehicle vehicle = new Car(); //here Type is vehicle but object will be Car
vehicle.start(); //Car's start called because start() is overridden method
}
}
class Vehicle {
public void start() {
System.out.println("Inside start method of Vehicle");
}
}
class Car extends Vehicle {
@Override
public void start() {
System.out.println("Inside start method of Car");
}
}
산출:
자동차 내부 시동 방법
정적 바인딩 / 컴파일 시간 다형성 :
호출 할 메서드는 컴파일 타임에만 결정됩니다.
public class StaticBindingTest {
public static void main(String args[]) {
Collection c = new HashSet();
StaticBindingTest et = new StaticBindingTest();
et.sort(c);
}
//overloaded method takes Collection argument
public Collection sort(Collection c){
System.out.println("Inside Collection sort method");
return c;
}
//another overloaded method which takes HashSet argument which is sub class
public Collection sort(HashSet hs){
System.out.println("Inside HashSet sort method");
return hs;
}
}
출력 : 내부 컬렉션 정렬 방법
간단히 말해서 :
정적 다형성 : 동일한 메서드 이름이다른 유형 또는 매개 변수 수로 오버로드 됩니다. 동일한 클래스 (다른 서명). 대상 메서드 호출은 컴파일 타임에 해결됩니다.
동적 다형성 : 동일한 방법이동일한 서명으로 재정의 됩니다. 다른 클래스의 . 메소드가 호출되는 객체의 유형은 컴파일 타임에 알려지지 않지만 런타임에 결정됩니다.
일반적으로 과부하는 다형성으로 간주되지 않습니다.
자바 튜토리얼 페이지에서 :
클래스의 하위 클래스는 고유 한 동작을 정의 할 수 있지만 부모 클래스와 동일한 기능을 일부 공유 할 수 있습니다.
Generally overloading won't be considered as polymorphism.
이 점에 대해 자세히 설명해 주시겠습니까?
메서드 오버로딩 은 정적 다형성 이라고하며 컴파일 시간 다형성 또는 정적 바인딩 이라고도합니다. 오버로드 된 메서드 호출은 인수 목록과 메서드를 호출하는 참조를 기반으로 컴파일러에 의해 컴파일 타임에 해결되기 때문입니다.
그리고 방법 재정이 로 알려져 동적 다형성 또는 단순 다형성 또는 런타임 디스패치 방법 또는 동적 바인딩 재정의 된 메서드 호출이 실행시에 해결하세요 때문이다.
이것이 왜 그런지 이해하기 위해 예제 Mammal
와 Human
클래스를 살펴 보겠습니다.
class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
class Human extends Mammal {
@Override
public void speak() { System.out.println("Hello"); }
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
}
아래 코드 줄에 출력과 바이트 코드를 포함했습니다.
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
그리고 위의 코드를 살펴보면 humanMammal.speak (), human.speak () 및 human.speak ( "Hindi")의 바이트 코드가 컴파일러가 인수 목록을 기반으로 구분할 수 있기 때문에 완전히 다른 것을 알 수 있습니다. 및 클래스 참조. 그리고 이것이 왜 Method Overloading 이 Static Polymorphism으로 알려진 입니다.
그러나 anyMammal.speak () 및 humanMammal.speak ()의 바이트 코드는 컴파일러에 따라 두 메서드가 모두 Mammal 참조에서 호출되지만 런타임에서 JVM이 참조가 보유하고있는 객체를 알고 JVM을 호출하기 때문에 두 메서드 호출의 출력이 다르기 때문에 동일합니다. 객체에 대한 메서드이고 이것이 메서드 재정의가 동적 다형성으로 알려진 이유입니다.
따라서 위의 코드와 바이트 코드에서 컴파일 단계에서 메서드 호출이 참조 유형에서 고려된다는 것이 분명합니다. 그러나 실행시 참조가 보유하고있는 객체에서 메소드가 호출됩니다.
이것에 대해 더 알고 싶다면 JVM이 메소드 오버로딩 및 오버 라이딩을 내부적으로 처리하는 방법 에 대해 자세히 읽어 볼 수 있습니다 .
정적 다형성 : 수행 할 방법을 결정하는 결정은 컴파일 시간 동안 결정됩니다. 메서드 오버로딩이 그 예가 될 수 있습니다.
동적 다형성 : 실행할 방법을 선택하는 결정은 런타임 중에 설정됩니다. 메서드 재정의가 이에 대한 예가 될 수 있습니다.
다형성은 동일한 트리거에 대해 개체가 다르게 작동하는 능력을 나타냅니다.
정적 다형성 (컴파일 시간 다형성)
동적 다형성 (런타임 다형성)
컴파일 시간 다형성 (Static Binding / Early Binding) : 정적 다형성에서 우리 코드에서 메서드를 호출하면 실제로 호출 할 메서드의 정의는 컴파일 타임에만 해결됩니다.
(또는)
컴파일 타임에 Java는 메서드 서명을 확인하여 호출 할 메서드를 알고 있습니다. 따라서 이것을 컴파일 타임 다형성 또는 정적 바인딩이라고합니다.
Dynamic Polymorphism (Late Binding / Runtime Polymorphism) : 런타임에 Java는 런타임까지 참조하여 실제로 어떤 객체를 가리키고 있는지 확인합니다. 메서드 확인은 런타임 다형성이라고 부르기 때문에 런타임에 수행되었습니다.
아래 코드를 고려하십시오.
public class X
{
public void methodA() // Base class method
{
System.out.println ("hello, I'm methodA of class X");
}
}
public class Y extends X
{
public void methodA() // Derived Class method
{
System.out.println ("hello, I'm methodA of class Y");
}
}
public class Z
{
public static void main (String args []) {
//this takes input from the user during runtime
System.out.println("Enter x or y");
Scanner scanner = new Scanner(System.in);
String value= scanner.nextLine();
X obj1 = null;
if(value.equals("x"))
obj1 = new X(); // Reference and object X
else if(value.equals("y"))
obj2 = new Y(); // X reference but Y object
else
System.out.println("Invalid param value");
obj1.methodA();
}
}
이제 코드를 보면 methodA ()의 어떤 구현이 실행 될지 결코 알 수 없습니다. 이는 런타임 중에 사용자가 제공하는 값에 따라 다르기 때문입니다. 따라서 어떤 메서드가 호출 될 것인지는 런타임 동안에 만 결정됩니다. 따라서 런타임 다형성.
메서드 오버로딩은 컴파일 시간 다형성입니다. 개념을 이해하기 위해 예제를 살펴 보겠습니다.
class Person //person.java file
{
public static void main ( String[] args )
{
Eat e = new Eat();
e.eat(noodle); //line 6
}
void eat (Noodles n) //Noodles is a object line 8
{
}
void eat ( Pizza p) //Pizza is a object
{
}
}
이 예에서 Person에는 Pizza 또는 Noodles를 먹을 수 있음을 나타내는 eat 메서드가 있습니다. 이 Person.java를 컴파일 할 때 eat 메소드가 오버로드된다는 점에서 컴파일러는 8 행에 지정된 메소드 정의를 사용하여 "e.eat (noodles) [6 행에 있음] 메소드 호출을 해결합니다. 즉, 국수를 매개 변수로 취하는 메소드입니다. 전체 프로세스는 Compiler에 의해 이루어 지므로 Compile time Polymorphism입니다. 메서드 호출을 메서드 정의로 대체하는 과정을 바인딩이라고하며,이 경우 컴파일러에 의해 수행되므로 얼리 바인딩이라고합니다.
Naresh의 답변에 이어 동적 다형성은 가상 머신의 존재와 기본적으로 실행되는 코드가 아닌 런타임에 코드를 해석 할 수있는 능력 때문에 Java에서 '동적'일뿐입니다.
C ++에서는 gcc를 사용하여 네이티브 바이너리로 컴파일되는 경우 컴파일 타임에 해결되어야합니다. 그러나 가상 테이블의 런타임 점프 및 썽 크는 여전히 '조회'또는 '동적'이라고합니다. C가 B를 상속하고를 선언B* b = new C(); b->method1();
하면 컴파일러가 b를 C 내부의 B 개체를 가리 키도록 확인합니다 (단순한 클래스가 클래스 상황을 상속하는 경우 C 및 C 내부의 B 개체는 동일한 메모리 주소에서 시작하므로 아무것도 수행해야합니다. 둘 다 사용하는 vptr을 가리 킵니다). C가 B와 A를 상속하는 경우 method1에 대한 C 항목 내부의 A 개체의 가상 함수 테이블에는 캡슐화 C 개체의 시작에 대한 포인터를 오프셋 한 다음 실제 A :: method1 ()에 전달하는 썽크가 있습니다. C가 재정의 한 텍스트 세그먼트에서. 에 대한C* c = new C(); c->method1()
, c는 이미 외부 C 객체를 가리키고 포인터는 텍스트 세그먼트의 C :: method1 ()에 전달됩니다. 인용하다: http://www.programmersought.com/article/2572545946/
Java for B b = new C(); b.method1();
에서 가상 머신은 b와 쌍을 이루는 객체의 유형을 동적으로 확인할 수 있으며 올바른 포인터를 전달하고 올바른 메소드를 호출 할 수 있습니다. 가상 머신의 추가 단계는 컴파일 시간에 알 수있는 경우에도 컴파일 시간에 해석되는 가상 함수 테이블 또는 유형의 필요성을 제거합니다. 가상 머신이 관련되고 코드가 바이트 코드로만 컴파일 될 때 의미가있는 다른 방법입니다.