C ++과 Java가 왜 "참조"라는 개념을 사용하지만 같은 의미가 아닌가?


26

C ++에서 함수에 대한 참조 인수는 함수가 참조가 다른 것을 참조하도록합니다.

int replacement = 23;

void changeNumberReference(int& reference) {
    reference = replacement;
}

int main() {
    int i = 1;
    std::cout << "i=" << i << "\n"; // i = 1;
    changeNumberReference(i);
    std::cout << "i=" << i << "\n"; // i = 23;
}

마찬가지로 함수에 대한 상수 참조 인수는 참조를 변경하려고하면 컴파일 타임 오류를 발생시킵니다.

void changeNumberReference(const int& reference) {
    reference = replacement; // compile-time error: assignment of read-only reference 'reference'
}

이제 Java를 사용하면 문서는 기본이 아닌 유형의 함수 인수가 참조라고 말합니다. 공식 문서의 예 :

public void moveCircle(Circle circle, int deltaX, int deltaY) {
    // code to move origin of circle to x+deltaX, y+deltaY
    circle.setX(circle.getX() + deltaX);
    circle.setY(circle.getY() + deltaY);

    // code to assign a new reference to circle
    circle = new Circle(0, 0);
}

그런 다음 circle에 x = y = 0 인 새 Circle 객체에 대한 참조가 할당됩니다. 그러나이 재 할당에는 참조가 값으로 전달되어 변경할 수 없기 때문에 영구성이 없습니다.

나에게 이것은 C ++ 참조처럼 보이지 않습니다. 다른 것을 참조 할 수 없기 때문에 일반 C ++ 참조와 유사하지 않으며 Java에서는 참조가 변경되지만 실제로는 그렇지 않은 코드가 컴파일되지 않기 때문에 C ++ const 참조와 유사하지 않습니다. 시간 오류.

이것은 C ++ 포인터와 동작이 더 비슷합니다. 이를 사용하여 뾰족한 객체 값을 변경할 수 있지만 함수에서 포인터 값 자체를 변경할 수는 없습니다. 또한 C ++ 포인터 (C ++ 참조는 아님)와 마찬가지로 Java에서는 이러한 인수의 값으로 "null"을 전달할 수 있습니다.

그래서 제 질문은 : Java가 왜 "참조"라는 개념을 사용합니까? 그것들이 C ++ 참조와 유사하지 않다는 것을 이해해야합니까? 아니면 실제로 실제로 C ++ 참조와 비슷하며 뭔가 빠졌습니다.


10
첫 번째 C ++ 예제에서는 "다른 것을 가리 키도록"참조하지 않습니다. 대신 참조가 가리키는 변수 값을 변경합니다. 이것은 개념적으로 Java 참조로 참조되는 객체의 상태를 변경하는 것과 유사합니다.
Xion

@ Xion yep, 이제 귀하의 의견을 읽었으므로 귀하가 의미하는 바를 확인하고 귀하가 말한 것의 98 %에 동의합니다. : Java의 문제는 개념적으로 객체의 모든 상태에 액세스해야한다는 것입니다 참조를 다른 참조의 값으로 설정하여 C ++의 기능을 간단히 달성하십시오.
Shivan Dragon

답변:


48

왜? 일관된 용어가 전체 직업에 일반적으로 도움이되지만, 언어 디자이너가 다른 언어 디자이너의 언어 사용을 존중하지는 않습니다. 특히 다른 언어가 경쟁자로 인식되는 경우에는 더욱 그렇습니다.

그러나 실제로 '참조'를 사용하는 것도 좋은 선택이 아닙니다. C ++의 "참조"는 별칭 (정확히 동일한 엔티티의 대체 이름)을 명시 적으로 도입하는 언어 구성 입니다. 처음에는 새로운 기능을 "별칭"이라고 불렀다는 것이 훨씬 명확 해졌습니다. 그러나 그 당시 가장 큰 어려움은 모든 사람들이 포인터 (역 참조가 필요함)와 참조 (그렇지 않은)의 차이점을 이해하게하는 것이 었습니다. 따라서 중요한 것은 "포인터"이외의 다른 것이라 불렀습니다. 구체적으로 어떤 용어를 사용해야합니까?

