IT

정적 대.

lottoking 2020. 10. 10. 10:23

정적 대. 자바의 동적 바인딩


현재 클래스 중 하나에 대한 할당을 수행하고 여기에서 Java 구문을 사용하여 정적동적 바인딩 의 예제를 제공해야합니다 .

정적 바인딩은 발생하는 발생하고 동적 바인딩은 실행 타임에 발생하는 기본 개념을 이해합니다.

이 예제를 제공하는 온라인 정적 바인딩 예제를 찾았습니다.

public static void callEat(Animal animal) {
    System.out.println("Animal is eating");
}

public static void callEat(Dog dog) {
    System.out.println("Dog is eating");
}

public static void main(String args[])
{
    Animal a = new Dog();
    callEat(a);
}

이것은 그리고 호출이 callEat정적 바인딩 사용 하기 때문에 "동물이 먹고"인쇄을 하지만, 이것이 정적 바인딩으로 간주 되는 이유를모르겠습니다 .

지금까지 내가 본 소스 중 어느 것도 내가 따를 수있는 방식으로 설명하지 않습니다.


에서 Javarevisited 블로그 게시물 :

다음은 정적 바인딩과 동적 바인딩의 몇 가지 중요한 차이점입니다.

  1. Java의 정적 바인딩은 시간 동안 발생하고 동적 바인딩은 실행 중에 발생합니다.
  2. private, finalstatic방법과 결합 정적 변수를 사용하여 가상 메소드 런타임에 결합됩니다.
  3. 정적 바인딩은 바인딩을 위해 Type( classJava에서) 정보를 사용하는 반면 동적 바인딩은 바인딩을 해결하기 위해 객체를 사용합니다.
  4. 오버로드 된 메서드는 정적 바인딩을 사용하여 연결되는 반면 재정의 된 메서드는 가동에 동적 바인딩을 사용하여 연결됩니다.

다음은 Java의 정적 및 동적 바인딩을 이해하는 데 도움이되는 예입니다.

자바의 정적 바인딩 예제

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

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

자바의 동적 바인딩 예

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

출력 : Car 내부 시작 방법


메서드 호출을 메서드 본문에 연결하는 것을 바인딩이라고합니다. Maulik이 말했듯이 "정적 바인딩은 바인딩을 위해 유형 (Java의 클래스) 정보를 사용하는 반면 동적 바인딩은 바인딩을 해결하기 위해 개체를 사용합니다." 그래서이 코드 :

public class Animal {
    void eat() {
        System.out.println("animal is eating...");
    }
}

class Dog extends Animal {

    public static void main(String args[]) {
        Animal a = new Dog();
        a.eat(); // prints >> dog is eating...
    }

    @Override
    void eat() {
        System.out.println("dog is eating...");
    }
}

결과를 생성합니다 : dog is eating ... 사용할 방법을 찾기 위해 참조를 사용하기 때문입니다. 위의 코드를 다음과 같이 변경하면 :

class Animal {
    static void eat() {
        System.out.println("animal is eating...");
    }
}

class Dog extends Animal {

    public static void main(String args[]) {

        Animal a = new Dog();
        a.eat(); // prints >> animal is eating...

    }

    static void eat() {
        System.out.println("dog is eating...");
    }
}

다음을 생성합니다. animal is eating ... 정적 메서드이기 때문에 Type (이 경우 Animal)을 사용하여 호출 할 정적 메서드를 확인합니다. 정적 메서드 외에도 private 및 final 메서드는 접근 방식을 사용합니다.


컴파일러는 "a"의 유형 만 알고 있습니다 Animal. 즉, 타임에 발생하는 정적 바인딩 (메소드 오버로딩 바인딩)이라고합니다. 그러나 동적 바인딩이면 Dog클래스 메서드를 호출합니다 . 다음은 동적 바인딩의 예입니다.

public class DynamicBindingTest {

    public static void main(String args[]) {
        Animal a= new Dog(); //here Type is Animal but object will be Dog
        a.eat();       //Dog's eat called because eat() is overridden method
    }
}

class Animal {

    public void eat() {
        System.out.println("Inside eat method of Animal");
    }
}

class Dog extends Animal {

    @Override
    public void eat() {
        System.out.println("Inside eat method of Dog");
    }
}

출력 : Dog의 내부 먹기 방법


를 설계하는 컴파일러 동안 정적 바인딩과 동적 바인딩 사이에는 세 가지 주요 차이점과 변수프로 시저런타임 Environmental &으로 전송되는 방식이 있습니다. 차이점은 다음과 같습니다.

정적 바인딩 : 정적 바인딩 에서는 다음 세 가지 문제에 대해 설명합니다.

  • 절차의 정의

  • 이름 선언 (등)

  • 선언의 범위

동적 바인딩 : 동적 바인딩에서 발생하는 세 가지 문제는 다음과 가변합니다.

  • 절차 활성화

  • 이름 바인딩

  • 바인딩의 수명


및 동적 바인딩 정적이 실제로 어떻게 작동 하는지 이해하려면 ? 또는 컴파일러와 JVM에서 어떻게 생겼나요?

Mammal메서드 speak()Human클래스 는가있는 부모 클래스가있는 아래 예제를 보겠습니다 . 방법을 Mammal재정의 speak()한 다음 다시 speak(String language).

public class OverridingInternalExample {

    private static class Mammal {
        public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
    }

    private static class Human extends Mammal {

