Java 기본 메소드가 정적 이유는 무엇입니까?


505

Java main () 메소드 의 메소드 서명 은 다음과 같습니다.

public static void main(String[] args){
    ...
}

이 방법이 정적 인 이유가 있습니까?


1
이 경우, 용어는 메소드 이름과 그 매개 변수만을 지칭하기 때문에 메소드 서명을 말해서는 안됩니다.
Andrew Tobilko

Java는 의도적으로 C 프로그래머에게 친숙해 보이도록 설계되었습니다. 이것은 C 규칙에 매우 가깝습니다.
Thorbjørn Ravn Andersen

답변:


337

그렇지 않으면 모호성이 있기 때문에이 메소드는 정적입니다. 어떤 생성자를 호출해야합니까? 특히 수업이 다음과 같은 경우 :

public class JavaClass{
  protected JavaClass(int x){}
  public void main(String[] args){
  }
}

JVM이 호출해야합니까 new JavaClass(int)? 무엇을 통과해야 x합니까?

그렇지 않은 경우 JavaClass생성자 메서드를 실행하지 않고 JVM을 인스턴스화해야 합니까? 나는 그것이 전체 클래스를 특별하게 만들 것이기 ​​때문에 그렇게해서는 안된다고 생각합니다. 때때로 초기화되지 않은 인스턴스가 있고 호출 할 수있는 모든 메소드에서 확인해야합니다.

엔트리 포인트가 호출되기 전에 JVM이 클래스를 인스턴스화해야하는 경우를 이해하기에는 너무 많은 경우와 모호함이 있습니다. 그게 main정적 인 이유 입니다.

main항상 표시되어 있는지 모르겠습니다public .


4
인터페이스를 구현해도 인스턴스화 문제가 해결되지 않습니다.
Jacob Krall

26
개인적 public static void main으로이 점이 진입 점의 마커 역할을합니다. 공개 매개 변수가없는 생성자는 "이것은 아마도 진입 점입니다!" 같은 방법으로.
Jacob Krall

5
@EdwinDalorzo-진입 점 클래스를 인스턴스화하도록하여 얻을 수있는 것은 무엇입니까? 정적 메서드를 호출하면 클래스에 부담이 가장 적습니다. 디자인에 더 적합한 경우 자유롭게 인스턴스화 할 수 있습니다.
David Harkness

18
"어떤 생성자를 호출해야합니까?" 어떻게 즉 도 생각할 문제? 어떤 결정을 내려야 할 지에 대해 동일한“문제”가 존재합니다 main. 이상하게도 (당신을 위해) JVM은 이것을 잘 관리합니다.
Konrad Rudolph

9
기본 메소드는 런타임 엔진 인 JVM에서 액세스해야하므로 항상 공용입니다.
gthm

398

이것은 단지 관습입니다. 사실 main ()이라는 이름과 전달 된 인수조차도 전적으로 관례입니다.

java.exe (또는 Windows의 경우 javaw.exe)를 실행할 때 실제로 발생하는 것은 몇 가지 JNI (Java Native Interface) 호출입니다. 이러한 호출은 실제로 JVM 인 DLL을로드합니다 (즉, java.exe는 JVM이 아님). JNI는 가상 머신 세계와 C, C ++ 등의 세계를 연결해야 할 때 사용하는 도구입니다. 그 반대도 마찬가지입니다. (적어도 내 지식으로는) 실제로는 얻을 수 없습니다. JNI를 사용하지 않고 실행중인 JVM.

기본적으로 java.exe는 명령 행을 구문 분석하고 JVM에서 새 문자열 배열을 작성하여 해당 인수를 보유하고 main ()을 포함하도록 지정한 클래스 이름을 구문 분석하고 JNI 호출을 사용하여 main () 메소드 자체가 main () 메소드를 호출하여 새로 작성된 문자열 배열을 매개 변수로 전달합니다. 이것은 자바에서 리플렉션을 사용할 때하는 것과 매우 흡사합니다. 대신 혼란스러운 이름의 네이티브 함수 호출을 사용합니다.

자신의 버전의 java.exe (소스는 JDK와 함께 배포 됨)를 작성하고 완전히 다른 방식으로 작업하는 것이 완벽하게 합법적입니다. 사실, 그것은 우리가 모든 Java 기반 앱으로하는 일입니다.

