Java, Javascript 및 C #과 같은 메모리 관리 언어가 왜 'new'키워드를 유지 했습니까?


138

newJava, Javascript 및 C #과 같은 언어로 된 키워드는 클래스의 새 인스턴스를 만듭니다.

이 구문은 new힙에 클래스의 새 인스턴스를 할당하고 새 인스턴스에 대한 포인터를 반환하는 데 특히 사용되는 C ++에서 상속 된 것으로 보입니다 . C ++에서는 이것이 객체를 구성하는 유일한 방법은 아닙니다. new- 를 사용하지 않고 스택에 객체를 생성 할 수도 있습니다 . 실제로 객체를 생성하는이 방법은 C ++에서 훨씬 더 일반적입니다.

따라서 C ++ 배경에서 비롯된 newJava, Javascript 및 C #과 같은 언어 의 키워드는 자연스럽고 분명했습니다. 그런 다음 new키워드 가없는 Python을 배우기 시작했습니다 . 파이썬에서 인스턴스는 다음과 같이 생성자를 호출하여 간단히 구성됩니다.

f = Foo()

처음에는 파이썬이 가질 이유가 없다는 것이 생길 때까지 new모든 것이 객체이기 때문에 다양한 생성자 구문 사이에서 명확하게 할 필요가 없기 때문에 이것은 나에게 조금 벗어난 것처럼 보였다 .

그러나 나는 생각했다-실제로 newJava 의 요점은 무엇입니까? 왜 말해야 Object o = new Object();합니까? 왜 안돼 Object o = Object();? C ++에는 new힙에 할당과 스택에 할당을 구별해야하기 때문에 분명히 필요합니다 .하지만 Java에서는 모든 객체가 힙에 구성되므로 new키워드 가있는 이유는 무엇입니까? Javascript에 대해서도 같은 질문을 할 수 있습니다. 익숙하지 않은 C #에서는 new객체 유형과 값 유형을 구별하는 데 약간의 목적이있을 수 있지만 확실하지 않습니다.

어쨌든, C ++ 이후에 나온 많은 언어들은 new실제로 키워드 를 "상속 적으로"상속 하지 않은 것 같습니다. 그것은 흔적 키워드 와 거의 같습니다 . 우리는 어떤 이유로 든 필요한 것 같지 않지만 아직 거기에 있습니다.

질문 : 이것에 대해 맞습니까? 아니면 newJava가 아닌 Java, Javascript 및 C #과 같은 C ++에서 영감을 얻은 메모리 관리 언어로 작성해야하는 강력한 이유가 있습니까?


13
문제는 언어에 new키워드 가있는 이유 입니다. 물론 새로운 변수, 멍청한 컴파일러를 만들고 싶습니다! 좋은 언어는 내 의견으로는 같은 구문을 것이다 f = heap Foo(), f = auto Foo().

7
고려해야 할 매우 중요한 점은 언어가 새로운 프로그래머에게 얼마나 친숙한 지입니다. Java는 C / C ++ 프로그래머에게 친숙하게 보이도록 명시 적으로 설계되었습니다.

1
@Lundin : 실제로 컴파일러 기술의 결과입니다. 최신 컴파일러에는 힌트가 필요하지 않습니다. 해당 변수의 실제 사용을 기반으로 객체를 배치 할 위치를 파악합니다. 즉 f, 함수를 이스케이프하지 않으면 스택 공간을 할당하십시오.
MSalters

3
@Lundin : 사실 현대 JVM이 할 수 있습니다. 엔 f클로징 함수가 리턴 될 때 GC가 오브젝트를 수집 할 수 있음을 증명하는 것 입니다.
MSalters

1
언어가 왜 그런 식으로 디자인되었는지 물어 보는 것은 건설적인 일이 아닙니다. 특히 그 디자인이 명백한 이점없이 4 개의 추가 문자를 입력하도록 요구한다면? 내가 무엇을 놓치고 있습니까?
MatrixFrog

답변:


93

당신의 관찰은 정확합니다. C ++은 복잡한 짐승이며 new키워드는 delete나중에 필요한 것과 자동으로 재생 되는 것을 구별하는 데 사용되었습니다 . Java 및 C #에서는 delete가비지 수집기가 키워드를 처리하므로 키워드 를 삭제 했습니다.

