[JAVA] 메인 메소드 public static void main(String[] args) 알아보기

skyepodium·2021년 4월 13일
7
post-thumbnail

자바 개발할 때 잘 몰라가지고,
파라미터가 없는데... String[] args 안쓰면 안되나요.

  • String[] args
  • 엔트리포인트
  • public, static
  • JNI
  • 여담

1. String[] args

public class Main {
	public static void main (String args[]) {
		System.out.println("Hi");
	}
}

1) 의미

String 객체로 정의된 args 라는 이름의 배열로 파라미터를 받겠습니다. 라는 의미입니다.

2) 배열

배열을 선언했기 때문에 java에서 배열을 선언하는 다음 3가지의 방식 모두 가능합니다.

String[] args
String args[]
String... args

그리고 args는 파라미터의 이름이기 때문에 다른 이름을 사용하셔도 괜찮습니다.

제가 정의한 blingbling 이름으로도 잘 동작합니다.

String[] blingbling
String blingbling[]
String... blingbling

3) 파라미터 어떻게 쓰는건데

메인 메소드의 파라미터는 커맨드를 통해 입력 받습니다.

다음과 같이 작성하고,

public class Main {
	// 1. args 라는 String 배열로 파라미터를 받습니다.
	public static void main (String args[]) {

		// 2. 배열의 길이를 출력합니다.
		System.out.println("배열의 길이 " + args.length);

               // 3. 반복문을 통해받은 내용을 순회하며 출력합니다. 
		for(String arg: args) {
			System.out.println(arg);
		}

	}
}
// javac 컴파일러로 Main.java 컴파일 -> Main.class 파일 생성
javac Main.java -encoding utf-8

// Main.class 파일 실행
java Main

커맨드로 Main.class 파일을 실행하면서 인자값을 전달하면

다음과 같이 공백으로 분리해서, 받은 문자열 출력합니다.

4) 파라미터...난 필요없는데

사실.. 나는요 커맨드로 자바 파일 실행하는일 거의 없고,
실행해도 인자값 전달할 일도 거의 없는데...

String[] args 안쓰면 안되나요.

결론은 안됩니다. 꼭 String 배열을 파라미터로 받아야합니다.

만약 안쓴다면, 컴파일은 가능하지만, 엔트리 포인트가 없어 실행할 수 없는 상태가 됩니다.

5) 없으면 외않되!

javaSE16 버전의 공식 문서를 보면

JVM(런처)의 엔트리 포인트로 단 1개의 메인 메서드만 허용됨을 알 수 있습니다.

... 그래서, 엔트리 포인트는 또 뭔데

2. 엔트리 포인트

1) 정의

엔트리 포인트(Entry Point)란 프로그램이 시작되는 시작점을 의미합니다.

2) main

다수의 프로그래밍 언어에서 main 함수가 엔트리 포인트로 사용됩니다.(예: c, c++, java 등)

다만, 스크립트 언어의 경우 정해진 엔트리 포인트는 main 함수가 아닌 인터프리터가 코드를 읽기 시작한 부분부터 진행됩니다.(예: python, javascript 등)

3) java의 엔트리 포인트

java의 경우 API 에서는 public static void main (String[] args)단 한개만 엔트리 포인트로 정의했기 때문에,

오버로딩 된 다른 형태의 main함수는 엔트리 포인트로 동작하지 않습니다.

public class Main {
	// 1. 유일하게 엔트리 포인트로 동작합니다.
	public static void main (String[] args) {
		System.out.println("main 메소드 - String[] args");
	}

	// 2. main 메소드 오버로딩
	public static void main (Integer num) {
		System.out.println("main 메소드 - Integer num");
	}

	// 2. main 메소드 오버로딩
	public static char main(char c) {
		System.out.println("main 메소드 - char c");

		return 'c';
	}
}

4) c++의 엔트리 포인트

c++ 에서는 기본적으로 다음 2가지를 제공합니다.

// 1) 파라미터가 없는 형태
int main()

// 2) 파라미터의 개수와, 파라미터를 인자값을 받습니다.
int main(int argc, char** arg)

다만, 오버로딩이 할 수 없습니다.

다음과 같이 실행할 수 있습니다.

#include <iostream>

using namespace std;

int main(int argc, char** argv) {

	// 1. 파라미터의 개수를 출력합니다.
	cout << "파라미터의 개수 " << argc << endl;

	// 2. 파라미터로 받은 문자열을 공백으로 분리해서 출력합니다.
	for (int i = 0; i < argc; i++) {
		cout << argv[i] << endl;
	}
}

3. public, static

왜 public, static 키워드가 있어야하는지 알아봅시다.

1) static

