Java가 함수 정의가 클래스 외부에 존재하지 않는 이유는 무엇입니까?


22

C ++과 달리 Java에서는 클래스에 함수 선언 만 있고 클래스 외부에 정의를 가질 수 없습니다. 왜 그래야만하지?

Java의 단일 파일에는 클래스가 하나만 있어야하며 다른 클래스는 없어야한다는 점을 강조해야합니까?



1
으로 정의 하면 평균 속성 또는 메소드 서명 헤더 파일 람을합니까?
데코

귀하의 질문에 대한 좋은 풍자적 답변 : steve-yegge.blogspot.com/2006/03/…
Brandon

답변:


33

C ++과 Java의 차이점은 언어가 가장 작은 연결 단위를 고려하는 것입니다.

C는 어셈블리와 공존하도록 설계되었으므로 해당 장치는 주소에 의해 호출되는 서브 루틴입니다. (이것은 FORTRAN과 같은 기본 객체 파일로 컴파일되는 다른 언어의 경우에 해당됩니다.) 즉, 함수 foo()를 포함하는 객체 파일에는 다음과 같은 주소로만 _foo해석 되는 심볼 이 있습니다.0xdeadbeef연결하는 동안. 그게 다야. 함수가 인수를 취하는 경우, 주소를 호출하기 전에 함수가 기대하는 모든 것이 순서대로되어 있는지 확인하는 것은 호출자에게 달려 있습니다. 일반적으로 이것은 스택에 물건을 쌓아서 수행되며 컴파일러는 거친 작업을 처리하고 프로토 타입이 일치하는지 확인합니다. 오브젝트 파일 간에는이를 확인하지 않습니다. 통화 연결을 끊으면 통화가 계획대로 진행되지 않고 경고 메시지가 표시되지 않습니다. 위험에도 불구하고 여러 언어 (조립 포함)로 컴파일 된 객체 파일을 많은 번거 로움없이 작동하는 프로그램에 연결할 수 있습니다.

C ++는 모든 추가 기능에도 불구하고 동일한 방식으로 작동합니다. 컴파일러는 네임 스페이스, 클래스 및 메소드 / 멤버 등을 표시합니다. 클래스의 내용을 고유 한 방식으로 엉망인 단일 이름으로 병합하여이 규칙에 예를 들어, 객체 파일에 넣을 때 와 같은 방법과 런타임 과 같은 주소 Foo::bar(int baz)가 엉망이 _ZN4Foo4barEi될 수 있습니다 0xBADCAFE. 이것은 전적으로 컴파일러에 의존하기 때문에 다른 mangling 구성표를 가진 두 객체를 연결하려고하면 운이 나빠질 것입니다. 추악한 것처럼 이것은 extern "C"블록을 사용하여 맹 글링을 비활성화하여 다른 언어에서 C ++ 코드에 쉽게 액세스 할 수 있도록합니다. C ++은 C에서 자유 부동 함수 (free-floating functions)라는 개념을 물려 받았습니다. 주로 기본 객체 형식이 허용하기 때문입니다.

Java는 자체 객체 파일 형식 인 파일로 격리 된 세상에 사는 다른 야수입니다 .class. 클래스 파일에는 해당 환경에 대한 풍부한 정보가 포함되어 있어 기본 링크 메커니즘이 상상조차 할 수 없었던 런타임시 환경에서 클래스로 작업을 수행 할 수 있습니다. 그 정보는 어딘가에서 시작해야하고 그 시작점은class. 사용 가능한 정보를 통해 컴파일 된 코드는 C, C ++ 또는 기타 언어에서와 같이 소스 코드에 설명이 포함 된 별도의 파일 없이도 자체 설명 할 수 있습니다. 이는 런타임에서도 네이티브 링키지 부족을 사용하여 모든 유형의 안전 혜택 언어를 제공하며, 리플렉션을 사용하여 파일에서 임의 클래스를 피싱하고 일치하지 않는 경우 보장 된 실패로 사용할 수있게 해줍니다 .

