나는 초기와 늦게 구속되는 것에 대해 계속 들었지만, 그것이 무엇인지 이해하지 못한다. 이해하지 못하는 다음 설명을 발견했습니다.
초기 바인딩은 디자인 타임 동안 변수에 값을 할당하는 것을 말하고, 늦은 바인딩은 런타임 동안 변수에 값을 할당하는 것을 말합니다.
누군가 두 가지 유형의 바인딩을 정의하고 비교할 수 있습니까?
나는 초기와 늦게 구속되는 것에 대해 계속 들었지만, 그것이 무엇인지 이해하지 못한다. 이해하지 못하는 다음 설명을 발견했습니다.
초기 바인딩은 디자인 타임 동안 변수에 값을 할당하는 것을 말하고, 늦은 바인딩은 런타임 동안 변수에 값을 할당하는 것을 말합니다.
누군가 두 가지 유형의 바인딩을 정의하고 비교할 수 있습니까?
답변:
혼동에는 바인딩과로드라는 두 가지 주요 개념이 있습니다. 그것은 종종 둘 다를 수행하는 중간의 어딘가에있는 DataBinding의 개념에 의해 혼란 스럽습니다. 그것을 고려한 후, 나는 trifecta를 완성하기 위해 개념을 하나 더 추가 할 것입니다.
후기 바인딩 : 런타임 동안 변수가 실행될 때까지 유형을 알 수 없습니다 . 일반적으로 할당을 통해 유형을 강제하는 다른 방법이 있습니다. 동적으로 유형이 지정된 언어는이를 기본 기능이라고하지만 많은 정적으로 유형이 지정된 언어에는 늦은 바인딩을 수행하는 방법이 있습니다
[특수] 동적 유형, 내부 검사 / 반사, 플래그 및 컴파일러 옵션을 사용하거나 동적 디스패치를 빌리고 확장하여 가상 메소드를 통해 자주 구현
Early Binding : 런타임에 변수가 실행되기 전에 일반적으로 정적, 선언적 수단을 통해 유형이 알려져 있습니다.
표준 기본 유형을 사용하여 자주 구현
정적 디스패치 : 컴파일시 알려진 특정 기능 또는 서브 루틴; 모호하지 않으며 서명과 일치합니다.
정적 함수로 구현됩니다. 어떤 메소드도 같은 서명을 가질 수 없습니다
동적 디스패치 : 컴파일시 특정 함수 또는 서브 루틴이 아닙니다 . 실행하는 동안 컨텍스트에 의해 결정됩니다. "동적 디스패치"에 대한 두 가지 접근 방식이 있으며, 적절한 컨텍스트 구현을 선택하기 위해 어떤 상황 정보가 사용되는지에 의해 구별됩니다.
에서는 단일 [ 동적 ] 디스패치 인스턴스의 유형은 적절한 기능 구현을 결정하는 데 사용된다. 정적 타입 언어에서, 이것이 실제로 의미하는 것은 인스턴스 타입이 변수가 선언 / 할당 될 때 표시되는 참조 타입에 관계없이 어떤 메소드 구현이 사용될지를 결정한다는 것입니다. 적절한 구현을 유추하는 데 단일 유형 (객체 인스턴스 유형) 만 사용되므로이 방법을 "단일 디스패치"라고합니다.
도있다 여러 [ 동적 ] 디스패치 입력 파라미터 유형이 또한 호출하는 기능 구현 결정할 수. 인스턴스 유형 과 매개 변수 유형 모두와 같은 여러 유형 이 선택된 메소드 구현에 영향을주기 때문에이 접근 방식을 "다중 디스패치"라고합니다.
가상 또는 추상 기능으로 구현됩니다. 다른 단서는 재정의, 숨겨진 또는 음영 처리 된 방법을 포함합니다.
주의 : 메소드 오버로딩에 동적 디스패치가 관련되는지 여부는 언어마다 다릅니다. 예를 들어, Java에서는 오버로드 된 메소드가 정적으로 전달됩니다.
지연로드 : 필요할 때까지 값 할당 을 지연 시키는 객체 초기화 전략 . 객체가 본질적으로 유효하지만 의도적으로 불완전한 상태에있게하고 데이터를로드하기 전에 데이터가 필요할 때까지 기다립니다. 대용량 데이터 세트를로드하거나 외부 리소스를 기다리는 데 특히 유용합니다.
일부 다운 스트림 호출자가 해당 컬렉션의 내용 (예 : get_value_at, get_all_as 등)을 볼 때까지 생성자 또는 초기화 호출 중에 컬렉션 또는 목록을 복합 객체로 의도적으로로드하지 않음으로써 종종 구현됩니다. 변형에는 컬렉션에 대한 메타 정보 (크기 또는 키와 같은)를로드하지만 실제 데이터는 생략합니다. 또한 개발자에게 상당히 안전하고 효율적인 싱글 톤 구현 체계를 제공하기 위해 일부 런타임에 메커니즘을 제공합니다.
Eager Loading : 유효한 상태에 있다고 생각하기 전에 모든 데이터를 완성하기 위해 모든 값 할당 을 즉시 수행 하는 객체 초기화 전략 .
생성자 호출 또는 초기화와 같이 가능한 한 빨리 알려진 모든 데이터가있는 복합 객체를 제공하여 자주 구현
데이터 바인딩 : 종종 두 개의 호환 가능한 정보 스트림 사이에 활성 링크 또는 맵을 작성하여 하나의 변경 사항이 다른 변경 사항으로 다시 반영되고 그 반대의 경우도 마찬가지입니다. 호환 되려면 종종 공통 기본 유형 또는 인터페이스가 있어야합니다
서로 다른 애플리케이션 측면 (예 : 뷰-뷰-뷰, 모델-컨트롤러 등)간에 깨끗하고 일관된 동기화를 제공하고 소스 및 대상, 엔드 포인트, 바인드 / 바인드 해제, 업데이트 및 이벤트와 같은 개념에 대해 이야기하기 위해 종종 구현됩니다. on_bind, on_property_change, on_explicit, on_out_of_scope
편집 참고 : 이러한 문제가 자주 발생하는 예에 대한 설명을 제공하는 마지막 주요 편집입니다. 특정 코드 예제는 전적으로 구현 / 런타임 / 플랫폼에 의존합니다
컴파일하는 동안 컴파일러가 결정한 것은 EARLY / COMPILE TIME Binding을 참조 할 수 있으며 RUNTIME 에서 결정되는 것을 LATE / RUNTIME 바인딩 이라고 합니다.
예를 들어
메서드 오버로드 및 메서드 재정의 .
1) Method Overloading 에서 메소드에 대한 메소드 호출은 컴파일 할 때 컴파일러가 어떤 함수를 호출할지 결정한다는 의미에서 컴파일러에 의해 결정됩니다. 따라서 초기 바인딩 되고 있습니다.
2) 메서드 재정의에서 RUNTIME에 어떤 메서드를 호출할지 결정됩니다. 그래서 그것은 늦은 바인딩으로 나타납니다 .
간단하고 쉽게 사용할 수 있도록 노력했습니다. 도움이 되었기를 바랍니다.
늦은 바인딩은 런타임에 동작이 평가 될 때입니다. 실제로 프로그램이 실행 중일 때만 가지고있는 정보를 기반으로 행동 방법을 결정하고 싶을 때 필요합니다. 내 생각에 가장 명확한 예는 가상 함수 메커니즘, 특히 C ++입니다.
class A
{
public:
void f() {}
virtual void g() {}
};
class B : public A
{
void f() {}
virtual void g() {}
};
int main()
{
A* a = new B;
a->f();
a->g();
}
이 예에서, a->f()
실제로 호출 void A::f()
조기 (또는 정적) 바인딩 등 런타임에 프로그램이기 때문에, 생각 그것이 단지 포인터입니다 A
반면, 형태 변수 a->g()
실제로 호출 void B::g()
컴파일러는, 보는이 있기 때문에, g()
가상이다, 보는 코드를 삽입 런타임에 호출 할 올바른 함수의 주소를 올립니다.
함수 포인터에 익숙하다면 이것이 예일 것입니다. 정의 된 함수는 초기 바인딩이라고 할 수 있습니다. 반면 함수 포인터를 사용하면 바인딩이 늦습니다.
int add(int x,int y)
{
return x+y;
}
int sub(int x,int y)
{
return x-y;
}
int main()
{
//get user choice
int(*fp)(int,int);
//if add
fp=add;
//else if sub
fp=sub;
cout<<fp(2,2);
}
여기에 함수 add와 sub는 함수입니다 (주소는 컴파일 타임 링커에서 바인딩됩니다)
그러나 함수 포인터는 늦게 바인딩됩니다. fp는 사용자 선택에 따라 add 또는 sub를 호출 할 수 있습니다 [런타임].
초기 및 후기 바인딩은 유형의 컨텍스트에서만 의미가 있으며 설명하는 방식이 아닙니다. 거의 모든 현대 언어는 모든 값에 고정 유형이 있다는 의미에서 입력됩니다. 우리가 동적 언어와 정적 형식의 언어를 볼 때 차이점이 있습니다. 동적으로 유형이 지정된 언어에서 변수에는 유형이 없으므로 모든 유형의 값을 참조 할 수 있으며 이는 일부 변수가 참조하는 객체에서 메소드를 호출 할 때 해당 호출이 유효한지 여부를 판별하는 유일한 방법임을 의미합니다. 객체의 클래스를 찾아 해당 메소드가 실제로 존재하는지 확인하십시오. 이것은 실제 메소드 검색이 마지막 순간까지 연기되기 때문에 런타임에 클래스에 새로운 메소드를 추가하는 것과 같은 멋진 것들을 허용합니다. 대부분의 사람들은이 상황을 늦게 구속한다고합니다.
정적으로 유형이 지정된 언어 변수에는 유형이 있으며 한 번 선언되면 동일한 유형이 아닌 값을 참조 할 수 없습니다. 이것은 사실이 아니지만 현재로서는 가정 해 보겠습니다. 이제 변수가 특정 유형의 값만 참조한다는 것을 알고 있다면 코드가 실행되기 전에 유효성을 확인할 수 있기 때문에 메소드 호출이 런타임인지 아닌지를 알아낼 이유가 없습니다. 이것을 초기 바인딩이라고합니다.
루비에서 늦은 바인딩을 보여주는 예제 :
a = 1 # a is an integer at this point
a.succ # asking for its successor is valid
class A
def method_a
# some code
end
end
a = A.new
a.method_a # this is also valid
a.succ # this is not valid
class A # we can re-open the class and add a method
def succ
# some more code
end
end
a.succ # now this is valid
모든 유형이 런타임에 고정 된 Java와 같은 언어에서는 위의 일련의 동작이 불가능합니다.
학문적 정의를 제공하는 대신 VBA를 사용하는 실제 예를 사용하여 차이점을 보여 드리겠습니다.
초기 바인딩 :
Dim x As FileSystemObject
Set x = New FileSystemObject
Debug.Print x.GetSpecialFolder(0)
디자인 타임에 "Microsoft 스크립팅 런타임"구성 요소에 대한 참조를 설정해야합니다 . 오타가 FileSystemObject
있거나 메소드 이름이 같은 경우 컴파일 타임에 이미 오류 메시지가 표시되는 이점이 있습니다 GetSpecialFolder
.
늦은 바인딩
Dim x As Object
Set x = CreateObject("Scripting.FileSystemObject")
Debug.Print x.GetSpecialFolder(0)
이를 위해서는 사전에 참조를 설정하지 않아도되며 인스턴스 생성 및 유형 결정은 런타임에 발생합니다. 존재하지 않는의 메소드를 호출하려고 할 때 컴파일러가 컴파일 타임에 불평하지 않으므로 x
특정 행이 실행될 때만 런타임 오류가 발생합니다.
따라서 늦은 바인딩의 단점은 여기에 강력한 유형 검사가 없다는 것입니다. 그러나 그것은 또한 장점입니다. 여러 버전이 존재하는 구성 요소가 있고 각 최신 버전이 추가 기능을 제공한다고 가정 해 봅시다. 실제 예제는 Excel COM 인터페이스와 같은 MS Office 구성 요소입니다. 후기 바인딩을 사용하면 모든 버전과 함께 작동하는 코드를 작성할 수 있습니다. 먼저 특정 구성 요소 버전을 확인할 수 있습니다. 사용 가능한 이전 버전 만 해당 버전에서 작동하지 않는 함수 호출을 실행하지 마십시오.
후기 바인딩의 가장 일반적인 예는 인터넷 URL을 확인하는 것입니다. 모든 사이트에 연결하기 전에 세계의 모든 사이트를 연결 및 바인딩하지 않고 동적 시스템 및 대규모 시스템을 지원하지만, 런타임에 약간의 오버 헤드 (DNS 조회, 훨씬 적은 IP 라우팅)가 발생합니다.
이러한 관점에서 언어 환경에서의 대부분의 바인딩은 컴파일 타임이나 링크 타임에 어느 정도 빠릅니다.
각 종류마다 비용과 혜택이 있습니다.