왜 생성자가 아닌 Java 및 C #의 정적 기본 메소드입니까?


54

Java 및 C #에서 Application클래스 의 인스턴스로 애플리케이션 인스턴스를 표시하지 않고 (시작점으로) 정적 메소드를 시작점으로 결정한 이유에 대한 기본 또는 보조 소스에서 명확한 답변을 찾고 있습니다. 적절한 생성자).


나의 이전 연구의 배경과 세부 사항

이것은 이전에 요청되었습니다. 불행히도 기존 답변은 단지 질문을 구걸하고 있습니다. 특히, 다음 답변은 내가 틀렸다고 생각하기 때문에 나를 만족시키지 못합니다.

  • 생성자가 오버로드되면 모호성이 있습니다. – 실제로 C # (C 및 C ++)은 서로 다른 서명을 허용 Main하므로 동일한 잠재적 모호성이 존재하고 처리됩니다.
  • static방법은 이렇게 초기화의 순서가 명확하기 전에 어떤 객체가 인스턴스화 될 수 있다는 것을 의미한다. – 이것은 실제로 잘못되었습니다. 일부 객체 예를 들어 정적 생성자에서 인스턴스화됩니다.
  • 따라서 부모 개체를 인스턴스화하지 않고도 런타임에서 호출 할 수 있습니다. – 이것은 전혀 답이 아닙니다.

왜 이것이 타당하고 흥미로운 질문이라고 생각하는지 더 정당화하기 위해 :

  • 많은 프레임 워크 클래스를 사용하여 응용 프로그램과 생성자를 진입 점으로 나타냅니다. 예를 들어 VB.NET 애플리케이션 프레임 워크 는 전용 기본 대화 상자 (및 해당 생성자)를 진입 점 1로 사용 합니다.

  • Java 나 C # 모두 기술적 으로 기본 방법이 필요 하지 않습니다 . 글쎄, C #에는 컴파일 할 것이 필요하지만 Java는 그렇지 않습니다. 그리고 두 경우 모두 실행에 필요하지 않습니다. 따라서 이것은 기술적 제한으로 보이지 않습니다. 그리고 첫 번째 단락에서 언급했듯이 단순한 컨벤션의 경우 Java 및 C #의 일반적인 디자인 원칙에 맞지 않는 것 같습니다.

분명히 정적 메서드 를 사용하는 데 특별한 단점 이 없으며 main분명히 이상 합니다. 기술적 인 근거가 있는지 궁금합니다.

나는 단순한 추측이 아니라 일차 또는 이차 소스의 결정적인 답변에 관심이 있습니다.


1Startup 이것을 가로 챌 수 있는 콜백 ( )이 있습니다.


4
@mjfgates 또한, 나는 이것이 분명히 있음을 만들었을 기대했던 없습니다 단순히 "사람들이 그것을 내가 원하는 방식으로하지 않은 이유", 나는 이유에 진정으로 관심이있다.
Konrad Rudolph

2
Java의 경우 추론은 간단하다고 생각합니다. Java를 개발할 때 언어를 배우는 대부분의 사람들이 C / C ++를 미리 알고 있다는 것을 알고있었습니다. 따라서 Java는 smalltalk 대신 C / C ++와 비슷하게 보일뿐만 아니라 C / C ++에서 고유 한 특성을 취했습니다 (8 진 정수 리터럴 만 생각하면 됨). c / c ++는 둘 다 기본 메소드를 사용하므로 Java에 대해서도 동일한 방식으로 수행합니다.
Voo

5
@Jarrod 당신은 불공평합니다. 나는 그것을 분명하게 비난 하지 않았다고 생각했다 . 건설적이지 않습니까? 어떻게 요? 나는 단지 거친 토론뿐만 아니라 언급을 명시 적으로 요구하고 있습니다. 물론 이것이 흥미로운 질문 이라는 것에 동의하지 않아도 됩니다. 그러나 이런 종류 의 질문이 여기서 구약 이라면 Programmers.SE가 어떤 목적으로 사용되는지 알 수 없습니다.
Konrad Rudolph