아직 알지 못했다면이 모든 안전 기능에는 트레이드 오프가 있습니다. Java 프로그램에 연결하는 모든 것은 Java 여야합니다. ( "링크"라는 말은 한 클래스 파일의 무언가가 다른 클래스의 무언가를 가리킬 때를 의미합니다.) JNI를 사용하여 네이티브 코드에 네이티브 코드를 링크 할 수 있지만, 네이티브 측면을 어기면 암묵적인 계약이 있습니다. , 두 조각을 모두 소유하고 있습니다.

Java는 Ada가 이전 10 년에했던 것처럼 처음 도입되었을 때 사용 가능한 하드웨어에서 특히 빠르지 않았습니다. Jim Gosling만이 자신의 동기가 Java의 가장 작은 연결 단위를 만드는 데 어떤 도움을 주 었는지 말할 수는 있지만 무료 플로터를 추가하는 것이 런타임에 추가 될 수있는 추가 복잡성은 거래 킬러라고 생각할 것입니다.


링크가 끊어짐, 웹 아카이브 링크 가져 오기
noɥʇʎԀʎzɐɹƆ

14

나는 위키 백과에 따르면, 자바는 단순하고 객체 지향적으로 설계되었다고 생각합니다. 함수는 정의 된 클래스에서 작동하도록되어 있습니다. 이러한 사고 방식으로 클래스 외부에 함수를 갖는 것은 의미가 없습니다. Java가 순수 OOP에 맞지 않기 때문에 Java가 허용하지 않는다는 결론으로 ​​도약하려고합니다.

저를위한 빠른 Google 검색은 Java 언어 디자인 동기 부여를 많이 얻지 못했습니다.


6
프리미티브 유형의 존재가 Java가 "순수 OOP"에서 제외되지 않습니까?
Radu Murzea

5
@SoboLAN : 예. 기능을 추가하면 "순수한 OOP"가 줄어 듭니다.
Giorgio

8
"순수한 OOP"의 정의에 의존하는 @SoboLAN. 어떤 시점에서 모든 것은 결국 컴퓨터 메모리의 비트 조합입니다 ...
jwenting

3
@jwenting : 프로그래밍 언어에서 추상화의 목적은 기본 비트를 최대한 숨기는 것입니다. 프로그램에서 해당 비트를 더 많이 볼수록, 프로그래밍 언어가 누출 된 추상화를 제공한다고 생각하기 시작해야합니다. 따라서 모든 것이 비트 조작으로 요약되지만 언어마다 다른 추상화 수준을 제공합니다. 그렇지 않으면 어셈블리를 상위 언어와 구별 할 수 없습니다.
Giorgio

2
"pure OOP"정의에 따라 다릅니다. 모든 데이터 값은 개체이며 모든 데이터 작업은 메시지 전달을 통해 얻은 결과 메서드 호출입니다. 내가 아는 한 더 이상 아무것도 없습니다.
Giorgio

11

진짜 질문은 C ++ 방식으로 일을 계속하는 장점은 무엇이며 헤더 파일의 원래 목적은 무엇입니까? 짧은 대답은 헤더 파일 스타일이 많은 클래스가 잠재적으로 동일한 유형을 참조 할 수있는 대규모 프로젝트에서 더 빠른 컴파일 시간을 허용한다는 것입니다. 컴파일러의 특성으로 인해 JAVA 및 .NET에서는 필요하지 않습니다.

여기 에이 답변을보십시오 : 헤더 파일이 실제로 좋습니까?


1
+1, 실제로 사람들은 헤더 파일이 제공하는 공용 인터페이스와 개인 구현을 분리하는 것을 좋아한다고 들었습니다. 물론 그 사람들은 틀 렸습니다. ;)
vaughandroid

6
@Baqueta에서 자바는이에 달성 할 수 interfaceclass헤더 : 필요 없음을!
Andres F.

1
간단한 클래스 인스턴스가 어떻게 작동하는지 이해하기 위해 3+ 파일을보아야하는 바람직 함을 결코 이해하지 못할 것입니다.
Erik Reppen

