Java는 C ++처럼 클래스 정의와 구현 사이의 분리를 촉진합니까? . 그러나 클래스 정의와

숙제를 배정 받았으며 GRASP “Protected Variation”에 따라 어떤 접근법이 더 나은지 평가해야합니다. C ++에서 헤더와 코드 파일의 분리에 대한 Stack Overflow에 대한 질문을 찾았 습니다 .

그러나 클래스 정의와 클래스 구현 간의 분리를 촉진하는 데 Java가 C ++을 따르지 않는 이유를 알고 싶습니다. C ++ 메소드에 비해 Java 메소드의 장점이 있습니까?



답변

다음 프로그램에는 몇 줄의 코드가 있습니까?

#include <iostream>

int main()
{
   std::cout << "Hello, world!\n";
   return 0;
}

아마도 7 (또는 빈 줄을 세지 않으면 6, 중괄호를 세지 않으면 4)이라고 대답했을 것입니다.

그러나 컴파일러는 매우 다른 것을 봅니다.

~$ cpp hello.cpp | wc
  18736   40822  437015

그렇습니다. “Hello, world!” 프로그램. C ++ 컴파일러는이 모든 것을 파싱 해야합니다. 이것이 C ++ 컴파일이 다른 언어에 비해 오래 걸리는 이유와 현대 언어가 헤더 파일을 피하는 이유입니다.

더 좋은 질문은

않는 C 헤더 파일을 가지고 ++?

C ++는 C의 상위 집합이되도록 설계되었으므로 이전 버전과의 호환성을 위해 헤더 파일을 유지해야했습니다.

그렇다면 왜 C에 헤더 파일이 있습니까?

원시적 인 별도의 컴파일 모델로 인해. C 컴파일러가 생성 한 객체 파일에는 유형 정보가 포함되어 있지 않으므로 유형 오류를 방지하려면 소스 코드에이 정보를 포함시켜야합니다.

~$ cat sqrtdemo.c
int main(void)
{
    /* implicit declaration int sqrt(int) */
    double sqrt2 = sqrt(2);
    printf("%f\n", sqrt2);
    return 0;
}

~$ gcc -Wall -ansi -lm -Dsqrt= sqrtdemo.c
sqrtdemo.c: In function main’:
sqrtdemo.c:5:5: warning: implicit declaration of function printf [-Wimplicit-function-declaration]
sqrtdemo.c:5:5: warning: incompatible implicit declaration of built-in function printf [enabled by default]
~$ ./a.out
2.000000

적절한 형식 선언을 추가하면 버그가 수정됩니다.

~$ cat sqrtdemo.c
#undef printf
#undef sqrt

int printf(const char*, ...);
double sqrt(double);

int main(void)
{
    double sqrt2 = sqrt(2);
    printf("%f\n", sqrt2);
    return 0;
}

~$ gcc -Wall -ansi -lm sqrtdemo.c
~$ ./a.out
1.414214

#includes 가 없습니다 . 그러나 많은 수의 외부 함수 (대부분의 프로그램에서 사용)를 사용하면 수동으로 선언하면 지루하고 오류가 발생하기 쉽습니다. 헤더 파일을 사용하는 것이 훨씬 쉽습니다.

현대 언어는 어떻게 헤더 파일을 피할 수 있습니까?

유형 정보가 포함 된 다른 객체 파일 형식을 사용합니다. 예를 들어, Java * .class 파일 형식 에는 필드 유형 및 메소드 매개 변수를 지정하는 “설명자”가 포함됩니다.

이것은 새로운 발명이 아닙니다. Borland (1987)는 Borland가 별도로 컴파일 한 “장치”를 Turbo Pascal 4.0에 추가 할 때 헤더 파일의 필요성을 제거하기 위해 *.TPUTurbo C 대신 새로운 형식 을 사용하기로했습니다 *.OBJ.


답변

Java에는 계약을 정의하기위한 인터페이스가 있습니다. 이것은 호출자가 필요로하는 것과 실제 구현에서 더 높은 수준의 추상화를 제공합니다. 즉, 호출자는 구현 클래스를 알 필요가 없으며 지원하는 계약 만 알면됩니다.

지도의 모든 키 / 값을 늦추는 방법을 작성한다고 가정 해보십시오.

public static <K,V> void printMap(Map<K,V> map) {
    for(Entry<K,V> entry: map.entrySet())
        System.out.println(entry);
}

이 메소드는 구현하는 클래스에서 제거 된 추상 인터페이스에서 entrySet ()을 호출 할 수 있습니다. 이 메소드를 호출 할 수 있습니다.

printMap(new TreeMap());
printMap(new LinkedHashMap());
printMap(new ConcurrentHashMap());
printMap(new ConcurrentSkipListMap());

답변

우연히도 우연히 역사적 사고로 존재합니다. 그것은 엄청나게 열악한 시스템이며, 다른 언어에는 끔찍한 것이 없으며, 그것을 다루지 않아도되는 사람은 기뻐해야합니다.


답변

별도의 컴파일을 가능하게하는 헤더가 있습니다. 헤더를 포함하여 # 컴파일러는 컴파일 된 C ++ 코드의 이진 구조에 대해 아무것도 알 필요가 없으며 해당 작업을 별도의 링커에 맡길 수 있습니다. Java는 컴파일러와 함께 별도의 링커를 사용하지 않으며 .class 파일이 엄격하게 정의되어 있으므로 컴파일러는 각 컴파일 단위에서 다시 선언 할 필요없이 모든 유형의 모든 멤버를 판별하기 위해 해당 멤버를 읽을 수 있습니다.

모든 구현을 C ++ 헤더에 포함 할 수 있지만, #include 될 때마다 컴파일러가이를 다시 컴파일하게하여 링커가 중복 된 사본을 정렬하여 버립니다.


답변

Java는 클래스 정의와 구현의 분리를 촉진하며, 원하는 위치에 따라 다릅니다.

Java 클래스의 작성자 인 경우 클래스 정의와 하나의 파일에서 해당 클래스의 정의를 볼 수 있습니다. 이렇게하면 클래스를 유지하기 위해 한 곳으로 이동하기 만하면 개발 프로세스가 간소화되므로 두 파일 (C ++에서와 같이 .h와 .cpp)을 전환 할 필요가 없습니다. 그러나 클래스의 소비자 인 경우 .jar 또는 독립 실행 형 .class에 패키지 된 .class 파일을 통해서만 정의를 처리합니다.

C ++을 사용하면 정의와 구현을 분리 할 수 ​​있지만 임시입니다. 예를 들어, 헤더 파일 내에서 메소드를 인라인으로 작성하는 것을 막을 것은 없으며 템플릿 클래스의 경우 필수입니다. 헤더 파일에는 클래스의 구현 세부 정보이고 소비자와 관련이 없지만 헤더 파일을 보는 모든 사람에게 표시되는 모든 멤버 변수가 나열됩니다.