2
관련 메타 토론 .
yannis

3
질문 : 응용 프로그램 객체 인 경우 두 가지가 필요하지 않습니다. 1) 생성자. 2) 응용 프로그램을 실행하는 객체의 방법. 객체가 유효하고 실행 가능하도록 생성자가 완료되어야합니다.
Martin York

답변:


38

TL; DR

자바에서 그 이유 public static void main(String[] args)

  1. 고슬링
  2. C에서 경험 한 사람이 작성한 코드 (Java가 아님)
  3. 실행하는 데 사용 누군가에 의해 실행되는 포스트 스크립트뉴스

http://i.stack.imgur.com/qcmzP.png

 
C #의 경우 추론은 전 이적으로 유사 합니다. 언어 설계자는 프로그램 진입 점 구문을 Java에서 온 프로그래머에게 친숙 하게 유지했습니다 . C # 설계자 인 Anders Hejlsberg는 다음과 같이 말합니다 .

... C #을 사용한 우리의 접근 방식은 단순히 Java 프로그래머에게 대안을 제공하는 것이 었습니다 ...

 

긴 버전

지루한 참조로 위로 확장하고 백업했습니다.

 

자바 터미네이터 Hasta la vista Baby!

VM 사양, 2.17.1 가상 머신 시작

... 초기 클래스가 JVM (Java Virtual Machine)에 지정되는 방식은이 스펙의 범위를 벗어나지 만 명령 행을 사용하는 호스트 환경에서는 클래스의 완전한 이름을 다음과 같이 지정하는 것이 일반적입니다. main 메소드에 대한 인수로 제공 될 문자열로 사용되는 명령 행 인수 및 후속 명령 행 인수 예를 들어, Solaris 용 Sun의 Java 2 SDK (명령 줄)를 사용하면

java Terminator Hasta la vista Baby!

클래스의 메인 메소드 Terminator(명명되지 않은 패키지 의 클래스)를 호출하고 네 개의 문자열 "Hasta", "la", "vista"및 "Baby!"를 포함하는 배열을 전달 하여 Java 가상 머신을 시작합니다 .

... 참조 : 부록 : 옷, 부츠, 오토바이가 필요합니다

  • 내 해석 :
    명령 줄 인터페이스의 일반적인 스크립트처럼 사용하기위한 실행.

 

중요한 회피

조사에서 몇 가지 잘못된 흔적을 피하는 데 도움이됩니다.

VM 스펙, 1.2 Java 가상 머신

자바 가상 머신은 자바 프로그래밍 언어를 전혀 모른다 ...

이전 장 -1.1 에서 공부할 때 위와 같은 사실을 알았습니다 .

  • 내 해석 :
    실행은 VM 사양 단독으로 관리되며
    Java 언어
    => OK 와 관련이 없으므로 JLS 와 Java 언어 를 무시 합니다.

 

고슬링 : C 언어와 스크립팅 언어의 타협 ...

위의 내용을 바탕으로 웹에서 JVM 히스토리 를 검색하기 시작했습니다 . 결과에 너무 많은 쓰레기가 도움이되지 않았습니다.

그런 다음 Gosling에 대한 전설을 기억하고 Gosling JVM history로 검색 범위를 좁혔습니다 .

유레카! JVM 사양은 어떻게 되었습니까?

James Gosling은 JVM Languages ​​Summit 2008의 기조 연설에서 Java의 생성, C와 스크립팅 언어의 타협에 대해 설명합니다.

  • 내 해석 :
    창조 순간
    C와 스크립팅이 가장 중요한 영향으로 간주되었다는 명시 적 선언 .
     
    이미 VM 사양 2.17.1에서 스크립트에 고개를 끄덕 볼,
    명령 줄 인수 충분히 설명 String[] args
    하지만, staticmain더 발굴 할 필요가 아직 없습니다 ...