@ErikReppen 일반적으로 인터페이스 (또는 C의 헤더 파일)는 고객이 솔루션을 작성하기 위해 사용자가 읽을 수있는 형태로 제공되는 것이며 나머지는 바이너리 형식으로 만 제공됩니다 (물론 Java에서는 소스를 제공 할 필요가 없습니다) 인터페이스, 클래스 파일 및 javadoc이 수행합니다).
jwenting

@jwenting 나는 그 경우를 생각하지 못했습니다. 나는이 바보 같은 코드베이스를 유지 해야하는 다음 나쁜 나쁜 자식을 생각하는 데 더 익숙합니다. 왜냐하면 너무나 자주 다음 일에 기괴한 인터페이스와 하위 / 수퍼 클래스 메리를 보면서 시간을 보낸 후 눈을 찌르기 때문입니다. 다목적 아키텍처.
Erik Reppen

3

Java 파일은 클래스를 나타냅니다. 수업 이외의 절차가 있다면, 그 범위는 무엇입니까? 글로벌일까요? 아니면 Java 파일이 나타내는 클래스에 속합니까?

아마도 다른 클래스보다 다른 클래스와 함께 사용되기 때문에 다른 파일 대신 Java 파일에 넣을 수 있습니다. 클래스 외부의 프로 시저가 실제로 해당 클래스와 연관되어 있다면 클래스가 속한 클래스 내부로 강제로 들어 가지 않겠습니까? Java는 이것을 클래스 내부의 정적 메소드로 처리합니다.

외부 클래스 프로 시저가 허용 된 경우 파일이 선언 된 클래스에 대한 특별한 액세스 권한이 없으므로 데이터를 변경하지 않는 유틸리티 함수로 제한합니다.

이 Java 제한 사항의 유일한 단점은 클래스와 연관되지 않은 글로벌 프로 시저가있는 경우이를 보유 할 MyGlobals 클래스를 작성하고 해당 프로 시저를 사용하는 다른 모든 파일에서 해당 클래스를 가져 오는 것입니다. .

실제로 Java 가져 오기 메커니즘이 작동하려면이 제한 사항이 필요합니다. 모든 API를 사용할 수 있으므로 Java 컴파일러는 컴파일 대상과 컴파일 대상을 정확히 알아야하므로 파일 맨 위에 명시 적 import 문이 있어야합니다. 인공 클래스로 그룹에 전역을하지 않고, 당신은 어떻게 자바 컴파일하는 컴파일러 말할 것 당신의 전역을하지 일체의 클래스 패스에 전역을? doStuff ()가 있고 다른 사람이 doStuff ()가있는 네임 스페이스 충돌은 어떻습니까? 작동하지 않습니다. MyClass.doStuff () 및 YourClass.doStuff ()를 지정하면 이러한 문제가 해결됩니다. 프로 시저가 외부가 아닌 MyClass 내부로 들어가도록 강요하면이 제한이 명확 해지고 코드에 대한 추가 제한이 적용되지 않습니다.

Java에는 많은 문제가 있습니다. 직렬화에는 사마귀가 너무 많아서 사용하기가 너무 어렵습니다 (SerialVersionUID 생각). 또한 싱글 톤 및 기타 일반적인 디자인 패턴을 파괴하는 데 사용할 수 있습니다. Object의 clone () 메소드는 deepClone () 및 shallowClone ()으로 분할되고 형식이 안전해야합니다. 모든 API 클래스는 기본적으로 (Scala에있는 방식으로) 변경 불가능할 수 있습니다. 그러나 모든 절차가 클래스에 속해야한다는 제한은 좋은 것입니다. 이 프로그램은 주로 복잡한 제한없이 언어와 코드를 단순화하고 명확하게합니다.


3

나는 대답 한 대부분의 사람들과 유권자들이 그 질문을 오해했다고 생각합니다. C ++을 모른다는 것을 반영합니다.

"정의"및 "선언"은 C ++에서 매우 특정한 의미를 가진 단어입니다.

OP가 Java 작동 방식을 변경한다는 의미는 아닙니다. 이것은 순전히 구문에 관한 질문입니다. 나는 그것이 유효한 질문이라고 생각합니다.

C ++에는 멤버 함수 를 정의 하는 두 가지 방법이 있습니다.