Java에는 포인터가 없으며이를 자랑스럽게 생각하므로 "포인터"를 용어로 사용하는 것은 선택 사항이 아닙니다. 그러나 C ++의 포인터가 전달할 때와 같이 "참조"는 약간 작동합니다. 큰 차이점은 더 낮은 수준의 작업 (캐스팅, 추가 ...)을 수행 할 수 없다는 것입니다 그러나 동일한 동일 엔티티와 동일한 엔티티에 핸들을 전달할 때 정확히 동일한 의미를 갖습니다. 불행히도, "포인터"라는 용어는 너무 많은 부정적인 하위 수준 연관성을 가지고있어 Java 커뮤니티에서 받아 들일 수 없을 것입니다.

결과적으로 두 언어 모두 서로 다른 두 가지 용어에 대해 동일한 모호한 용어를 사용합니다. 두 가지 언어 모두 더 구체적인 이름으로 이익을 얻을 수 있지만 곧 바뀔 수는 없습니다. 자연어도 때때로 실망 스러울 수 있습니다!


7
고맙게도 C ++ 참조를 "별칭"(동일한 값 / 인스턴스)으로 생각하고 Java 참조를 "나 스티어 낮은 수준의 작업이없는 포인터 (캐스팅, 추가 ...)"로 생각하면 정말 분명합니다.
Shivan Dragon

14
Java에는 포인터가 없으며이를 자랑스럽게 생각하므로 "포인터"를 용어로 사용하는 것은 선택 사항이 아닙니다. 무엇에 대한 NullPointerException또는 JLS 용어 "포인터"를 사용한다는 사실?
Tobias Brandt

7
@TobiasBrandt : NullPointerException는 포인터가 아니지만 하위 레벨에서 NULL 포인터가 전달 / 역 참조되었음을 나타내는 예외입니다. 사용Pointer 예외의 한 부분으로, 어떤 경우에, 그들은 잖소 JLS는 불쾌한 이미지에 추가 자바의 VM은 주로 언어로 사용하는 그 것을 작성 되었기 때문에, 포인터를 언급. 내부의 작동 방식을 설명하지 않으면 언어 사양을 정확하게 설명 할 수 없습니다
Elias Van Ootegem

3
@TobiasBrandt : Java는 모든 곳에서 포인터를 사용합니다. 힙 객체는 모든 실제적인 목적을위한 포인터를 통해 참조됩니다. Java가 포인터 유형에 대한 조작을 프로그래머에게 노출시키지 않는다는 것입니다.
John Bode

2
Java / .NET 참조에 "개체 ID"라는 용어를 선호합니다. 비트 수준에서, 그러한 것들은 일반적으로 포인터와 유사한 것으로 구현 될 수 있지만, 그럴 필요는 없습니다. 중요한 것은 객체 ID에 framework / vm이 객체를 식별하는 데 필요한 모든 종류의 정보가 포함되어 있다는 것입니다.
슈퍼 캣

9

참조는 다른 것을 의미하는 것입니다. 다양한 언어들이“참조”라는 단어,보다 구체적으로“모든 나쁜 측면이없는 포인터와 같은 것”에 대해보다 구체적인 의미를 부여했습니다. C ++은 Java 또는 Perl과 마찬가지로 특정 의미를 나타냅니다.

C ++에서 참조는 별칭과 비슷합니다 (포인터를 통해 구현할 수 있음). 이것은 참조 또는 출력 인수로 전달을 허용 합니다.

Java에서 참조는 이것이 언어의 통일 된 개념이 아니라는 점을 제외하고는 포인터입니다. 모든 객체는 참조이며 숫자와 같은 기본 유형은 아닙니다. 그들은 포인터 산술이없고 Java에는 확정 된 포인터가 없기 때문에“포인터”라고 말하고 싶지 않지만 Object인수로 전달할 때 객체가 복사되지 않는다는 것을 분명히하고 싶습니다 . 이것은 또한 참조로 전달 되지 않습니다 공유하여 전달하는 것과 비슷 합니다 .


6

그것은 대부분 Algol 68로 돌아가고 부분적으로 C가 포인터를 정의하는 방식에 대한 반응으로 돌아갑니다.

Algol 68은 참조라는 개념을 정의했습니다. 파스칼의 포인터와 거의 동일했습니다. NIL 또는 특정 유형의 다른 셀 주소를 포함하는 셀입니다. 참조에 할당 할 수 있으므로 참조는 한 번에 하나의 셀을 참조하고 재 할당 된 후 다른 셀을 참조 할 수 있습니다. 그러나 C 또는 C ++ 포인터 산술과 유사한 것을 지원 하지 않았습니다 .