static 메서드는 객체를 생성하지 않고도 호출 할 수 있다는 특징이 있습니다. (객체를 생성하고 static 메서드를 호출할 수는 있지만, 좋지는 않습니다.)

만약, static이 없어서 메인 메서드의 객체를 만들어야한다면, 생성자 때문에 조금 까다로울 수 있습니다.

왜냐하면, 다음과 같이 메인 메서드가 포함된 클래스의 생성자에 제대로된 인자값을 넣어주지 못한다면, 객체 만드는것에 실패하고 메인 메서드를 호출하지 못하기 때문입니다.

(사용자가 생성자로 어떤 인자값을 받을지에 대해서는 JVM은 모르기 때문이빈다.)

class Main {

    String name;

    public Main (String name) {
        this.name = name;
    }

    static public void main(String[] args) {
        // 객체를 만들어줍니다.
        Main ma = new Main("blinglbing");
        System.out.println(ma.name);

        // 생성자에 제대로 인자값을 넣어주지 않으면, 에러가 발생합니다.
        // Main ma2 = new Main();
    }
}

2) public

public 은 접근 제어자 이고, public이 인 메서드는 다른 클래스의 메서드에서 접근이 가능합니다.

자바는 클래스 기반 언어이고, JVM에서 엔트리포인트인 메인 메서드에 어느 곳에서든 자유롭게 접근하기 위해 public이 되어야합니다.

3) 순서

public, static 서로의 순서는 바꿔도 상관은 없습니다.

public static void main(String[] args)
static public void main(String[] args)

아래 부터는 왜 컴파일 때는 에러 안만들고, 실행할 때 에러를 발생시키는지, JVM에서 public static 을 어떻게 검사하는지 알아보다가...openJDK 열어 본 후기입니다.

4. JNI (Java Native Interface)

위키백과 정의
에 따르면 JNI는 자바 가상 머신 (JVM) 위에 실행되고 있는 자바 코드를 C, C++ 그리고 어샘블리 같은 다른 언어들로 작성된 라이브러리들이 호출하거나 반대로 호출하는 것을 의미한다.

커맨드로 자바 클래스를 호출한것은 JNI를 통해 자바 코드를 호출한것에 해당한다.

java Main

JDK는 자바 개발 환경이고, 컴파일 등이 담겨있고
JRE는 자바 실행환경이고 자바가 실행될 수 있도록 지원하고
JVM는 자바 코드가 실행되는 가상머신이다.

JDK 에는 JRE, JVM이 들어있다.

그래서... openJDK를 까봤다.

5. openJDK

openJDK 깃허브 에서 받았다.

1) LoadMainClass

여겨까지 오는것도 조금 길긴한데 여기서 부터라고 보면 java.c 파일의 LoadMainClass 함수를 호출하면서 시작이다.

직역하면, 애플리케이션의 메인 클래스를 가져옵니다. 또한, 메인 메소드가 존재하는지 검사합니다.

밑에 적힌 주석 또한 보면,

LoadMainClass 는 메인 클래스를 가져올 뿐만 아니라 메인 메소드의 시그니쳐가 정확한지 보증합니다. 그렇기 때문에 더 이상의 검사는 필요하지 않습니다.

GetStaticMethodID 함수를 호출하면서,

JNI 함수인 GetStaticMethodID 을 호출하면서, checkAndLoadMain 함수를 호출한다.

2) LauncherHelper.java

LauncherHelper.java의 checkAndLoadMain 메소드로 오고, 그 아래 validateMainClass 을 호출한다.

3) validateMainClass

NoSuchMethodException 익센셥에 걸리면 java.launcher.cls.error4 을 호출하고

java.launcher.cls.error4 는 public static void main(String[] args) 메인 메소드가 없는 클래스를 실행했을때 보여주는 에러메시지다.

여담

1) 대문자

혹시, 나 처럼 생각한 사람 있을까봐.. 아마 없겠지만
public static void main (String[] args) 에서 왜 String 만 대문자인거지..

java에서 String은 원래 클래스이고 자바에서 기본 클래스의 이름은 대문자로 시작합니다. (예: Integer, Main 등등)

사용자가 생성하는 클래스의 이름은 대문자로 시작하는게 권장 사항이지만, 대문자로 시작하지 않아도 생성할 수 있습니다.

2) 클래스

클래스라면 객체를 생성할 때 다음과 같이 생성하는게 맞지만

String mode = new String("blingbling");

문자열에 대해서는 예외적으로 다음과 같은 표현이 가능합니다.

String mode = "blinbling";
profile
callmeskye

1개의 댓글

comment-user-thumbnail
2022년 4월 1일

제가 봤던 java 메인 메소드 관련 설명 중에 가장 자세했어요. 감사합니다.

답글 달기