        @Override
        public void speak() { System.out.println("Hello"); }

        // Valid overload of speak
        public void speak(String language) {
            if (language.equals("Hindi")) System.out.println("Namaste");
            else System.out.println("Hello");
        }

        @Override
        public String toString() { return "Human Class"; }

    }

    //  Code below contains the output and bytecode of the method calls
    public static void main(String[] args) {
        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
    }
}

위 코드를 컴파일하고를 사용하여 바이트 코드를 살펴보면 javap -verbose OverridingInternalExample컴파일러가 프로그램 자체에 추출하여 포함시킨 프로그램의 모든 메서드 호출 및 바이트 코드에 정수 코드를 할당하는 상수 테이블을 생성하는 것을 볼 수 있습니다. 모든 메서드 호출 아래의 주석을 참조하십시오)

프로그램 바이트 코드

위의 코드를 살펴보면 우리의 바이트 코드 것을 볼 수 있습니다 humanMammal.speak(), human.speak()그리고 human.speak("Hindi")완전히 다른 ( invokevirtual #4, invokevirtual #7, invokevirtual #9) 컴파일러는 인수 목록 및 클래스 참조를 기반으로 그들을 구별 할 수 있기 때문이다. 이 모든 것이 컴파일 타임에 정적으로 해결되기 때문에 Method OverloadingStatic Polymorphism 또는 Static Binding이라고 합니다.

그러나 컴파일러에 따라 두 메서드가 참조에서 호출되기 때문에 anyMammal.speak()humanMammal.speak()대한 바이트 코드 는 동일합니다 ( invokevirtual #4) Mammal.

이제 두 메서드 호출에 동일한 바이트 코드가 있으면 JVM이 호출 할 메서드를 어떻게 알 수 있습니까?

글쎄, 대답은 바이트 코드 자체에 숨겨져 있으며 invokevirtual명령어 세트입니다. JVM은 invokevirtual명령을 사용하여 C ++ 가상 메소드에 해당하는 Java를 호출합니다. C ++에서 다른 클래스의 한 메서드를 재정의하려면 가상으로 선언해야하지만 Java에서는 자식 클래스의 모든 메서드를 재정의 할 수 있기 때문에 기본적으로 모든 메서드가 가상입니다 (개인, 최종 및 정적 메서드 제외).

Java에서 모든 참조 변수에는 두 개의 숨겨진 포인터가 있습니다.

  1. 객체의 메서드를 다시 보유하는 테이블에 대한 포인터와 Class 객체에 대한 포인터입니다. 예 : [speak (), speak (String) Class 객체]
  2. 해당 객체의 데이터 (예 : 인스턴스 변수 값)에 대해 힙에 할당 된 메모리에 대한 포인터.

따라서 모든 개체 참조는 해당 개체의 모든 메서드 참조를 보유하는 테이블에 대한 참조를 간접적으로 보유합니다. Java는이 개념을 C ++에서 차용했으며이 테이블을 가상 테이블 (vtable)이라고합니다.

vtable은 가상 메서드 이름과 배열 인덱스에 대한 참조를 보유하는 배열과 같은 구조입니다. JVM은 클래스를 메모리에로드 할 때 클래스 당 하나의 vtable 만 생성합니다.

따라서 JVM이 invokevirtual명령어 세트를 만날 때마다 해당 클래스의 vtable에서 메서드 참조를 확인하고 우리의 경우 참조가 아닌 객체의 메서드 인 특정 메서드를 호출합니다.

이 모든 것이 런타임에만 해결되고 런타임에 JVM이 호출 할 메소드를 알기 때문에 Method OverridingDynamic Polymorphism 또는 단순히 Polymorphism 또는 Dynamic Binding이라고 합니다.

내 기사 에서 JVM이 메서드 오버로딩 및 재정의를 내부적으로 처리하는 방법 에 대한 자세한 내용을 읽을 수 있습니다 .


부모 및 자식 클래스의 정적 메서드 사용 : 정적 바인딩

public class test1 {   
    public static void main(String args[]) {
        parent pc = new child(); 
        pc.start(); 
    }
}

class parent {
    static public void start() {
        System.out.println("Inside start method of parent");
    }
}

class child extends parent {

    static public void start() {
        System.out.println("Inside start method of child");
    }
}

// Output => Inside start method of parent

동적 바인딩 :

public class test1 {   
    public static void main(String args[]) {
        parent pc = new child();
        pc.start(); 
    }
}

class parent {
   public void start() {
        System.out.println("Inside start method of parent");
    }
}

class child extends parent {

   public void start() {
        System.out.println("Inside start method of child");
    }
}

// Output => Inside start method of child

컴파일러는 컴파일 타임에 바인딩을 알고 있기 때문입니다. 예를 들어 인터페이스에서 메서드를 호출하면 컴파일러가 알 수 없으며 메서드가 호출 된 실제 개체가 여러 개 중 하나 일 수 있으므로 런타임에 바인딩이 해결됩니다. 따라서 이는 런타임 또는 동적 바인딩입니다.

유형을 지정합니다. 동물 클래스에 호출이 바인딩됩니다. 해당 변수를 다른 메소드에 전달하면 실제 클래스가 무엇인지 아무도 알 수 없습니다. 유일한 단서는 선언 된 동물 유형입니다.

참고 URL : https://stackoverflow.com/questions/19017258/static-vs-dynamic-binding-in-java