문제는 왜 new키워드 를 유지 했 습니까? 언어를 쓰는 사람들과 이야기하지 않으면 대답하기가 어렵습니다. 가장 좋은 추측은 다음과 같습니다.

  • 그것은이었다 의미 론적으로 올바른. C ++에 익숙하다면 new키워드가 힙에 오브젝트를 작성 한다는 것을 알고 있습니다. 그렇다면 왜 예상되는 행동을 변화 시키는가?
  • 메소드를 호출하는 대신 객체를 인스턴스화한다는 사실에주의를 기울입니다. Microsoft 코드 스타일 권장 사항에서는 메서드 이름이 대문자로 시작하므로 혼동 될 수 있습니다.

Ruby는 Python과 Java / C # 사이에 new있습니다. 기본적으로 다음과 같은 객체를 인스턴스화합니다.

f = Foo.new()

키워드가 아니며 클래스의 정적 메소드입니다. 즉, 싱글 톤을 원할 new()경우 매번 동일한 인스턴스를 반환하도록 기본 구현을 재정의 할 수 있습니다 . 반드시 권장되는 것은 아니지만 가능합니다.


5
루비 문법은 훌륭하고 일관성있게 보입니다! C # 의 키워드 는 기본 생성자가있는 형식 의 일반 형식 제약 조건 으로도 사용됩니다 .
Steven Jeuris

3
예. 그러나 제네릭에 대해서는 이야기하지 않습니다. Java와 C #의 제네릭 버전은 매우 애매합니다. C ++을 말하지 않으면 이해하기가 훨씬 쉽습니다. 제네릭은 실제로 정적으로 형식이 지정된 언어에만 유용합니다. 파이썬, 루비, 스몰 토크와 같은 동적 타입 언어는 필요하지 않습니다.
Berin Loritsch

