source

Java에서의 동적 다형과 정적 다형의 차이점은 무엇입니까?

manysource 2022. 11. 4. 23:30

Java에서의 동적 다형과 정적 다형의 차이점은 무엇입니까?

Java에서 동적 다형과 정적 다형의 차이를 설명하는 간단한 예를 들어줄 수 있는 사람이 있나요?

다형성

1. 정적 바인딩/컴파일 타임 바인딩/얼리 바인딩/메서드 오버로드(동급)

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
   }
}
  • 메서드 오버로드는 정적 다형성의 예입니다.

  • 반면 오버라이드는 동적 다형성의 예가 될 수 있습니다.

    오버로드의 경우 컴파일러는 콜에 링크하는 메서드를 컴파일 시에 인식하기 때문입니다.그러나 동적 다형성에 대해 런타임에 결정됩니다.

동적(런타임) 다형성은 런타임에 존재하는 다형성입니다.여기서 Java 컴파일러는 컴파일 시에 어떤 메서드가 호출되는지 이해하지 못합니다.런타임에 호출되는 메서드는 JVM만 결정합니다.인스턴스 메서드를 사용한 메서드 오버로드 및 메서드 덮어쓰기는 동적 다형성의 예입니다.

예를들면,

  • 여러 유형의 문서를 직렬화하고 직렬 해제하는 응용프로그램을 고려합니다.

  • 기본 클래스로 'Document'를 사용할 수 있으며 여기서 파생되는 다양한 문서 유형 클래스(XMLDocument, WordDocument 등)를 사용할 수 있습니다.

  • 문서 클래스는 "Serialize()" 메서드와 "De-serialize()" 메서드를 가상으로 정의하고 파생된 각 클래스는 문서의 실제 내용을 기반으로 고유한 방식으로 이러한 메서드를 구현합니다.

  • 다른 유형의 문서를 직렬화/비직렬화해야 할 경우 문서 객체는 "Document" 클래스 참조(또는 포인터)에 의해 참조되며, "Serialize()" 또는 "De-serialize()" 메서드가 호출되면 적절한 버전의 가상 메서드가 호출됩니다.

정적(컴파일 시간) 다형성은 컴파일 시 나타나는 다형성이다.여기서 Java 컴파일러는 어떤 메서드가 호출되는지 알고 있습니다.정적 메서드를 사용한 메서드 오버로드 및 메서드 오버라이드.프라이빗 메서드 또는 최종 메서드를 사용한 메서드 오버라이드는 정적 다형성의 예입니다.

예를들면,

  • 종업원 오브젝트에는 2개의 print() 메서드를 사용할 수 있습니다.하나는 인수를 사용하지 않는 메서드와 프레픽스 문자열을 사용하여 종업원 데이터와 함께 표시할 수 있습니다.

  • 이러한 인터페이스에서 print() 메서드가 인수 없이 호출되면 컴파일러는 함수 인수를 보고 호출해야 할 함수가 무엇인지 알고 그에 따라 객체 코드를 생성합니다.

자세한 내용은 "다형이란 무엇인가"(Google it)를 참조하십시오.

바인딩은 메서드 호출과 메서드 정의 사이의 링크를 나타냅니다.

이 그림은 구속력이 있는 것을 명확하게 보여준다.

바인딩

이 그림에서는 "a1.methodOne()" 콜은 대응하는 methodOne() 정의에 바인딩되어 있으며 "a1.methodTwo()" 콜은 대응하는 methodTwo() 정의에 바인딩되어 있습니다.

모든 메서드 호출에 대해 적절한 메서드 정의가 있어야 합니다.이것은 Java의 규칙입니다.컴파일러가 모든 메서드 호출에 대해 적절한 메서드 정의를 인식하지 못할 경우 오류가 발생합니다.

이제 java에서의 정적 바인딩과 동적 바인딩에 대해 살펴보겠습니다.

Java에서의 스태틱바인딩:

정적 바인딩은 컴파일 중에 발생하는 바인딩입니다.바인딩은 프로그램이 실제로 실행되기 전에 발생하기 때문에 조기 바인딩이라고도 합니다.

.

정적 바인딩은 아래 그림과 같이 시연할 수 있습니다.

여기에 이미지 설명 입력

이 그림에서 'a1'은 클래스 A의 오브젝트를 가리키는 클래스 A의 참조 변수이며, 'a2'도 클래스 A의 오브젝트를 가리키는 참조 변수이다.

컴파일 중 바인딩 중 컴파일러는 특정 참조 변수가 가리키는 객체의 유형을 확인하지 않습니다.메서드가 호출되는 참조 변수 유형을 확인하고 해당 유형에 메서드 정의가 있는지 확인합니다.