Java를 사용하지 않고 C, 스크립팅 및 VM Spec 1.2를 연결하는 동안 이것을 입력하는 동안 친숙하고 무언가 ... 객체 지향 객체 가 천천히 사라지는 것처럼 느낍니다 . 내 손을 잡고 움직여 라 '천천히 하지마 우리는 거의 다 왔어

키 노트 슬라이드는 온라인으로 제공됩니다 : 20_Gosling_keynote.pdf , 키포인트 복사에 매우 편리합니다.

    3 페이지

        자바의 선사 시대
        * 내 생각의 원인

    9 페이지

        뉴스
        * 네트워크 확장 가능 윈도우 시스템
        * 스크립팅 기반의 윈도우 시스템 ....
          포스트 스크립트 (!!)

    16 페이지

        큰 (하지만 조용한) 목표 :
          내가 얼마나 가까이 갈 수 있을까
          "스크립팅"느낌 ...

    19 페이지

        원래 개념
        * 건물에 관한 모든 것
          사물의 네트워크,
          스크립팅으로 조정
          언어
        * (유닉스 쉘, AppleScript, ...)

    20 페이지

        양의 늑대
        * 개발자를위한 C 구문
          편안

아하! C 구문을 자세히 살펴 보자 .

"hello, world"예제 ...

main()
{
    printf("hello, world\n");
}

... main이라는 함수가 정의되고 있습니다. 주요 기능은 C 프로그램에서 특별한 용도로 사용됩니다; 런타임 환경은 main 함수를 호출하여 프로그램 실행을 시작합니다.

... 주 함수에는 실제로 두 개의 인수가 int argc있으며 char *argv[], 각각 명령 행 인수를 처리하는 데 사용할 수 있습니다.

우리는 점점 가까워지고 있습니까? 물론이지. 위의 인용문에서 "main"링크를 따르는 것도 가치가 있습니다.

주요 기능은 프로그램이 실행을 시작하는 곳입니다. 프로그램 기능의 상위 레벨 조직을 담당하며 일반적으로 프로그램이 실행될 때 제공된 명령 인수에 액세스 할 수 있습니다.

  • 내 해석 :
    C 개발자가 편하게하려면 프로그램 시작 지점이이어야 main합니다.
    자바 클래스에있을 어떤 방법을 필요로하기 때문에, Class.main있다
    가수록 가까운 정적 호출, 단지 클래스 이름과 점은,
    어떤 생성자하십시오 - C는 그런 아무것도 모른다.
     
    이는 Java에서 쉽게 마이그레이션 할 수 있다는 아이디어 를 고려 하여 C # 에도 전 이적으로 적용됩니다
    .

친숙한 프로그램 진입 점이 중요하지 않다고 생각하는 독자들은 Java SE에서 온 사람들이 Hello ME for Java ME MIDP 를 작성하려고 시도하는 스택 오버플로 질문을 검색하고 확인하도록 친절하게 초대됩니다 . 참고 MIDP 진입 점 에는도 main없습니다 static.

 

결론

나는 그 말을 상기 내용을 토대로 static, main그리고 String[] args정의하는 자바와 C # 만드는 가장 합리적인 선택의 순간에 있었던 프로그램의 진입 점을 .

 

부록 : 옷, 부츠, 오토바이가 필요합니다

VM Spec 2.17.1 을 읽는 것은 엄청난 재미였습니다.

... 명령 줄

java Terminator Hasta la vista Baby!

클래스의 메소드 main Terminator(이름없는 패키지 의 클래스)을 호출하고 "Hasta", "la", "vista"및 "Baby!"라는 네 개의 문자열을 포함하는 배열을 전달 하여 Java 가상 머신을 시작합니다 .

이제 Terminator이후 섹션에서 자세히 설명하는로드, 링크 및 초기화 프로세스의 예로 가상 머신이 실행하는 단계를 간략하게 설명합니다.

