public class Practice {
public static void main(String[] args) {
// 코드를 입력하세요.
}
}
자바를 처음 익히는 날부터 주구장창 치게 되는 코드가 있다.
바로 모든 실행클래스에서 절대 빠질 수 없는 코드, public static void main(String[] args) {} 다.
처음 언어를 배우면 책과 강사를 막론하고 이렇게 말한다. "일단 보고 따라 치세요."
하지만 누구든 한 번쯤은 궁금증을 가졌을 것이다. 저게 뭔데 저렇게 긴걸 꼭 따라쳐야해?
1. 접근제한자 public
접근제한자는 말 그대로 접근을 제한하기 위한 키워드이다. 번거롭게 왜 접근을 제한해둘까?
예를 들어 은행에서 계좌의 비밀번호를 저장해두었다고 생각해보자. 이때 누구나 비밀번호에 접근할 수 있다면 보안에 큰 문제가 생길 것이다. 아무나 남의 계좌의 비밀번호에 접근해서 변경할 수 있을테니 말이다. 그렇기 때문에 접근을 제한해야할 필요가 있다.
이러한 접근 제한자 (Access Modifier) 는 접근이 가능한 범위에 따라 다음과 같이 분류할 수 있다.
public | protected | (default) | private | |
외부 클래스 | O | X | X | X |
자식 클래스 | O | O | X | X |
동일 패키지 | O | O | O | X |
동일 클래스 | O | O | O | O |
(default는 엄밀히 말해서 접근 제한자가 아니다. 아무런 접근 제한자가 붙지 않은 상태를 말하는 것이지만, 설명의 편의를 위해 포험시켜 두었다.)
그렇다면 왜 main() 메소드는 public으로 선언되었을까? 바로 JVM(Java Virtual Machine)이 실행될 때 클래스의 main() 메소드를 호출하여 실행을 시작하기 때문이다. 만약 main() 메소드가 (default)로 선언된다면 JVM은 이 메소드에 접근할 수 없으므로 프로그램이 실행되지 않는다.
2. static 키워드 (참고 - 2023.09.06 - [Java] - [Java] Math과 Random의 비교로 살펴보는 static의 역할)
static의 역할에 대해서는 지난 포스팅에서 설명하였으니 간단하게만 짚고 넘어가고자 한다.
class Person{
// 정적 멤버 선언
static void starve() {
System.out.println("굶습니다.");
}
// 인스턴스 멤버 선언
void eat() {
System.out.println("밥을 먹습니다.");
}
public static void main(String[] args) {
// 정적 멤버 호출 - 객체 생성이 필요 없음
person.starve();
// 인스턴스 멤버 호출 - 객체 생성이 필요함
Person p1 = new Person();
p1.eat();
}
}
정적 멤버 (static member) | 1. static 키워드를 붙여서 선언 2. 객체를 생성하지 않고도 클래스를 통해 호출 가능 |
인스턴스 멤버 (instance member) | 객체를 생성 후 멤버 호출 |
main() 메소드의 경우 static이 붙어있으므로 정적 메소드라는 것을 알 수 있다. 그렇기 때문에 main() 메소드는 해당 클래스의 인스턴스를 생성하지 않고도 바로 실행될 수 있다.
3. 리턴타입 void
리턴 타입은 해당 메소드가 실행된 후에 메소드를 호출한 곳으로 어떤 타입의 결과값을 돌려줄지를 명시해 두는 것이다.
정수형을 리턴한다면 int, 문자형이라면 char, 문자열이라면 String 등등 다양한 타입이 있다. 만약 리턴 값이 없다면 void로 리턴 이 없음을 알려주어야한다.
왜 main()메소드의 리턴타입은 void일까? main() 메소드가 종료되면 자바 프로그램도 종료된다. 그렇기 때문에 main() 메소드를 호출한 JVM에게 값을 반환하더라도 JVM은 그 값으로 아무것도 할 수가 없다. 즉 반환 자체가 무의미하기 때문에 void로 선언된다.
4. 왜 메소드의 이름은 main일까?
간단하다. 약속이다.
사실 프로그램의 진입점으로서 main이라는 이름을 사용하기 시작한 것은 자바가 처음이 아니다. 거슬러 올라가자면 C++이, C가, 그 위 B까지도 main()이라는 이름을 사용했다. 자바는 그저 조상의 영향을 받았을 것이다.
5. (String[] args) 의 정체
일단 String[] args는 main 함수의 파라미터로서 문자열 배열을 받겠다는 뜻이고, 이 배열을 args라고 부른다는 뜻이다.
다른 메소드같이 이 파라미터를 이용해서 코드를 짜는 것도 가능하다.
public class Practice {
public static void main(String[] args) {
for(int i = 0; i < args.length; i++) {
System.out.println(args[i])
}
}
}
그러면 이 파라미터는 어떻게 전달받는 걸까?
우선은 클래스를 실행할 때 기본적으로 JVM은 길이가 0인 String배열을 생성한 다음에 해당 배열을 매개값으로 전달한다.

또, 빈 배열이 아니라 특정 값을 전달하는 것도 가능하다.
cmd를 이용할 때는 클래스파일을 실행할 때 문자열로 파라미터를 입력하면 된다.
그렇다면 왜 다른 타입 다 냅두고 String[] 일까? main() 함수는 cmd나 shell에서 호출된다. 그런데 이때 cmd에서 입력되는 것은 기본적으로 String타입이다. 즉, 내가 123을 쓰든 Hello를 쓰든 타입은 String이 된다. 그렇기 때문에 String[]을 파라미터의 타입으로 명시하고 있는 것이다.
args는 우리가 유일하게 main()메소드 선언부에서 바꿀 수 있는 부분이다. args가 아니라 a라 하든 abc라고 하든 다 실행된다. 하지만바꾸는 것은 다른 개발자에게 불편을 끼칠 수 있으니 굳이 그러지 말자.
+첨언) 괜시리 호기심이 생겼다. 정말 꼭 저대로 적어야만 실행될까?

args를 제외하고는 바꾸게 될 경우 컴파일은 되지만 실행은 되지 않는다
'Backend' 카테고리의 다른 글
[알고리즘] 알고리즘 성능을 분석하는 상환 분석 (Amortized Analysis) (2) | 2023.11.22 |
---|---|
[Java] 추상클래스와 인터페이스의 비교 (2) | 2023.10.17 |
[Java] 연속된 부분 배열의 최대 합 구하기 (2) | 2023.10.08 |
[Java] 자식클래스 생성자에서 super()의 필요성 (2) | 2023.09.13 |
[Java] Math과 Random의 비교로 살펴보는 static의 역할 (0) | 2023.09.06 |