예를 들어 위의 그림에서 "a1.method()" 메서드 호출의 경우 컴파일러는 클래스 A에 method() 메서드 정의가 있는지 확인합니다.왜냐하면 'a1'은 클래스 A 타입이기 때문입니다.마찬가지로 "a2.method()" 메서드 호출의 경우 클래스 A에 method() 메서드 정의가 있는지 확인합니다.왜냐하면 'a2'도 클래스 A 타입이기 때문입니다.'a1'과 'a2'가 어떤 개체를 가리키는지 확인하지 않습니다.이런 유형의 바인딩을 정적 바인딩이라고 합니다.

Java에서의 동적 바인딩:

동적 바인딩은 런타임 중에 발생하는 바인딩입니다.바인딩은 프로그램이 실제로 실행 중일 때 발생하므로 레이트 바인딩이라고도 합니다.

런타임 중에는 실제 개체가 바인딩에 사용됩니다.예를 들어 위의 그림에서 "a1.method()" 호출의 경우 "a1"이 가리키는 실제 객체의 method()가 호출됩니다."a2.method()" 호출의 경우 "a2"가 가리키는 실제 객체의 method()가 호출됩니다.이런 유형의 바인딩을 동적 바인딩이라고 합니다.

위 예의 동적 바인딩은 다음과 같이 시연할 수 있습니다.

여기에 이미지 설명 입력

참조 스태틱바인딩 및 다이내믹바인딩 자바

메서드 오버로드는 메서드콜과 메서드 정의 간의 메서드바인딩이 컴파일 시에 이루어지며 클래스의 참조(컴파일 시에 작성되어 스택으로 이동)에 의존하기 때문에 컴파일 시간/스태틱 다형성의 예입니다.

메서드 오버라이드는 실행 시 메서드콜과 메서드 정의 간의 메서드바인딩이 발생하고 클래스의 오브젝트(실행 시에 작성되어 힙으로 이동)에 의존하기 때문에 실행 시/다이나믹 다형성의 예입니다.

간단히 말하면:

스태틱 다형성 : 같은 메서드명이 다른 타입 또는 같은 클래스(다른 시그니처)의 파라미터 수로 오버로드되어 있습니다.타깃 메서드 호출은 컴파일 시 해결됩니다.

동적 다형성:같은 메서드는 다른 클래스의 동일한 시그니처로 덮어씁니다.메서드가 호출되는 객체의 유형은 컴파일 시 알 수 없지만 실행 시 결정됩니다.

일반적으로 과부하는 다형성으로 간주되지 않습니다.

Java 튜토리얼 페이지에서:

클래스의 서브클래스는 독자적인 동작을 정의할 수 있지만 부모 클래스의 동일한 기능 중 일부를 공유할 수 있습니다.

메서드 오버로드는 정적 다형성 또는 컴파일 시간 다형성 또는 정적 바인딩이라고도 합니다.왜냐하면 오버로드된 메서드 호출은 컴파일러에 의해 인수 목록과 메서드 호출을 호출하는 참조에 따라 해결되기 때문입니다.

Method Overriding은 오버라이드된 메서드 호출이 실행 시 해결되기 때문에 동적 다형성 또는 단순 다형성 또는 런타임 메서드 디스패치 또는 동적 바인딩으로 알려져 있습니다.

예를 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

위의 코드를 보면 컴파일러가 인수 목록과 클래스 참조에 따라 구분할 수 있기 때문에 humanMamal.speak(), human.speak() 및 human.speak("Hindi")의 바이트 코드가 완전히 다르다는 것을 알 수 있습니다.그래서 메서드 오버로딩이 정적 다형성이라고 불립니다.

그러나 anyMamal.speak()와 humanMamal.speak()의 바이트코드는 컴파일러에 따르면 두 메서드가 모두 포유류의 참조에서 호출되지만 두 메서드 호출의 출력은 다르기 때문에 런타임에 JVM이 참조를 보유하고 있는 객체를 호출하고 JVM이 메서드 오버라이드(Method Overriding)를 Dynamic Po라고 부릅니다.리모르피즘

따라서 위의 코드와 바이트 코드를 통해 컴파일 단계 호출 방식이 참조 유형에서 고려되는 것이 분명합니다.그러나 실행 시 참조가 있는 개체에서 메서드가 호출됩니다.

자세한 내용은 "JVM이 내부적으로 메서드 오버로드 오버라이딩을 처리하는 방법"을 참조하십시오.

다형성:다형성은 물체의 다양한 형태를 취할 수 있는 능력이다.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;
    }

}

출력: 내부 컬렉션 정렬 방법

정적 다형성: 컴파일 중에 어떤 방법을 실행할지 결정하는 곳입니다.메서드 오버로드가 그 예입니다.