초기 시도는 ... 클래스 Terminator가로드되지 않았 음을 발견합니다 .

Terminator로드 된 후에 는 main을 호출하기 전에 초기화해야하며, 유형 (클래스 또는 인터페이스)이 초기화되기 전에 항상 링크되어야합니다. 연결 (§2.17.3)에는 검증, 준비 및 (선택적) 해결이 포함됩니다 ...

검증 (§2.17.3)은로드 된 표현 Terminator이 잘 구성되어 있는지 확인합니다 .

결의안 (§2.17.3)은 클래스에서 상징적 참조를 확인하는 과정이다 Terminator.

 
Terminator오 예 에서 상징적 인 참조 .


2
어떤 이유로 나는 "현대성"이 실제 단어라고 믿기 어려웠습니다.
someguy

@Songo의 해답은 영화와도 같습니다. 그것은 질문 폐쇄에 대한 토론 에서 메타 에 처음 게시 되었습니다 .
gnat

16

그것은 나에게 모호하게 느낀다. 생성자는 객체의 초기화에 사용됩니다. 객체를 설정 한 다음 객체를 생성 한 코드에서 사용합니다.

생성자 내부에 기본 사용 기능을 넣은 다음 생성자가 만든 코드를 실제로 외부 코드로 사용하지 않으면 OOP의 원칙을 위반하는 것입니다. 기본적으로 명백한 이유없이 정말 이상한 일을합니다.

어쨌든 왜 그렇게 하시겠습니까?


5
그러나“애플리케이션 인스턴스”는 논리적으로 객체가 아닌가? 왜 그렇게 모욕적인가? 객체 사용과 관련하여 실행중인 응용 프로그램을 나타내는 한 가지 목적이 있습니다. 매우 SoC -y 나에게 들린다 . “왜 그렇게하고 싶습니까?”– 나는 그 결정이 나머지 다른 사고와 상충되는 것을 알기 때문에 단지 결정에 대한 이론적 근거에 관심이 있습니다.
Konrad Rudolph

7
@KonradRudolph : 속성 게터와 같은 생성자는 일반적으로 사용자 입력과 같은 일부 비동기 이벤트가 발생하기를 기다리지 않고 제한된 시간 안에 완료 될 것으로 예상됩니다. 주 응용 프로그램 스레드를 시작한 생성자를 가질 수는 있지만 모든 응용 프로그램에 필요하지 않은 수준의 복잡성을 추가합니다. 단순히 "Hello world"를 표준 출력으로 인쇄하는 콘솔 응용 프로그램을 사용하려면 추가 스레드가 생성되어야합니다. Main방법을 사용하는 것은 간단한 경우에 잘 작동하며 어려운 경우에는 실제로 문제가되지 않습니다. 왜 그렇지 않습니까?
supercat

9

Java의 경우 추론은 간단하다고 생각합니다. Java를 개발할 때 개발자는 언어를 배우는 대부분의 사람들이 C / C ++를 미리 알고 있다는 것을 알고있었습니다.

따라서 Java는 smalltalk 대신 C / C ++와 비슷하게 보일뿐만 아니라 C / C ++에서 고유 한 특성을 취했습니다 (8 진 정수 리터럴 만 생각하면 됨). c / c ++는 둘 다 기본 메소드를 사용하므로 Java에 대해서도 동일한 방식으로 수행합니다.

나는 왜 8 진 정수 리터럴을 추가했는지에 대해 블로크 나 누군가 가이 줄을 따라 무언가를 말하고 있다는 것을 기억합니다. 나는 어떤 출처를 찾을 수 있는지 볼 것입니다 :)


2
예를 들어 변화를 그들이 왜 그랬는지 찾고 있다면 C ++과 같은, 자바 훨씬 중요 :extends? 그리고 public static void main(String [ ] args)수업 내부는 수업 int main(int argc, char **argv)외부와는 다릅니다 .
svick