첫 번째 방법은 Java 방식입니다. 모든 코드를 중괄호 안에 넣으십시오.

class Box {
public:
    // definition of member function
    void change(int newInt) { 
        this._m = newInt;
    }
private:
    int _m
}

두 번째 방법 :

class Box {
public:  
    // declaration of member function
    void change(int newInt); 
private:
    int _m
}

// definition of member function
// this can be in the same file as the declaration
void Box::change(int newInt) {
    this._m = newInt;
}

두 프로그램은 동일합니다. 이 함수 change는 여전히 멤버 함수입니다. 클래스 외부에는 존재하지 않습니다. 또한 클래스 정의에는 Java에서와 같이 모든 멤버 함수 및 변수의 이름과 유형이 포함되어야합니다.

Jonathan Henson은 이것이 C ++에서 헤더가 작동하는 방식의 결과라고 생각합니다. 헤더 파일에 선언을 구현하고 별도의 .cpp 파일에 구현을 적용하여 프로그램이 ODR (One Definition Rule)을 위반하지 않도록 할 수 있습니다. 그러나 그것은 그 밖에 장점이 있습니다. 큰 클래스의 인터페이스를 한눈에 볼 수 있습니다.

Java에서는 추상 클래스 또는 인터페이스를 사용하여이 효과를 근사 할 수 있지만 구현 클래스와 동일한 이름을 가질 수 없으므로 다소 어색합니다.


그리고 그것은 당신이 사람이나 Java를 이해하지 못한다는 것을 보여줍니다. 인터페이스 및 구현에 동일한 이름을 사용하지 않는 한 동일한 이름을 인터페이스 및 구현에 사용할 수 있습니다.
jwenting

패키지 (또는 네임 스페이스 또는 외부 클래스)를 이름의 일부로 간주합니다.
Erik van Velzen 14

2

클래스 로딩 메커니즘의 인공물이라고 생각합니다. 각 클래스 파일은로드 가능한 객체의 컨테이너입니다. 클래스 파일의 "외부"는 없습니다.


1
소스 코드를 별도의 단위로 구성하면 클래스 파일 형식을 그대로 유지하지 못하는 이유를 알 수 없습니다.
Mat

클래스 파일과 소스 파일 간에는 1 : 1의 대응 관계가 있으며 이는 전체 시스템에서 더 나은 디자인 결정 중 하나입니다.
ddyer

@ddyer Foo $ 2 $ 1.class를 본 적이 없습니까? ( Java 내부 클래스 클래스 파일 이름 참조 )

그것이 "온"매핑이 될까요? 어쨌든 각 클래스는 정확히 하나의 소스 파일을 컴파일하여 생성되므로 좋은 디자인 결정입니다.
ddyer

0

Java와 매우 유사한 C #은 부분 메소드가 독점적으로 전용 인 것을 제외하고는 부분 메소드를 사용하여 이러한 기능을 제공합니다.

부분 방법 : http://msdn.microsoft.com/en-us/library/6b0scde8.aspx

부분 클래스 및 메소드 : http://msdn.microsoft.com/en-us/library/wa80x488.aspx

Java가 똑같이 할 수없는 이유는 보이지 않지만 아마도이 기능을 언어에 추가하기 위해 사용자 기반에서 인식해야 할 필요성이 있는지 여부 일 수 있습니다.

C #을위한 대부분의 코드 생성 도구는 부분 클래스를 생성하므로 개발자는 원하는 경우 수동으로 작성된 코드를 별도의 파일로 클래스에 쉽게 추가 할 수 있습니다.


0

C ++에서는 클래스의 전체 텍스트를 멤버를 사용하거나 인스턴스를 생성하는 모든 컴파일 단위의 일부로 컴파일해야합니다. 컴파일 시간을 깔끔하게 유지하는 유일한 방법은 클래스 자체의 텍스트를 가능한 한 많이 소비자에게 실제로 필요한 것만 포함하는 것입니다. C ++ 메소드가 종종 클래스를 포함하는 클래스 외부에서 작성된다는 사실은 컴파일러가 클래스가 사용되는 모든 컴파일 단위마다 한 번 모든 클래스 메소드의 텍스트를 처리해야한다는 사실에 동기를 부여 한 정말 악의적 인 해킹입니다. 미친 빌드 시간.