그러나 적어도 Algol 68이 정의한 바와 같이, 참고 문헌은 실제로 사용하기에는 상당히 어색한 개념이었습니다. 대부분의 변수 정의는 실제로 참조로 사용되었으므로, 완전히 손에서 벗어나지 않도록 속기 표기법을 정의했지만, 사소한 용도 이상은 어쨌든 매우 빨리 어색해질 수 있습니다.

예를 들어, like와 같은 선언 INT j := 7;은 실제로 컴파일러에서와 같은 선언으로 취급되었습니다 REF INT j = NEW LOC INT := 7. 그래서, 당신이 알골 (68)에 선언하는 것은 다음 힙에 할당 된 뭔가를 참조 초기화 된 참조는, 일반적으로, 그리고 (선택적으로) 일부 지정된 값을 포함하도록 초기화되었습니다. 그러나 Java와는 달리, 그들은 foo bar = new foo();"우리의 포인터는 포인터가 아닙니다"라는 말 을 끊임없이 또는 피브에게 알려주 는 대신 최소한 구문을 유지하도록 노력했습니다.

파스칼과 그 후손들 (직접적인 그리고 영적인 것)은 Algol 68 참조 개념의 이름을 "포인터"로 바꾸었지만 그 개념 자체는 본질적으로 동일하게 유지했습니다. 포인터는 nil , 또는 당신이 할당 된 무언가의 주소 힙에 (즉, 적어도 Jensen과 Wirth에 의해 정의 된대로 "주소"연산자가 없었으므로 포인터가 정상적으로 정의 된 변수를 참조 할 방법이 없었습니다). "포인터"임에도 불구하고 포인터 산술은 지원되지 않았습니다.

C와 C ++는 그것에 약간의 왜곡을 추가했습니다. 첫째, 그들은 어떻게 포인터가 힙에 할당 뭔가뿐만 아니라 참조 할 수 있도록 주소-의 연산자를 가지고 있지만, 어떤 변수에 관계없이 할당 어떻게의. 둘째, 포인터에 대한 산술을 정의하고 기본적으로 포인터 산술에 대한 간단한 표기법으로 배열 첨자를 정의하므로 포인터 산술은 대부분의 C 및 C ++에서 어디에나있을 수 있습니다 (피할 수없는 것).

자바가 발명되었을 때, 썬은 "자바에는 포인터가 없다"는 것보다 간단하고 깔끔한 마케팅 메시지라고 생각했다. "자바의 거의 모든 것이 포인터이지만,이 포인터는 대부분 C 대신 Pascal과 비슷하다." 그들은 "포인터"가 용인 할 수없는 용어라고 결정했기 때문에, 참조가 Algol 68 참고 문헌과 미묘하게 (그리고 경우에 따라 미묘하게는 다르지만) 다른 것을 필요로하고 대신 "참조"를 준설했습니다.

비록 약간 다르게 나왔지만 C ++은 거의 같은 문제로 고착되어있었습니다. "포인터"라는 단어는 이미 알려져 있고 이해되어 있기 때문에 다른 것을 언급 한 다른 단어에 대해 다른 단어가 필요했습니다. 사람들이 "포인터"를 이해 한 것과는 조금 다릅니다. 따라서 Algol 68 참조와 눈에 띄게 다르더라도 "참조"라는 용어를 재사용했습니다.


Algol 68에서 특히 고통스러운 것은 자동 역 참조입니다. 한 수준으로 제한되는 한 편리합니다. 그러나 그것이 눈에 보이지 않는 눈에 대한 언급 중 일부를 숨긴 구문 설탕과 결합하여 여러 번 수행 할 수 있다는 사실은 혼란 스럽습니다.
AProgrammer

0

'reference type'의 개념은 일반적인 것으로, 'value type'과는 반대로 포인터와 참조를 모두 표현할 수 있습니다 (C ++로 표시). 자바의 참조는 정말의 구문 오버 헤드없이 포인터 역 참조. C ++에서 JVM의 구현을 살펴보면 실제로 포인터입니다. 또한 C #에는 Java와 유사한 참조 개념이 있지만 함수 매개 변수에 대한 포인터 및 'ref'한정자가 있으므로 참조로 값 유형을 전달 하고 C ++에서 와 같이 복사를 피할 수 있습니다.->*&


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