2
@svick 하나의 가능성 : Java는 인터페이스를 도입했으며 분명히 작동하지 않는 하나의 "키워드"로 두 가지 개념 (인터페이스 / 클래스 상속)을 분리하려고했습니다. 그리고 "quite different"? 그것은 가장 가까운 가능한 매핑이며 지금까지 c ++ 프로그래머가 정적 기본 메소드가 진입 점이라는 것을 이해하는 데 문제가있는 것을 본 적이 없습니다. Application이라는 클래스 또는 생성자가 사용되는 클래스와 달리 대부분의 C ++ 프로그래머에게는 이상하게 보일 수 있습니다.
Voo

Java에서 c의 @svick int는 System.exit (int)가 호출되지 않으면 응용 프로그램의 리턴 코드 생성 방법과 관련이 있습니다. 매개 변수 변경은 문자열 배열이 각 언어로 전달되는 방법과 관련이 있습니다. 자바의 모든 것은 클래스에 있습니다-다른 곳에서 가질 수있는 옵션이 없습니다. 로 변경 :하는 extends것은 구문의 문제이며 본질적으로 동일합니다. 다른 모든 언어에 의해 지시됩니다.

@MichaelT 그러나 모든 것은 Java를 C ++과 다르게 만드는 디자인 결정입니다. 따라서 Java의 경우 C ++과 동일하게 유지하는 이유는 main()다른 경우에는 그렇게 중요하지 않은 경우에 중요합니다.
svick

@svick C의 main에서 아무것도 반환하지 않는 것이 완벽하다는 것을 제외하고는 사소한 일이 누군가를 혼동하지 않습니다. 요점은 C ++과 모든 실수를 재현하는 것이 아니라 프로그래머를 집에서 더 많이 만드는 것입니다. C ++ 프로그래머가 Java 또는 objective-c 코드를 쉽게 읽을 수 있다고 생각하십니까? C ++ 프로그래머에게 진입 점으로 주요 메소드 또는 일부 클래스의 생성자에게 더 분명하게 보이는 것은 무엇입니까?
Voo

6

음, 무한 루프를 실행하는 많은 주요 기능이 있습니다. 이런 식으로 작동하는 생성자 (생성되지 않은 객체로)는 나에게 이상한 것 같습니다.

이 개념에는 많은 재미있는 것들이 있습니다. 태어나지 않은 개체 (생성자에서 모든 작업을 수행하기 때문에), 태어나지 않은 개체 위에서 실행되는 논리, ...

이 모든 부작용이 단순한 대중보다 OO 왜건을 훨씬 더 많이 손상 시키지는 않습니까? )?

간단하고 평범한 함수 진입 점이 Java에 존재하려면 공개 및 정적이 자동으로 필요합니다. 정적 메소드 이지만 원하는 기능을 달성하기 위해 일반 함수에 더 가깝게 도달 할 수있는 것, 즉 간단한 진입 점으로 요약합니다.

단순하고 평범한 기능 진입 점을 진입 점으로 채택하지 않으려는 경우. 다음은 건설자가 아닌 건설업자로서 이상하게 보이지 않는 것은 무엇입니까?


1
문제가 일급 기능을 가지고 있지 않다고 말하고 싶습니다. main ()을 객체 내부에 고정시키는 것은 (메인이 호출되기 전에 인스턴스화되지 않음) 약간의 반 패턴입니다. 아마도 그것들은 비 정적 main () 메소드를 구성하고 실행하는 "application"객체를 가지고 있어야합니다. 그러면 생성자에 시작 초기화를 넣을 수 있습니다. = level main () fn도 좋습니다. 정적 메인은 전체적으로 약간의 혼란입니다.
gbjbaanb

3

테스트 main()하려는 클래스를 사용 하여 개발 중에 클래스에서 일부 독립형 테스트를 빠르게 실행할 수 있습니다 .