각 Java 앱에는 자체 실행기가 있습니다. 우리는 주로이 작업을 수행하여 자체 아이콘과 프로세스 이름을 얻지 만, 일반적인 main () 호출 이외의 작업을 수행하려는 다른 상황에서 유용합니다 (예를 들어, 어떤 경우에는 COM 상호 운용성, 실제로는 문자열 핸들 대신 main ()에 COM 핸들을 전달합니다.

그래서 길고 짧습니다 : 정적 인 이유는 b / c가 편리합니다. 그것이 'main'이라고 불리는 이유는 그것이 무언가 여야했기 때문이며 main ()은 C의 옛날 시절에했던 일입니다 (그리고 그 당시에는 함수의 이름 중요했습니다). java.exe를 사용하면 클래스 (java com.mycompany.Foo.someSpecialMain) 대신 정규화 된 기본 메소드 이름을 지정할 수 있다고 생각하지만 IDE에서 ' 프로젝트에서 실행 가능한 클래스.


66
+1 : 매우 흥미 롭습니다 (특히 관례 작성에 관한 부분 java.exe)
Adam Paynter

9
흥미롭게도 "이것은 컨벤션 일뿐입니다."에 동의하지 않습니다. 답의 일부. OP의 주요 질문은 선언에서 정적 이유였습니다. 나는 생각하지 않는다 static에서 main()선언이 단지 컨벤션을 위해입니다. 그러나 그것이`main () '이고 다른 것이 아니라는 사실은 실현 가능합니다.
Jared

2
@David 그렇게했다. 나는 실제로 원래 관련된 사람들 중 한 사람의 답변을 선호했을 것입니다. 다른 답변의 대부분은 불행히도 임시 추론의 연습입니다. 이것은 (아마도) 비 기술적 원인을 추론하기 위해 잘못된 기술적 세부 사항을 발명하지 않는 겸손을 갖는 것 외에도 상당히 흥미로운 세부 사항을 제공합니다.
Konrad Rudolph

2
@Jared-공개 인수없는 생성자가 필요할 수 있고 main비 정적 상태를 유지하면서도 언어의 범위에 맞출 수있었습니다. 디자이너의 의견을 듣지 않으면 동의하지 않으면됩니다. :)
David Harkness

4
@BenVoigt jLib dll을 얻기 위해 LoadLibrary ()를 호출합니다. 그런 다음 getprocaddress ( "JNI_CreateJavaVM")를 호출 한 다음 JNI_CreateJavaVM 함수 ( docs.oracle.com/javase/1.4.2/docs/guide/jni/spec/… ) 를 호출합니다 . VM이로드되면 표준 JNI 호출을 사용하여 올바른 클래스를 찾고 정적 기본 메소드를로드하고 호출하십시오. 거기에 오해의 여지가 많지 않습니다. JNI는 절대적으로 VM을로드하는 방법입니다. 네이티브 키워드 javah -jni 등을 사용하여 클라이언트 측 JNI 만 작성하는 데 익숙 할 수 있지만 JNI의 절반에 불과합니다.
Kevin Day

188

main()의 방법 C++, C#그리고 Java정적
들이 다음 런타임 엔진에 의해 호출 될 수 있기 때문에 하지 않고 본문에 다음 코드를 어떤 객체를 인스턴스화하는 데 main()나머지를 할 것입니다.


1
그래도 런타임에서 클래스의 한 객체를 인스턴스화 할 수 없었습니까? 그런 다음 Main 메소드를 호출합니까? 왜?
Andrei Rînea

12
기본 클래스에 생성자가 오버로드 된 경우 JVM이 호출 할 생성자를 어떻게 알 수 있습니까? 어떤 매개 변수를 전달합니까?
Jacob Krall

1
@Noah 부모 클래스를 말할 때 주요 메소드가 포함 된 클래스를 의미합니까? 그렇다면 "부모 클래스"라는 용어는 여기에서 다소 혼란스럽고 그렇지 않으면 나에게는 의미가 없습니다. 또한 규칙에 따라을 사용 public static void main...하는 경우 응용 프로그램 진입 점 클래스에 공개 기본 생성자가 있어야한다는 규칙이없는 이유는 무엇입니까?
에드윈 달로 조

2
@Jacob JVM이 어떤 오버로드 static void main를 호출 하는지 어떻게 알 수 있습니까? 전혀 문제가 없습니다.
Konrad Rudolph

4
@Namratha : 예, 뭔가 빠졌습니다. "정적 메소드가 비 정적 메소드를 참조 할 수 없음"은 사실이 아닙니다. 올바른 진술은 "정적이 아닌 메소드를 사용할 때 모든 정적 메소드가 오브젝트를 제공해야합니다"입니다. 그리고 이러한 객체를 만드는 데 자주 사용 되는 static방법을 보십시오 . mainnew
Ben Voigt

38

왜 public static void main (String [] args)입니까?

Java 언어가 설계되고 Java Virtual Machine이 설계되고 작성되는 방식입니다.

Oracle Java 언어 사양

체크 아웃 장 12 실행 - 제 12.1.4 호출 Test.main를 :

마지막으로 Test 클래스의 초기화가 완료된 후 (다른 결과적로드, 링크 및 초기화가 발생한 동안) Test의 main 메소드가 호출됩니다.

main 메소드는 public, static 및 void로 선언해야합니다. 문자열 배열 인 단일 인수를 허용해야합니다. 이 방법은 다음 중 하나로 선언 될 수 있습니다

public static void main(String[] args)

또는

public static void main(String... args)

Oracle Java Virtual Machine 사양

확인 2 장 자바 프로그래밍 언어의 개념 - 섹션 2.17 실행 :

JVM (Java Virtual Machine)은 지정된 클래스의 메소드 main을 호출하고 단일 배열 (문자열 배열)을 전달하여 실행을 시작합니다. 이로 인해 지정된 클래스가로드되고 (§2.17.2), 사용되는 다른 유형에 연결되고 (§2.17.3) 초기화됩니다 (§2.17.4). main 메소드는 public, static 및 void로 선언해야합니다.

Oracle OpenJDK 소스

소스 jar을 다운로드하고 추출하여 JVM 작성 방법을 확인하십시오 ../launcher/java.c. 여기에는 명령 뒤에 기본 C 코드가 포함되어 있습니다 java [-options] class [args...].

/*
 * Get the application's main class.
 * ... ...
 */
if (jarfile != 0) {
    mainClassName = GetMainClassName(env, jarfile);

... ...

    mainClass = LoadClass(env, classname);
    if(mainClass == NULL) { /* exception occured */

... ...

/* Get the application's main method */
mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
                                   "([Ljava/lang/String;)V");

... ...

{    /* Make sure the main method is public */
    jint mods;
    jmethodID mid;
    jobject obj = (*env)->ToReflectedMethod(env, mainClass,
                                            mainID, JNI_TRUE);

... ...

/* Build argument array */
mainArgs = NewPlatformStringArray(env, argv, argc);
if (mainArgs == NULL) {
    ReportExceptionDescription(env);
    goto leave;
}

/* Invoke main method. */
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);

... ...

4
여기서 문제는 실제로 많은 참고 문헌 (+1)과 함께 원래 형태의 질문에 대한 아주 좋은 대답이라는 것입니다. 그러나 정적 메서드를 생성자 또는 인스턴스 메서드가 아닌 진입 점으로 만드는 디자인 결정의 이론적 근거 에 대해 배우고 싶습니다 .
Konrad Rudolph

1
@KonradRudolph, 언어 및 JVM 사양 설계에 관한 질문은 Oracle의 원본 소스에 문의하여 긍정적 인 피드백을받을 수 있는지 확인하십시오.
yorkw

2
일반적으로 메소드 결과 계산이 매개 변수에만 의존하여 오브젝트 인스턴스 내부 상태에 의존하지 않으면 정적 일 수 있습니다. 또한 코드 유지 관리 / 재사용 성을 위해 정적으로 설정하는 것이 좋습니다. 메소드 main가 정적이 아닌 경우, 클래스 인스턴스 상태를 알아야하며 먼저 사용할 생성자와 같이 정의하기가 훨씬 더 복잡합니다.
이브 마틴

@KonradRudolph 흥미롭게도, 오크 (자바의 전신)는 이미 유사한 프로토 타입을 가지기위한 주요 방법을 요구했다 :-Reference public static void main(String arguments[]): Oak 0.2 Spec .
assylias

2
@Yves 가능 합니다. 다른 디자인이 의미가 있다면 필요하지 않습니다. 여기 코멘트에 좋은 인수를 들었어요하지만, 난 여전히 프로세스가 매우 스레드 (이 같은 효율적이라고 생각 이다 ), 그리고 자바에서 쓰레드가 보통의 인스턴스로 표현된다 Runnable. 전체 프로세스를 동일한 방식으로 (즉 Runnable.Run, 진입 점으로) 나타내는 것은 Java에서 의미가 있습니다. 물론 RunnableJava 자체에는 익명의 메소드가 아직 없기 때문에 디자인 결함이라고 할 수 있습니다. 그러나 그것이 이미 있기 때문에 ...
Konrad Rudolph

36

단순히 static응용 프로그램 진입 점으로 필요하지 않은 척하자 .

응용 프로그램 클래스는 다음과 같습니다.

class MyApplication {
    public MyApplication(){
        // Some init code here
    }
    public void main(String[] args){
        // real application code here
    }
}

생성자 코드와 main메소드 의 구분은 OO에서 생성자가 인스턴스가 올바르게 초기화 되었는지 확인해야하기 때문에 필요 합니다. 초기화 후 인스턴스는 의도 한 "서비스"에 사용될 수 있습니다. 완전한 응용 프로그램 코드를 생성자에 넣으면 그것을 망칠 것입니다.

따라서이 접근법은 응용 프로그램에 대해 세 가지 다른 계약을 강요 합니다.

  • 기본 생성자 가 있어야합니다 . 그렇지 않으면 JVM은 호출 할 생성자와 어떤 매개 변수를 제공해야하는지 알 수 없습니다.
  • 있어야합니다main방법 1 . 좋아, 이것은 놀라운 일이 아니다.
  • 수업 이 아니어야 합니다 abstract. 그렇지 않으면 JVM이 인스턴스화 할 수 없습니다.

반면 static에이 접근법은 하나의 계약 만 필요합니다 .

  • main방법 1 이 있어야합니다 .

여기서도 abstract여러 생성자가 중요 하지 않습니다.

Java는 사용자를 위해 간단한 언어 로 설계되었으므로 응용 프로그램 진입 점도 하나의 계약을 사용하여 간단한 방식으로 설계되었지만 세 개의 독립적이고 취약한 계약을 사용하는 복잡한 방식이 아니라는 점은 놀라운 일이 아닙니다 .

참고 :이 인수는 JVM 내부 또는 JRE 내부의 단순성에 관한 것이 아닙니다 . 이 주장은 사용자의 단순성에 관한 것 입니다.


1 여기서 완전한 서명은 하나의 계약으로 만 간주됩니다.


1
사실, 요구 사항은 더 복잡 같습니다이 있어야 main이다 방법 public, static그리고 서명이 있습니다 void main(String[]). 메소드가 인스턴스 메소드 인 경우 JRE는 약간 더 많은 작업을 수행하지만 작업의 종류 는 동일 하지만 복잡성은 크게 높지 않습니다 (이전 답변에 대한 의견의 토론 참조). 나는이 차이가 진입 점을 정적으로 만드는 결정을 설명하지 않는다고 생각하지 않는다. 특히 인스턴스 메소드의 해결을 위해 필요한 메소드가 존재하고 쉽게 사용할 수 있기 때문이다.
Konrad Rudolph

3
@ KonradRudolph : 내 요점은 JRE 가해 야 할 일에 관한 것이 아닙니다. 내 요점은 언어의 모든 사용자 가 필요에 따라 더 많은 계약을 따르도록하는 것입니다. 이러한 의미에서 static public main(String[])방법은 하나의 서명이므로 하나의 계약입니다. 그렇지 않으면 세 개의 독립적 인 계약을 따라야합니다.
AH

1
아 나는 여전히 이것이 차이가 있다는 것에 동의하지 않습니다. 진입 점 클래스는 잘 구현할 수 있습니다 Runnable. 분명히 Java는 개발자가 항상 계약을 따르기를 기대합니다. 왜 애플리케이션 진입 점에 비해 너무 많은가? 말이되지 않습니다.
Konrad Rudolph

3
@KonradRudolph : 모순이 없습니다. 어떤 경우에는 시스템이 사용자에게 세 번의 계약을 강제합니다. 모호한 계약은 컴파일러를 통해 확인할 수 없으며 사용자의 관점에서 독립적입니다. 평소에Thread 하고 Runnable경우 아무 것도 사용자로부터 숨겨, 그는 분명히에 가서 그가 구현하는 변화가 무엇을 볼 수 있습니다 그에 맞게 그 계약을 - 그는이 아닌 시스템, 제어에 있습니다.
AH

2
이것이 가장 좋은 대답입니다. 많은 사용자가 페이지에서 상위 2 ~ 3 개의 답변 만 읽는 것은 부끄러운 일입니다. 그리고 이것은 곧 갈 수 없을 것입니다. 초기화의 경우에만 생성자의 중요한 점을 언급하므로 생성자가 전체 응용 프로그램을 실행하는 스타일로 코딩하는 것은 의미가 없습니다.
Dawood ibn Kareem

14

그렇지 않은 경우 둘 이상이있는 경우 어떤 생성자를 사용해야합니까?

Java 언어 사양 에서 사용 가능한 Java 프로그램의 초기화 및 실행에 대한 자세한 정보가 있습니다 .


12

main 메소드가 호출되기 전에 오브젝트가 인스턴스화되지 않습니다. 정적 키워드를 사용하면 객체를 먼저 만들지 않고도 메서드를 호출 할 수 있습니다.


잘못된. 또는 적어도 매우 정확하지 않습니다. 공개 클래스 Main {정적 객체 object = new Object () {{System.out.println ( "object created"); }}; 공개 정적 무효 main (String [] args) {System.out.println ( "in main"); }}
eljenso

공정한 의견. 기술적으로 Main 메서드가 호출되기 전에 main 메서드가 포함 된 클래스가 인스턴스화되지 않았다고 말해야합니다.
BlackWasp 2016 년

12

그렇지 않으면 실행할 개체의 인스턴스가 필요합니다. 그러나 객체를 먼저 구성하지 않고 처음부터 호출해야합니다. 일반적으로 main () 함수 (부트 스트랩)의 작업이므로 인수를 구문 분석하고 일반적으로 이러한 인수 / 프로그램 매개 변수를 사용하여 객체를 구성합니다.


10

이러한 것들을 훨씬 간단한 방법으로 설명하겠습니다.

public static void main(String args[])

애플릿을 제외한 모든 Java 응용 프로그램은에서 시작합니다 main().

키워드 public는 클래스 외부에서 멤버를 호출 할 수있는 액세스 수정 자입니다.

staticmain()해당 클래스의 특정 인스턴스를 인스턴스화하지 않고도 호출 할 수 있기 때문에 사용 됩니다.

voidmain()값을 반환하지 않음을 나타냅니다 .


9

의 의미는 public static void main(String args[])무엇입니까?

  1. public JVM (Java Virtual Machine)과 같이 누구나 액세스 / 호출 할 수있는 액세스 지정자입니다.
  2. staticmain()클래스의 객체가 생성되기 전에 호출 할 수 있습니다. main()JVM은 오브젝트를 작성하기 전에 호출 하기 때문에 필요합니다. 정적이므로 클래스를 통해 직접 호출 할 수 있습니다.

    class demo {    
        private int length;
        private static int breadth;
        void output(){
            length=5;
            System.out.println(length);
        }
    
        static void staticOutput(){
            breadth=10; 
            System.out.println(breadth);
        }
    
        public static  void main(String args[]){
            demo d1=new demo();
            d1.output(); // Note here output() function is not static so here
            // we need to create object
            staticOutput(); // Note here staticOutput() function is  static so here
            // we needn't to create object Similar is the case with main
            /* Although:
            demo.staticOutput();  Works fine
            d1.staticOutput();  Works fine */
        }
    }

    마찬가지로, 우리는 객체를 만들 필요가 없도록 사용자 정의 메소드에 언젠가 정적을 사용합니다.

  3. voidmain()선언 된 메소드가 값을 리턴하지 않음을 나타냅니다 .

  4. String[] args메소드에서 유일한 매개 변수를 지정합니다 main().

    args-클래스 타입의 객체 배열을 포함하는 매개 변수 String.


6

다양한 종류의 애플릿, 미드 릿, 서블릿 및 빈이 생성 된 후 수명주기 메소드가 호출됩니다. main 호출은 main 클래스에서 수행되는 모든 작업이므로 여러 번 호출되는 객체에 상태를 유지할 필요가 없습니다. 클래스를 사용하여 주 객체를 만드는 방법에 방해가되는 다른 클래스에 main을 고정하는 것은 일반적입니다.


5

그것은 단지 컨벤션이지만 대안보다 더 편리 할 것입니다. 정적 기본을 사용하면 Java 프로그램을 호출하기 위해 알아야 할 모든 것은 클래스의 이름과 위치입니다. 정적이 아닌 경우 해당 클래스를 인스턴스화하는 방법을 알고 있거나 클래스에 빈 생성자가 있어야합니다.


컨벤션이 아닙니다. 언어 사양의 일부입니다. 런타임은 정적 기본 메소드가없는 클래스를 유효한 진입 점으로 인식하지 않습니다.
Rob

2
언어 사양 자체는 규칙을 따릅니다. Java 디자이너가 정적 메인을 요구하도록 실제로 요구할 필요는 없습니다. 그러나 Logan이 설명 하듯이 대안은 더 복잡합니다.
David Arno

@DavidArno이 규칙은 언어 사양을 따른다는 것이 더 합리적입니다.
Lorne의 후작

5

main 메소드가 정적이 아닌 경우 프로그램 외부에서 main 클래스의 오브젝트를 작성해야합니다. 어떻게 하시겠습니까?


5

java명령을 사용하여 JVM (Java Virtual Machine)을 실행하면

java ClassName argument1 argument2 ...

애플리케이션을 실행할 때 위와 같이 클래스 이름을 java 명령의 인수로 지정하십시오.

JVM이 지정한 클래스의 기본 메소드를 호출하려고 시도합니다.

—이 시점에서 클래스의 객체가 만들어지지 않았습니다.

선언 main 정적으로 allows에 JVM을 invoke주요 without만드는 instance클래스를.

명령으로 돌아 가자

ClassNamecommand-line argument실행할 클래스를 알려주는 JVM의 a 입니다. ClassName 다음에 list of StringsJVM이 애플리케이션에 전달할 명령 행 인수로 공백으로 구분하여 지정할 수도 있습니다 . 같으니 인수는 옵션 (예를 들어, 파일 이름)를 실행하기 위해이라는 매개 변수가 왜 응용 프로그램 - 지정하는 데 사용할 수있는 String[] args주에가

참조 : Java ™ 프로그래밍 방법 (초기 객체), 10 판


4

최근에 비슷한 질문이 Programmers.SE에 게시되었습니다.

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

    기본 소스 또는 보조 소스에서 결정적인 답변을 찾고 있는데 왜 Java와 C #이 Application클래스 의 인스턴스에 의해 애플리케이션 인스턴스를 나타내는 것이 아니라 시작점으로 정적 메소드를 사용하기로 결정했는지에 대한 이유는 무엇입니까? 적절한 생성자?

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 프로그래머에게 대안을 제공하는 것입니다 ...

...


3

키워드 'static'은 기본 메소드를 클래스 메소드로 만들고 클래스 메소드에는 사본이 하나만 있고 모두 공유 할 수 있으며 참조를 위해 객체가 필요하지 않다고 생각합니다. 따라서 드라이버 클래스가 컴파일되면 기본 메소드를 호출 할 수 있습니다. (나는 자바의 알파벳 수준에 있습니다. 잘못되면 미안합니다)


모든 방법에는 '복사본이 하나만 있습니다'.
Lorne의 후작

3

main ()은 정적이므로; 응용 프로그램 수명주기의 해당 시점에서 인스턴스화 된 객체가 없기 때문에 응용 프로그램 스택은 본질적으로 절차 적입니다.

깨끗한 슬레이트입니다. 객체가 선언되지 않아도이 시점에서 애플리케이션이 실행 중입니다 (절차 및 OO 코딩 패턴이 있음을 기억하십시오). 개발자는 객체의 인스턴스를 작성하고 컴파일 된 코드에 따라 애플리케이션을 객체 지향 솔루션으로 전환합니다.

객체 지향은 수백만의 명백한 이유로 훌륭합니다. 그러나 대부분의 VB 개발자가 코드에서 "goto"와 같은 키워드를 정기적으로 사용하던 시절은 지나갔습니다. "goto"는 VB의 절차 적 명령으로 OO 대응 : 메소드 호출로 대체됩니다.

정적 진입 점 (main)을 순수한 자유로 볼 수도 있습니다. Java가 객체를 인스턴스화하고 실행시 해당 인스턴스 만 제공 할만큼 충분히 다르면 절차 적 앱을 작성할 수있는 선택의 여지가 없습니다. Java에서 들리는 것처럼 상상할 수 없을만큼 절차 적 접근을 요구하는 많은 시나리오가있을 수 있습니다.

이것은 아마도 매우 모호한 답변 일 것입니다. "클래스"는 상호 관련 코드 모음 일뿐입니다. "인스턴스"는 해당 클래스의 고립되고 살아 숨쉬는 자율적 생성입니다.


7
이것은 올바르지 않습니다. main도달 하기 전에 많은 객체가 인스턴스화 됩니다. 그리고 main을 포함하는 클래스에 정적 생성자를 포함하면 이전과 main마찬가지로 실행 됩니다.
Konrad Rudolph

2

그것은 단지 협약입니다. JVM은 비 정적 주요 메소드를 처리 할 수 ​​있었을 것입니다. 결국, 클래스에서 정적 이니셜 라이저를 정의하고 main () 메소드에 도달하기 전에 중요한 객체를 인스턴스화 할 수 있습니다.


2

protoype public static void main(String[])JLS에 정의 된 규칙입니다 .

main 메소드는 public, static 및 void로 선언해야합니다. 선언 된 유형이 문자열 배열 인 공식 매개 변수 (§8.4.1)를 지정해야합니다.

JVM 사양 5.2. 가상 머신 스타트 업 :

Java 가상 머신은 부트 스트랩 클래스 로더 (§5.3.1)를 사용하여 구현 종속 방식으로 지정된 초기 클래스를 작성하여 시작합니다. 그런 다음 JVM (Java Virtual Machine)은 초기 클래스를 링크하고 초기화 한 후 공용 클래스 메소드 void main (String [])을 호출 합니다 . 이 메소드의 호출은 모든 추가 실행을 유도합니다. 기본 메소드를 구성하는 JVM (Java Virtual Machine) 명령어를 실행하면 추가 클래스 및 인터페이스의 링크 (및 결과적으로)가 발생하고 추가 메소드가 호출 될 수 있습니다.

재미있는 점은 JVM 사양에서 기본 메소드가 정적이어야한다는 언급은 없습니다. 그러나 스펙에 따르면 Java 가상 머신은 2 단계 전에 수행한다고합니다.

클래스 또는 인터페이스의 초기화는 클래스 또는 인터페이스 초기화 방법을 실행하는 것으로 구성됩니다.

2.9. 특별한 방법 :

클래스 또는 인터페이스 초기화 방법 정의한다 :

클래스 또는 인터페이스에는 최대 하나의 클래스 또는 인터페이스 초기화 방법이 있으며 해당 메서드를 호출하여 초기화 (§5.5)됩니다. 클래스 또는 인터페이스의 초기화 메소드는 특별한 이름을 가지고 있습니다<clinit> 인수를 사용하지 않으며 void입니다.

그리고 클래스 또는 인터페이스 초기화 방법은 다른 인스턴스 초기화 방법 다음과 같이 정의 :

Java 가상 머신 레벨에서 Java 프로그래밍 언어 (JLS §8.8)로 작성된 모든 생성자는 특수한 이름을 가진 인스턴스 초기화 메소드로 나타납니다 <init>.

따라서 JVM 은 실제로 생성자 인 인스턴스 초기화 메소드 가 아닌 클래스 또는 인터페이스 초기화 메소드 를 초기화 합니다. 따라서 메인 메소드를 호출하기 전에 인스턴스가 작성되지 않기 때문에 JVM 스펙에서 메인 메소드가 정적이어야 함을 언급 할 필요가 없습니다.


2

public키워드 프로그래머가 반원의 여부를 제어 할 수있는 액세스 개질제이다. 클래스 멤버 앞에 public가 있으면 해당 멤버는 선언 된 클래스 외부의 코드로 액세스 할 수 있습니다.

반대 publicIS private그 클래스 코드 정의 외부에서 사용되는 것을 방지 부재.

이 경우 프로그램이 시작될 때 클래스 외부의 코드에 의해 호출 main()되어야하므로로 선언 public되어야합니다.

키워드 staticmain()클래스의 특정 인스턴스를 인스턴스화하지 않고도 호출 할 수 있습니다. 이것은 main()오브젝트가 작성되기 전에 Java 인터프리터에 의해 호출 되므로 필요 합니다.

키워드는 void단순히 main()값을 반환하지 않는 컴파일러를 알려줍니다 .


1

모든 응용 프로그램의 진정한 진입 점은 정적 방법입니다. Java 언어가 "엔트리 포인트"로 인스턴스 메소드를 지원 한 경우 런타임은 객체의 인스턴스를 구성한 다음 인스턴스 메소드를 호출하는 정적 메소드로 내부적으로 구현해야합니다.

그런 식으로 다음 세 가지 옵션 중 하나를 선택하는 이유를 살펴 보겠습니다.

  1. static void main() 오늘 우리가 그것을 볼 수있다.
  2. 인스턴스 메소드 void main()새로 생성 된 객체에서 호출 입니다.
  3. 유형의 생성자를 진입 점으로 사용 (예 : 진입 클래스가 호출 된 Program경우 실행은 효과적으로 구성됨 new Program()).

고장:

static void main()

  1. 둘러싸는 클래스의 정적 생성자를 호출합니다.
  2. 정적 메서드를 호출합니다 main().

void main()

  1. 둘러싸는 클래스의 정적 생성자를 호출합니다.
  2. 효과적으로 호출하여 둘러싸는 클래스의 인스턴스를 구성합니다 new ClassName().
  3. 인스턴스 메소드를 호출합니다 main().

new ClassName()

  1. 둘러싸는 클래스의 정적 생성자를 호출합니다.
  2. 클래스의 인스턴스를 구성합니다 (그러면 아무것도하지 않고 단순히 반환합니다).

이론적 해석:

나는 이것에 대해 역순으로 갈 것이다.

Java의 디자인 목표 중 하나는 우수한 객체 지향 프로그래밍 방법을 강조하는 것입니다 (가능한 경우 필요). 이 컨텍스트에서 객체의 생성자는 객체를 초기화 하지만 객체의 동작에 책임을지지 않아야합니다. 따라서 진입 점을 부여한 사양은 new ClassName()모든 응용 프로그램에서 "이상적인"생성자의 디자인에 예외를 적용하여 새로운 Java 개발자의 상황을 혼동 할 수 있습니다.

함으로써 main()인스턴스 메소드를, 상기 문제는 확실히 해결된다. 그러나, 스펙이 엔트리 클래스 생성자의 서명과 main()메소드 의 서명을 나열하도록 요구함으로써 복잡성을 만듭니다 .

요약하면,를 지정하면 static void main()동작을 메소드에 배치하는 원칙을 준수하면서 복잡성이 가장 적은 스펙 이 작성됩니다 . main()자체적으로 클래스의 인스턴스를 구성하고 인스턴스 메소드를 호출하는 메소드 를 구현하는 것이 얼마나 간단한지를 고려 하면 인스턴스 메소드로 지정하는 main()것에는 실질적인 이점이 없습니다 .


1
이것은 단지 질문을 구걸하는 것입니다. Java는 어쨌든 호출하기 전에 많은 작업을 수행하는 애플리케이션 로더가 필요합니다 main. main초보자에게는 너무 복잡하다는 이론적 근거 는 믿을 수 없을 것 같습니다. 사실, 정적 main은 초보자 에게는 매우 혼란 스럽습니다. 생성자가 더 그렇습니다. 당신은“생성자가 물체의 행동에 책임을지지 않아야한다”고 말합니다. 이것은 흥미로운 것 같지만 동의하지 않을 것입니다. 왜 그렇지 않습니까? 이것을 막는 것은 무엇입니까?
Konrad Rudolph

1

static-JVM이 기본 메소드를 호출 할 때 호출중인 클래스에 존재하는 오브젝트가 없으므로 클래스에서 호출을 허용하려면 정적 메소드가 있어야합니다.


1

객체가 인스턴스화되기 전에 JVM이 기본 메소드를 호출하는지 모르겠습니다 ... 그러나 main () 메소드가 정적 인 훨씬 더 강력한 이유가 있습니다 ... JVM이 클래스의 메인 메소드를 호출 할 때 (예 : ). " Person.main () "으로 호출합니다 . JVM은 클래스 이름으로이를 호출합니다. 그래서 main () 메소드는 정적이며 공개되어 있어야 JVM에서 액세스 할 수 있습니다.

도움이 되었기를 바랍니다. 그렇다면 의견을 말하여 알려주십시오.


0

정적 메소드에는 객체가 필요하지 않습니다. 직접 실행되므로 메인이 직접 실행됩니다.


0

main 메소드에서 발생하는 인스턴스화가 없기 때문에 main 메소드의 정적 키워드가 사용됩니다. 그러나 우리는 main 메소드에서 정적 키워드를 사용하므로 호출이 아닌 객체가 생성됩니다. jvm 컨텍스트에서 클래스가로드 될 때 메모리가 생성되고 모든 정적 멤버가 해당 메모리에 존재합니다. 메인을 정적으로 만들면 메모리에 있고 jvm (class.main (..))에 액세스 할 수 있으므로 힙을 만들 필요없이 메인 메소드를 호출 할 수 있습니다.


0

우리가 여기서 볼 수있는 것은 단지 관습입니다.

이 메소드 는 public 및 static으로 선언되어야하며 값을 리턴하지 않아야하며 문자열 배열을 매개 변수로 승인해야합니다. 기본적으로 옵션이 아닌 첫 번째 인수는 호출 할 클래스의 이름입니다. 정규화 된 클래스 이름을 사용해야합니다. -jar 옵션이 지정된 경우 옵션이 아닌 첫 번째 인수는 시작 클래스가 Main-Class Manifest 헤더로 표시되는 응용 프로그램의 클래스 및 자원 파일을 포함하는 JAR 아카이브의 이름입니다.

http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/java.html#description


언어의 규칙, 당신은 의미합니다.
Lorne의 후작

0

public static void 키워드는 JVM (Java Virtual Machine) 인터프리터가 클래스의 인스턴스 (정적)를 작성하지 않고 프로그램의 기본 메소드를 호출하여 프로그램 (공용)을 시작할 수 있으며 프로그램이 Java VM 인터프리터에 데이터를 리턴하지 않음을 의미합니다. 끝날 때 (void).

출처 : 기초, 1 부, 학습 2 : 응용 프로그램 빌드


0

기본적으로 우리는 DATA MEMBERS와 MEMBER FUNCTIONS를 STATIC으로 만들어 객체와 관련된 작업을 수행하지 않습니다. 그리고 main 메소드의 경우 main 메소드가 항상 오브젝트를 작성하는지 여부에 관계없이 실행되므로 오브젝트와 관련이 없기 때문에 정적 상태로 만듭니다.


0

Java에서 static으로 선언 된 모든 메소드는 클래스 자체에 속합니다. 특정 클래스의 정적 메소드는 다음과 같은 클래스를 참조해야만 액세스 할 수 있습니다Class_name.method_name();

따라서 정적 메서드에 액세스하기 전에 클래스를 인스턴스화 할 필요가 없습니다.

따라서 main () 메소드는 static해당 클래스의 오브젝트를 작성하지 않고 액세스 할 수 있도록 선언됩니다 .

우리는 main 메소드가 존재하는 클래스의 이름으로 프로그램을 저장하기 때문에 (또는 프로그램이 실행을 시작해야하는 곳에서 main()method () (Advanced Level)이 없는 클래스에 적용 가능 ) 위에서 언급 한 방식으로 :

Class_name.method_name();

주요 방법에 액세스 할 수 있습니다.

간단히 말해서 프로그램이 컴파일 될 때 언급 된 클래스 (예 : 프로그램 이름)에서 다음 과 같은 인수를 main()갖는 메소드를 검색 합니다. 처음에는 해당 클래스를 인스턴스화 할 범위가 없으므로 main () 메소드는 정적로 선언됩니다.Stringmain(String args[])


컴파일되지 않고 프로그램이 실행될 때 발생합니다.
Lorne의 후작

0

에서 java.sun.com (사이트에 대한 자세한 내용이있다)

기본 메소드는 Java VM 인터프리터에게 제어 클래스의 인스턴스를 먼저 작성하지 않고 클래스를 시작할 수있는 방법을 제공하기 위해 정적입니다. 제어 클래스의 인스턴스는 프로그램이 시작된 후 기본 메소드에서 작성됩니다.

필자는 항상 정적 메서드와 마찬가지로 기본 클래스를 관련 클래스의 인스턴스를 만들지 않고 호출하여 프로그램의 다른 것보다 먼저 실행할 수 있다는 것을 이해했습니다. 정적이 아닌 경우 객체를 호출하기 전에 객체를 인스턴스화해야합니다. 주된 방법은 일반적으로 프로그램 시작시 객체를 인스턴스화하는 데 사용되므로 '치킨 앤 에그'문제가 발생합니다.


그러나 "프로그램의 다른 것보다 먼저"실행 되지 않습니다 . 전체 논쟁은 오해이며, 더 나아가 이것은 이것을 언급하는 첫 번째 대답이 아니며 두 번째 또는 세 번째조차 아닙니다.
Konrad Rudolph

내 대답이 다른 사람들의 말을 되풀이하여 죄송합니다. 나는 내가 이해 한 내용과 온라인에서 찾을 수있는 내용에 대해서만 대답했습니다. 내가 본 결과에서 main 메소드가 정적 인 이유에 대한 다른 이유는 없습니다. 어딘가에 깊이 숨겨져 있지 않은 한 그것이 유일한 대답 일 것입니다. Java에 대한 나의 이해는 상당히 기본적이지만 위의 이유 (교수, 교과서 등)를 들어 본 적이 없습니다.
Jesse M

@Jesse M 다른 답변을 먼저 읽는 것을 고려하지 않은 경우에만 의견이 의미가 있습니다. 그건 그렇고 멀리 할 일이 아닙니다. 당신이 자신을 언급했듯이, 당신의 이해는 상당히 기본적이므로 다른 누군가가 이미 그 질문에 더 유능하게 대답했을 가능성이 매우 높습니다. 그리고 귀하의 의견은 귀하의 답변이 더 좋아 보이도록 합리화 된 것 같습니다. 그것은 당신이 주장하는 것을 생각하고 솔직히 나는 그것을 믿지 않는 Java 교과서와 교수가 있다는 놀라운 주장입니다. (모든 참조?)
LeoR

1
@KonradRudolph 최고 의견은 꽤 합리적입니다. main ()은 프로그램의 시작점으로 사용되며 Java 웹 사이트에는 C / C ++에 main () 함수가있는 방법과 비슷하다고 가정하는 몇 가지 참조가 있습니다. Java는 모든 객체이므로 객체 인스턴스화를 피하려면 정적이어야합니다. 정적 상태를 유지하면 런타임에 JVM으로로드 및 실행 가능합니다. 나는 단지 이전 답변을 되풀이하고 있지만 만족스러운 답변을 무엇으로 생각할 지 궁금합니다. 나는 당신이 얻을 수있는 최선의 방법은 "그들이 원하는 방식"이라고 생각합니다. Java가 작성된 날짜를 명심하십시오.
trevor-e

1
@Jesse Spot-on. 그것은 단지 협약의 문제 일 수 있습니다. (그렇지는 않지만 그렇게 지루한 대답이되기를 바랍니다). 이 질문에 대한 나의 원래 관심은 Java를 사용하기 때문에 "실행중인 응용 프로그램"객체를 나타내는 적절한 인스턴스를 사용하고 진입 점을이 클래스의 메서드 (또는 생성자)로 만드는 것이 훨씬 더 명백한 디자인이라고 생각했기 때문입니다. 가져 오기 - 이동에서 객체 지향 할 수 있도록 설계하고, 겉보기에 비슷한 객체 (스레드를 통해 이후되었다 Runnable자바에서) 이 디자인을 사용합니다. 왜 (명백한) 예외가 있습니까?
Konrad Rudolph
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.