Java에서 컴파일 된 클래스 파일에는 무엇보다도 C ++ .h 파일과 거의 동일한 정보가 포함됩니다. 클래스 소비자는 컴파일러가 .java 파일을 처리하지 않아도 해당 파일에서 필요한 모든 정보를 추출 할 수 있습니다. .h 파일에 포함 된 클래스의 구현과 클라이언트 모두에서 사용할 수있는 정보가 포함 된 C ++와 달리 Java의 흐름은 반대로됩니다. 클라이언트에서 사용하는 파일은 컴파일 할 때 사용 된 소스 파일이 아닙니다. 클래스 코드이지만 클래스 코드 파일 정보를 사용하여 컴파일러에서 생성합니다. 정보 클라이언트가 포함하는 파일과 구현이 포함 된 파일간에 클래스 코드를 나눌 필요가 없으므로 Java는 이러한 분할을 허용하지 않습니다.


-1

Java의 일부는 대규모 팀에서의 사용과 관련된 보호주의 언어라고 생각합니다. 클래스를 덮어 쓰거나 재정의 할 수 없습니다. 메소드를 사용할 수있는 방법과 사용할 수없는 방법을 매우 구체적으로 정의하는 4 가지 레벨의 액세스 수정자가 있습니다. 모든 사람이 다른 사람이나 자신에 의해 발생하는 유형 불일치로부터 개발자를 보호하기 위해 강력하고 정적으로 유형이 지정됩니다. 클래스와 함수를 가장 작은 단위로 사용하면 앱을 설계하는 방법에 대한 패러다임을 다시 쉽게 만들 수 있습니다.

이중 목적 명사 / 동사 일급 함수가 비가 내리고 버스트 오픈 피 나타에서 사탕처럼 전달되는 JavaScript와 비교하면 클래스와 동등한 함수 생성자는 프로토 타입이 새로운 속성을 추가하거나 인스턴스에 대한 기존 속성을 변경하도록 할 수 있습니다. 이미 생성 된 적이 있으며, 자신의 버전으로 구조물을 교체하는 것을 막을 수있는 것은 아무것도 없습니다. 5 가지 유형이 있으며 다양한 상황에서 자동 변환 및 자동 평가되며, 근처에있는 새로운 속성을 추가 할 수 있습니다.

function nounAndVerb(){
}
nounAndVerb.newProperty = 'egads!';

틈새 시장과 시장에 관한 것입니다. 자바는 웹 UI를 작성하려는 소규모 개발자 그룹이 자바를 사용했던 것처럼 100 명 (많은 평범 할 것임) 개발자에게 적절하고 비참하다. 100 개발자와 함께 일할 때 마지막으로 원하는 것은 저주받은 패러다임을 재창조하는 사람입니다. UI로 작업하거나 빠른 개발이 더 중요한 관심사 인 경우, 마지막으로 원하는 것은 조심하지 않으면 매우 어리석게 수행하기 쉽기 때문에 비교적 간단한 작업을 신속하게 수행하는 데 방해가됩니다.

하지만 마지막에는 일반적인 대중 용 언어이기 때문에 약간의 철학적 주장이 있습니다. Java 및 C #을 사용하는 가장 큰 개인 소고기는 대다수의 개발자가 기본 OOP의 가치를 이해 한 것처럼 보이는 레거시 코드베이스를 보거나 본 적이 없다는 것입니다. 게임에서 클래스의 모든 것을 감싸 야 할 때 3-5 라인 클래스의 거대한 체인으로 위장한 기능 스파게티보다는 OOP를하고 있다고 생각하는 것이 더 쉽습니다.

즉, 위험 할 정도로만 알고 그것을 과시하는 것을 두려워하지 않는 사람이 작성한 JavaScript보다 더 끔찍한 것은 없습니다. 그리고 그것이 일반적인 생각이라고 생각합니다. 그 사람은 아마도 자바에서 거의 같은 규칙을 따라야합니다. 나는 자식이 항상 길을 찾을 것이라고 주장합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.