2
델파이는 Ruby와 비슷한 문법을 ​​가지고 있는데, 생성자는 일반적으로 Create (`f : = TFoo.Create (param1, param2 ...) '라는 이름을 사용한다는 점을 제외하고는 루비와 비슷합니다.
Gerry

Objective-C에서이 alloc메소드 (루비와 거의 동일 new)도 클래스 메소드 일뿐입니다.
mipadi

3
언어 디자인의 관점에서 키워드는 여러 가지 이유로 좋지 않습니다. 주로 키워드를 변경할 수 없습니다. 반면에 방법의 개념을 재사용하는 것이 더 쉽지만 구문 분석 및 분석하는 동안 약간의주의가 필요합니다. 스몰 토크와 그 친족은 메시지, C ++, 그리고 그 친족에게 메시지를 사용합니다
Gabriel Ščerbák

86

요컨대, 당신이 맞습니다. new 키워드는 Java 및 C #과 같은 언어에서 불필요합니다. 다음은 1990 년대 C ++ Standard Comitee의 일원이었고 나중에 Java에 관한 책을 출판 한 Bruce Eckel의 통찰력입니다. http://www.artima.com/weblogs/viewpost.jsp?thread=260578

힙 객체와 스택 객체를 구별 할 수있는 방법이 필요했습니다. 이 문제를 해결하기 위해 Smalltalk에서 새 키워드를 사용했습니다. 스택 객체를 만들려면 Cat x에서와 같이 간단히 선언하면됩니다. 또는, 인수로 Cat x ( "mittens") ;. 힙 오브젝트를 작성하려면 새 Cat에서와 같이 new를 사용하십시오. 또는 new Cat ( "mittens") ;. 제약 조건이 주어지면 우아하고 일관된 솔루션입니다.

C ++의 모든 것이 잘못되고 지나치게 복잡하다고 결정한 후 Java를 입력하십시오. 여기서의 아이러니 한 점은 자바가 스택 할당을 버리 겠다는 결정을 내릴 수 있었고 (다른 곳에서 다룬 프리미티브의 혼란을 무시하고) 지적했다. 또한 모든 객체가 힙에 할당되므로 스택 할당과 힙 할당을 구분할 필요가 없습니다. 그들은 Cat x = Cat () 또는 Cat x = Cat ( "mittens")라고 쉽게 말할 수 있습니다. 또는 반복을 제거하기 위해 형식 유추를 통합했습니다 (그러나 클로저와 같은 다른 기능은 "너무 오래 걸렸을 것입니다". 따라서 평범한 Java 버전 대신 붙어 있습니다. 유형 유추에 대해서는 논의했지만 Java에 새로운 기능을 추가하는 데 문제가 있다고 가정하면 안됩니다.


2
스택 대 힙 ... 통찰력, 결코 생각하지 않았을 것입니다.
WernerCD

1
"유형 추론에 대해 논의했지만 그 일이 일어나지 않을 확률이 높아질 것입니다.", :) 글쎄, Java의 개발은 여전히 ​​진행 중입니다. 이것이 Java 10의 유일한 주력이라는 점에 흥미가 있습니다. var키워드는 좋은으로 갑자기 가까운 autoC ++에있는,하지만 난 그것을 향상시킬 수 있기를 바랍니다.
patrik

15

내가 생각할 수있는 두 가지 이유가 있습니다.

  • new 객체와 프리미티브를 구별
  • new구문 좀 더 읽을 (IMO)

첫 번째는 사소한 것입니다. 나는 두 방법을 구별하는 것이 더 어렵다고 생각하지 않습니다. 두 번째는 OP 포인트의 예이며, 이는 new일종의 중복입니다.

그러나 네임 스페이스 충돌이있을 수 있습니다. 치다:

public class Foo {
   Foo() {
      // Constructor
   }
}

public class Bar {
   public static void main(String[] args) {
      Foo f = Foo();
   }

   public Foo Foo() {
      return Foo();
   }
}

상상력을 너무 많이 늘리지 않으면 무한 재귀 호출로 쉽게 끝날 수 있습니다. 컴파일러는 "객체와 동일한 기능 이름"오류를 적용해야합니다. 이것은 실제로 아프지 않을 것이지만 사용하기가 훨씬 간단합니다 new. Go to the object of the same name as this method and use the method that matches this signature.Java는 구문 분석하기가 매우 간단한 언어이며,이 부분이 도움이 될 것 같습니다.


1
이것은 다른 무한 재귀와 어떻게 다른가요?
DeadMG

그것은 일어날 수있는 나쁜 일에 대한 상당히 좋은 예입니다.하지만 그렇게하는 개발자에게는 심각한 정신 문제가있을 것입니다.
Tjaart

10

자바는 하나, 여전히 ++ C의 이분법이 있습니다하지 모든 객체입니다. Java에는 동적으로 할당 할 필요가없는 내장 유형 (예 : charint)이 있습니다.

그렇다고 newJava에서 실제로 필요한 것은 아닙니다. 동적으로 할당 할 필요가없는 유형 세트는 고정되어 알려져 있습니다. 객체를 정의 할 때 컴파일러는 단순한 값인지 char또는 동적으로 할당해야하는 객체 인지 알 수 있습니다 (사실 알고 있습니다) .

Java 디자인의 품질 (또는 경우에 따라 부족한 경우)에 대해 이것이 의미하는 바를 선택하지 말아야합니다.


또한 기본 유형은 생성자 호출이 전혀 필요하지 않습니다. 리터럴로 작성되거나 연산자 또는 기본 리턴 함수에서 작성됩니다. 실제로을 사용하지 않고 문자열 (힙에 있음)을 생성 new하므로 이것이 실제로는 아닙니다.
Paŭlo Ebermann

9

JavaScript에서는 생성자가 일반 함수처럼 보이기 때문에 필요하므로 JS가 새 키워드가 아닌 경우 새 객체를 만들려면 어떻게 알 수 있습니까?


4

흥미롭게도 VB 그것을 필요로합니다.

Dim f As Foo

변수를 할당하지 않고 선언합니다 Foo f;. C #과 동일합니다.

Dim f As New Foo()

변수를 선언하고 클래스의 새 인스턴스를 할당합니다. var f = new Foo();C # 과 동등한 것은 실질적인 구별입니다. pre-.NET VB에서, 당신도 사용할 수 있습니다 Dim f As Foo또는 Dim f As New Foo- 생성자에는 과부하가 없기 때문이다.


4
VB는 속기 버전이 필요 하지 않으며 약어 일뿐입니다. type 및 constructor Dim f As Foo = New Foo ()로 더 긴 버전을 작성할 수도 있습니다. C #의 var에 가장 가까운 Option Infer On을 사용하면 Dim f = New Foo ()를 작성할 수 있으며 컴파일러는 f 유형을 유추합니다.
MarkJ

2
... Dim f As Foo()배열 을 선언합니다 Foo. 오 기쁨! :-)
Heinzi

@MarkJ : vb.net에서 속기는 동일합니다. vb6에서는 그렇지 않았습니다. vb6에서는 읽는 동안 (즉 ) if를 구성하는 속성을 Dim Foo As New Bar효과적으로 만듭니다 . 이 동작은 한 번만 발생하는 것으로 제한되지 않았습니다. 설정 을 한 후 다른 새를 만들 것이다 읽기 . FooBarNothingFooNothingBar
supercat

4

나는 많은 답변을 좋아하고 이것을 추가하고 싶습니다.
코드를 더 쉽게 읽
습니다. C #과 다른 언어는 당연히 object예약어입니다. 그러나 그렇지 않은 경우 Foo = object()객체 메소드 호출의 결과이거나 새로운 객체를 인스턴스화합니다. new키워드가 없는 언어 는이 상황에 대해 보호 기능을 갖추고 있지만 new생성자를 호출하기 전에 키워드 가 필요 하므로 객체와 동일한 이름의 메소드가 존재할 수 있기를 바랍니다.


4
아마도 이것을 알아야한다는 것은 나쁜 징조입니다.
DeadMG

1
@DeadMG :“논쟁 적으로”는“막대가 닫힐 때까지 논쟁 할 것입니다”를 의미합니다…
Donal Fellows

3

많은 프로그래밍 언어에는 많은 흔적이 있습니다. 때로는 의도적으로 설계되어 있습니다 (C ++은 가능한 한 C와 호환되도록 설계되었습니다). 때로는 그저 있습니다. 보다 심각한 예를 들어, 깨진 C switch문이 얼마나 멀리 전파 되었는지 고려하십시오 .

Javascript와 C #을 잘 알지 못하지만 newJava에서 C ++에 해당하는 것 외에는 이유 가 없습니다.


자바 스크립트는 특히 자바와는 다른 일을 할 때에도 가능한 한 "자바처럼 보이도록"설계되었다고 생각합니다. x = new Y()JavaScript 에는 클래스 가 없으므로 JavaScript 에서 클래스를 인스턴스화Y 하지 않습니다 . 그러나 그것은 Java처럼 보이 므로 키워드를 Java에서 전달합니다. 물론 C ++에서 전달했습니다. new
MatrixFrog

고장난 스위치는 +1 (수리 희망 : D).
maaartinus

3

C #에서는 멤버에 의해 가려 질 수있는 컨텍스트에서 유형을 볼 수 있습니다. 유형과 이름이 같은 속성을 가질 수 있습니다. 다음을 고려하세요,

class Address { 
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

class Person {
    public string Name { get; set; }
    public Address Address { get; set; }

    public void ChangeStreet(string newStreet) {
        Address = new Address { 
            Street = newStreet, 
            City = Address.City,
            State = Address.State,
            Zip = Address.Zip
        };
    }
}

의 사용을 참고 new하면 해당 명확하게 할 수 Address는 IS Address타입이 아닌 Address멤버. 이를 통해 멤버는 유형과 동일한 이름을 가질 수 있습니다. 이것이 없으면 이름 충돌을 피하기 위해 유형의 이름 앞에 접두사를 붙여야합니다 CAddress. Anders는 헝가리어 표기법이나 이와 유사한 것을 좋아하지 않았고 C #이 없으면 사용할 수 있기를 원했기 때문에 이것은 매우 의도적이었습니다. 또한 친숙하다는 사실은 이중 보너스였습니다.


w00t와 Address는 Address라는 인터페이스에서 파생 될 수 있습니다. 따라서 동일한 이름을 재사용하고 코드의 일반적인 가독성을 줄일 수 있다는 이점이별로 없습니다. 따라서 인터페이스의 I을 유지하면서 클래스에서 C를 제거함으로써 실질적인 이점이없는 불쾌한 냄새가났습니다.
gbjbaanb

그들이 "new"대신 "New"를 사용하지 않는 것이 궁금합니다. 누군가는 그들에게 소문자가 있다고 말할 수 있습니다.이 문제를 해결합니다.
maaartinus

C #과 같은 C 파생 언어의 모든 예약어는 소문자입니다. 문법에는 모호성을 피하기 위해 여기에 예약어가 필요하므로 "New"대신 "new"를 사용하십시오.
chuckj

@gbjbaanb 냄새가 없습니다. 유형이나 속성 / 멤버 또는 함수를 참조하는지 여부는 항상 명확합니다. 실제 냄새는 네임 스페이스의 이름을 클래스와 동일하게 지정할 때입니다. MyClass.MyClass
Stephen

0

흥미롭게도, 완벽한 전달의 도래 new로 C ++에서도 비 배치 가 필요하지 않습니다. 따라서 언급 된 언어에서는 더 이상 필요하지 않습니다.


4
무엇 하시겠습니까? 궁극적으로 어떻게 든 std::shared_ptr<int> foo();전화해야합니다 new int.
MSalters

0

나는 자바 디자이너들이이 점을 가지고 있는지 모르겠어요하지만 당신은 같은 개체 생각하면 재귀 기록 , 당신은 그 상상할 수있는 Foo(123)객체하지만 그 fixpoint 객체가 생성되고 (예. 함수를 반환하는 함수를 반환하지 않습니다 인수로 지정되어있는 경우는, 작성 중의 오브젝트) 그리고 목적은 new"매듭을 묶고"그 고정 점을 반환하는 것입니다. 다시 말해서 new"object-to-be"가 그것의 것을 인식하게 할 self것이다.

이러한 종류의 접근 방식은 예를 들어 상속을 공식화하는 데 도움이 될 수 있습니다. 다른 객체 함수로 객체 함수를 확장하고 다음 self을 사용하여 공통으로 제공 할 수 있습니다 new.

cp = new (Colored("Blue") & Line(0, 0, 100, 100))

여기에는 &두 가지 객체 기능이 결합되어 있습니다.

이 경우 new다음과 같이 정의 할 수 있습니다.

def new(objectFunction) {
    actualObject = objectFunction(actualObject)
    return actualObject
}

-2

'nil'을 허용합니다.

Java는 힙 기반 할당과 함께 nil 객체 사용을 수용했습니다. 유물뿐만 아니라 기능으로도 사용됩니다. 객체가 nil 상태 일 수있는 경우 선언과 초기화를 분리해야합니다. 따라서 새로운 키워드입니다.

C ++에서 다음과 같은 줄

Person me;

기본 생성자를 즉시 ​​호출합니다.


4
음, 기본적으로 Nil에 문제가 Person me = Nil있거나 Person meNil이 Person me = Person()아닌 경우에 어떤 문제가 있습니까? 내 요점은 Nil이이 결정의 한 요인이었던 것 같지 않다는 것입니다 ...
Andres F.

당신은 요점이 있습니다. 사람 나 = 사람 (); 똑같이 잘 작동합니다.
Kris Van Bael

@AndresF. 또는 Person menil이 아닌 Person me()기본 생성자를 호출하여 더 간단 합니다. 따라서 무엇이든 호출하려면 항상 괄호가 필요하므로 하나의 C ++ 불규칙성을 제거하십시오.
maaartinus

-2

파이썬이 필요로하지 않는 이유는 타입 시스템 때문입니다. 기본적 foo = bar()으로 파이썬에서 볼 때 bar()호출되는 메소드, 인스턴스화되는 클래스 또는 functor 객체 인지 여부 는 중요하지 않습니다 . 파이썬에서는 함수와 함수 사이에 근본적인 차이가 없습니다 (메소드가 객체이기 때문에). 인스턴스화되는 클래스가 펑터의 특별한 경우라고 주장 할 수도 있습니다. 따라서 어떤 일이 일어나고 있는지에 특별한 차이를 만들 이유가 없습니다 (특히 메모리 관리가 파이썬에 너무 숨겨져 있기 때문에).

다른 타이핑 시스템이 있거나 언어와 메소드가 클래스가 아닌 언어에서는 오브젝트 작성과 함수 또는 펑터 호출 사이에 개념적 차이 가 더 커질 수 있습니다. 따라서 컴파일러 / 인터프리터에 new키워드 가 필요하지 않더라도 파이썬의 모든 경계를 무너 뜨리지 않은 언어로 유지 될 수 있음을 이해할 수 있습니다.


-4

실제로 Java에서는 문자열을 사용할 때 차이가 있습니다.

String myString = "myString";

~와 다르다

String myString = new String("myString");

문자열 "myString"이 이전에 사용 된 적이 없다고 가정하면 첫 번째 명령문은 문자열 풀 (힙의 특수 영역)에 단일 문자열 오브젝트를 작성하는 반면 두 번째 명령문은 오브젝트의 일반 힙 영역에 하나, 문자열 풀에 다른 오브젝트를 작성합니다. . 이 특정 시나리오에서 두 번째 진술은 쓸모가 없지만 언어로는 허용된다는 것이 명백합니다.

이는 새로운 객체가 힙의 해당 특수 영역에 객체가 생성되어 일반 객체 인스턴스화에 할당되었음을 보장하지만 객체가없는 객체를 인스턴스화하는 다른 방법이있을 수 있음을 의미합니다. 위의 예는 예이며 확장 성을위한 공간이 남아 있습니다.


2
그러나 이것은 문제가 아니었다. 문제는 "왜 안돼 String myString = String("myString");?" ( new키워드 가 없음에 주목 )
Andres F.

@AndresF. 명백한 imho의 종류 ... String 클래스에서 String을 반환하는 String이라는 메소드를 갖는 것이 합법적이며 호출하는 것과 생성자를 호출하는 것에는 차이가 있어야합니다. 같은 것class MyClass { public MyClass() {} public MyClass MyClass() {return null;} public void doSomething { MyClass myClass = MyClass();}} //which is it, constructor or method?
m3th0dman

3
그러나 분명하지 않습니다. 먼저, 일반적인 메소드 이름을 갖는 것은 StringJava 스타일 규칙에 위배되므로 대문자로 시작하는 메소드가 생성자라고 가정 할 수 있습니다. 두 번째로, 우리가 자바에 제약을받지 않는다면 스칼라는 생성자가 정확히 말한 것처럼 "케이스 클래스"를 가지고 있습니다. 문제가 어디에 있습니까?
Andres F.

2
죄송합니다, 당신의 주장을 따르지 않습니다. 의미론이 아닌 구문을 효과적으로 주장 하고 있으며 어쨌든 문제는 관리되는 언어 에 관한 것 new입니다 . 나는이 보여 전혀 필요하지 않습니다 (예 : 스칼라는 경우 클래스에 대한 필요하지 않음) 또한 (당신이 절대적이라는 방법이 없기 때문에 모호함이 없다는 것을 클래스를 어쨌든). 없다 모호함 에 대한이 ; 생성자 외에는 아무것도 될 수 없습니다. 마지막으로 동의하지 않습니다. 구문을 향상시키고 명확하게하기 위해 코드 규칙이 있습니다. newMyClassMyClassString s = String("hello")
Andres F.

1
그게 당신의 주장입니까? " new그렇지 않으면 Java의 구문이 다르기 때문에 Java 디자이너가 키워드를 필요로 했습니까?" 나는 당신이 그 주장의 약점을 볼 수 있다고 확신합니다.;) 그리고 당신은 의미론이 아닌 구문을 계속 논의합니다. 또한 이전 버전과의 호환성 은 무엇입니까? Java와 같은 새로운 언어를 디자인하는 경우 이미 C 및 C ++과 호환되지 않습니다!
Andres F.

-8

C #에서는 스택에서 생성 된 개체와 힙을 구분하기 위해 new가 중요합니다. 성능 향상을 위해 스택에 객체를 생성하는 경우가 종종 있습니다. 스택의 객체가 범위를 벗어나면 스택이 풀릴 때 기본 요소처럼 즉시 사라집니다. 가비지 콜렉터가이를 추적 할 필요가 없으며 힙에 필요한 공간을 할당하기 위해 메모리 관리자의 추가 오버 헤드가 없습니다.


5
불행히도 C #과 C ++을 혼동하고 있습니다.
gbjbaanb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.