1
이것은 다른 구성 등을 테스트하기 위해 개발 중에 여러 진입 점을 허용하기 때문에 아마도 가장 매력적인 이유 일 것입니다.
cgull

0

당신은 어딘가에서 시작해야합니다. 정적 기본은 가장 간단한 실행 환경으로, JVM 및 간단한 문자열 매개 변수를 제외한 어떤 인스턴스도 만들 필요가 없으므로 최소한의 번거 로움이 적고 가능성이 낮습니다. 시작 등을 방지하는 코딩 오류) 및 다른 많은 설정없이 간단한 작업을 수행 할 수 있습니다.

기본적으로 KISS의 응용 프로그램입니다.

[물론, 주된 이유는 무엇입니까?]


3
내가 말했듯이, 나는 그것에 대해 전혀 확신하지 못한다. 객체 이전에 인스턴스화되고 코드는 이전에 실행됩니다. 이것이 원래 이유임을 확신시키기 위해 원래 개발자 중 한 사람의 인용이 필요합니다.
Konrad Rudolph

2
C 코드에서 클래스를 인스턴스화하는 데 필요한 작업량은 정적 메서드를 호출하는 것과 거의 동일합니다. 동일한 검사를 수행해야합니다 (클래스가 존재합니까? 벌금).
Voo

어떤 사용자 개체를 생성 할 필요가 없습니다. 객체 생성자는 실행되지 않습니다. API는 엄청나게 간단합니다. 그리고 이해하기가 가장 쉽습니다.
Daniel R은

0

내가 이해하는 주된 이유는 간단합니다. Sun은 유닉스 머신을 판매하는 유닉스 회사였으며 유닉스는 바이너리를 호출하기위한 C "main (args)" 규약 이 고안된 것입니다.

또한 Java는 C 및 C ++ 프로그래머가 쉽게 선택할 수 있도록 명시 적으로 설계되었으므로 단순히 C 규칙을 선택하는 것만으로는 충분하지 않습니다.

모든 클래스가 호출 메소드를 가질 수있는 선택된 접근법은 특히 Main-Class실행 가능한 jar의 MANIFEST.MF 파일 의 행 과 결합하여 매우 유연 합니다.


물론 jar 파일은 훨씬 이후까지 발명되지 않았습니다.
Daniel R은

-1

정의에 의해 하나 이상을 가질 수있는 방법이 없기 때문에 프로그램이 OS 프로세스 관점에서 객체가된다는 것은 OOP 철학과 일치하지 않습니다.

게다가 생성자는 결코 진입 점이 아닙니다.

정적 기능으로 main을 갖는 것이 가장 합리적인 선택 인 것 같습니다. 실제로 하루가 끝났습니다. JVM 및 CLR과 같은 VM의 아키텍처를 고려할 때 다른 선택은 불필요하게 푸시합니다.


1
나는 당신이 잘못 생각합니다. 하나 개 이상의 프로세스, 따라서 하나 개 이상의 객체를 가질 수있다. 또한 이것은 Runnable여러 스레드를 갖도록 객체를 인스턴스화하는 것과 완전히 같습니다 .
Konrad Rudolph

프로세스는 실행중인 프로그램이므로 하나의 진입 점을 통해 프로세스를 한 번만 시작할 수 있습니다. 스레드는 자체 진입 점이 있지만 여전히 동일한 프로세스 내에 있습니다.
얌 마르코비치

1
내가 누군가의 대답 아래에서 말했듯이, 이것은 관련이 없습니다. 관련된 것은 논리적 일관성입니다. 논리적으로 프로세스는 실행기 (OS, JVM 등)에 의해 객체로 표시되며 초기화됩니다.
Konrad Rudolph

@KonradRudolph 사실이지만 프로그램의 초기화는 프로세스 초기화의 일부일 뿐이며 프로그램 생성자를 정당화하지는 않습니다.
얌 마르코비치
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.