Dynamic Polymorphism: 런타임 중에 실행할 방법을 선택하는 데 사용됩니다.메서드 오버라이드(Method Override)가 그 예입니다.

다형성은 동일한 트리거에 대해 다르게 동작하는 개체의 기능을 의미합니다.

정적 다형성(컴파일 시간 다형성)

  • 정적 다형성은 컴파일 시간 동안 실행할 방법을 결정합니다.
  • 메서드 오버로드는 스태틱 다형성의 일례이며 스태틱 다형성을 발생시키기 위해 요구됩니다.
  • 정적 바인딩을 통해 정적 다형성을 실현합니다.
  • 정적 다형성은 같은 클래스에서 발생합니다.
  • 정적 다형성에는 개체 할당이 필요하지 않습니다.
  • 정적 다형에는 상속이 포함되지 않습니다.

동적 다형성(런타임 다형성)

  • 동적 다형성은 런타임에 실행할 메서드를 결정합니다.
  • Method Overriding은 동적 다형성의 한 예이며 동적 다형이 발생하도록 요구됩니다.
  • 동적 바인딩을 통해 동적 다형성을 실현합니다.
  • 동적 다형성은 다른 클래스 간에 발생합니다.
  • 동적 다형성을 위해 하위 클래스 개체가 슈퍼 클래스 개체에 할당되는 경우 필요합니다.
  • 동적 다형성에 관련된 상속입니다.

컴파일 시간 다형성(정적 바인딩/조기 바인딩):정적 다형성에서는 코드의 메서드를 호출하면 실제로 호출되는 메서드의 정의는 컴파일 시에만 해결됩니다.

(또는)

컴파일 시 Java는 메서드 시그니처를 체크함으로써 어떤 메서드를 호출해야 하는지 알고 있습니다.이를 컴파일 시간 다형성 또는 정적 바인딩이라고 합니다.

동적 다형성(최신 바인딩/런타임 다형성):실행 시 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.java를 컴파일할 때 메서드 eat(면)이 오버로드되는 것은 컴파일러가 메서드 호출 "e.eat(면) [line 6]를 8행에서 지정한 메서드 정의로 해결합니다.이것은 면을 파라미터로 하는 메서드이며 전체 프로세스는 컴파일러에 의해 이루어지기 때문에 컴파일 타임 폴리몰피즘입니다.메서드 호출을 메서드 정의로 대체하는 프로세스를 바인딩이라고 합니다.이 경우 컴파일러에 의해 처리되므로 얼리 바인딩이라고 부릅니다.

Nareh의 답변에 따르면 동적 다형성은 Java에서만 '동적'입니다.이는 가상 머신의 존재와 코드가 네이티브로 실행되는 것이 아니라 런타임에 코드를 해석할 수 있기 때문입니다.

C++에서는 gcc를 사용하여 네이티브 바이너리로 컴파일된 경우 컴파일 시 해결되어야 합니다.그러나 가상 테이블의 런타임 점프와 트렁크는 여전히 '룩업' 또는 '다이나믹'이라고 불립니다.C가 B를 상속하고, 당신이 선언하는 경우B* b = new C(); b->method1();, b는 컴파일러에 의해 C 내부의 B 오브젝트를 가리키도록 해결됩니다(단순한 클래스의 경우 C와 C 내부의 B 오브젝트는 같은 메모리주소에서 시작되므로 아무것도 할 필요가 없습니다.이 오브젝트는 둘 다 사용하는vptr을 가리키고 있습니다).C가 B와 A를 상속하는 경우 method1의 C 엔트리 내의 A 객체의 가상 함수 테이블에는 thunk가 있으며, 이를 통해 캡슐화 C 객체의 선두에 대한 포인터가 오프셋되어 C가 덮어쓴 텍스트세그먼트 내의 실제 A:method1()에 전달됩니다.위해서C* c = new C(); c->method1()c는 이미 외부 C 객체를 가리키고 있으며 포인터는 텍스트세그먼트 내의 C::method1()에 전달됩니다.참조처: http://www.programmersought.com/article/2572545946/

자바어,B b = new C(); b.method1();가상 시스템은 b와 쌍으로 구성된 개체의 유형을 동적으로 확인하고 올바른 포인터를 전달하고 올바른 메서드를 호출할 수 있습니다.가상 시스템의 추가 단계를 통해 컴파일 시 가상 기능 테이블이나 유형을 알 수 있는 경우에도 컴파일 시 확인할 필요가 없습니다.이는 가상 머신이 관여하고 코드가 바이트 코드로 컴파일되는 경우에 적합한 다른 방법입니다.

언급URL : https://stackoverflow.com/questions/20783266/what-is-the-difference-between-dynamic-and-static-polymorphism-in-java