Programing

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

lottogame 2020. 8. 13. 07:39
반응형

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
   }
}

  • 메서드 오버로딩은 정적 다형성의 예입니다.

  • 재정의는 동적 다형성의 예가 될 것입니다.

    오버로딩의 경우 컴파일 타임에 컴파일러가 호출에 연결할 메서드를 알고 있기 때문입니다. 그러나 동적 다형성을 위해 런타임에 결정됩니다.


동적 (런타임) 다형성 은 런타임에 존재하는 다형성입니다. 여기서 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;
    }

}

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


간단히 말해서 :

정적 다형성 : 동일한 메서드 이름이 동일한 클래스 (다른 서명)에서 다른 유형 또는 매개 변수 수로 오버로드 됩니다. 대상 메서드 호출은 컴파일 타임에 해결됩니다.

동적 다형성 : 동일한 메서드가 다른 클래스의 동일한 서명으로 재정의 됩니다. 메소드가 호출되는 객체의 유형은 컴파일 타임에 알려지지 않지만 런타임에 결정됩니다.

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

자바 튜토리얼 페이지에서 :

클래스의 하위 클래스는 고유 한 동작을 정의 할 수 있지만 상위 클래스와 동일한 기능을 일부 공유 할 수 있습니다.


메서드 오버로딩 은 컴파일 타임 / 정적 다형성의 한 예입니다. 메서드 호출과 메서드 정의 간의 메서드 바인딩은 컴파일 타임에 발생하고 클래스 참조 (컴파일 타임에 생성 된 참조가 스택으로 이동)에 의존하기 때문입니다.

메서드 재정의 는 메서드 호출과 메서드 정의 간의 메서드 바인딩이 런타임에 발생하고 클래스의 개체 (런타임에 생성되고 힙으로 이동하는 개체)에 따라 다르기 때문에 런타임 / 동적 다형성의 예입니다.


정적 다형성 : 수행 할 방법을 결정하는 결정은 컴파일 시간 동안 결정됩니다. 메서드 오버로딩이 그 예가 될 수 있습니다.

동적 다형성 : 실행할 방법을 선택하는 결정은 런타임 중에 설정됩니다. 메서드 재정의가 이에 대한 예가 될 수 있습니다.


다형성은 동일한 트리거에 대해 개체가 다르게 작동하는 능력을 나타냅니다.

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

  • 정적 다형성은 컴파일 시간 동안 실행할 메서드를 결정합니다.
  • 메서드 오버로딩은 정적 다형성의 한 예이며 정적 다형성이 발생해야합니다.
  • 정적 바인딩을 통해 달성 된 정적 다형성.
  • 정적 다형성은 같은 클래스에서 발생합니다.
  • 정적 다형성에는 객체 할당이 필요하지 않습니다.
  • 정적 다형성과 관련되지 않은 상속.

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

  • 동적 다형성은 런타임에 실행할 방법을 결정합니다.
  • 메서드 재정의는 동적 다형성의 한 예이며 동적 다형성이 발생해야합니다.
  • 동적 바인딩을 통해 달성 된 동적 다형성.
  • 동적 다형성은 서로 다른 클래스간에 발생합니다.
  • 동적 다형성을 위해 하위 클래스 개체가 수퍼 클래스 개체에 할당되는 경우 필요합니다.
  • 동적 다형성에 관련된 상속.

메서드 오버로딩정적 다형성 이라고하며 컴파일 시간 다형성 또는 정적 바인딩 이라고도합니다. 오버로드 된 메서드 호출은 인수 목록과 메서드를 호출하는 참조를 기반으로 컴파일러가 컴파일 타임에 해결하기 때문입니다.

그리고 방법 재정이 로 알려져 동적 다형성 또는 단순 다형성 또는 런타임 방법 파견 또는 동적 바인딩 재정의 된 메서드 호출이 실행시에 해결하세요 때문이다.

이것이 왜 그런지 이해하기 위해 예제 MammalHuman클래스를 살펴 보겠습니다.

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

And by looking at above code we can see that the bytecodes of humanMammal.speak() , human.speak() and human.speak("Hindi") are totally different because the compiler is able to differentiate between them based on the argument list and class reference. And this is why Method Overloading is known as Static Polymorphism.

But bytecode for anyMammal.speak() and humanMammal.speak() is same because according to compiler both methods are called on Mammal reference but the output for both method calls is different because at runtime JVM knows what object a reference is holding and JVM calls the method on the object and this is why Method Overriding is known as Dynamic Polymorphism.

So from above code and bytecode, it is clear that during compilation phase calling method is considered from the reference type. But at execution time method will be called from the object which the reference is holding.

If you want to know more about this you can read more on How Does JVM Handle Method Overloading and Overriding Internally.


Compile time polymorphism(Static Binding/Early Binding): In static polymorphism, if we call a method in our code then which definition of that method is to be called actually is resolved at compile time only.

(or)

At compile time, Java knows which method to invoke by checking the method signatures. So, this is called compile-time polymorphism or static binding.

Dynamic Polymorphism(Late Binding/ Runtime Polymorphism): At run time, Java waits until runtime to determine which object is actually being pointed to by the reference. Method resolution was taken at runtime, due to that we call as run time polymorphism.


Consider the code below:

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();
}
}

Now, looking at the code you can never tell which implementation of methodA() will be executed, Because it depends on what value the user gives during runtime. So, it is only decided during the runtime as to which method will be called. Hence, Runtime polymorphism.


Method overloading is a compile time polymorphism, let's take an example to understand the concept.

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입니다. 메서드 호출을 메서드 정의로 대체하는 과정을 바인딩이라고하며,이 경우 컴파일러에 의해 수행되므로 얼리 바인딩이라고합니다.

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

반응형