[컬러잇자바] #6. 왜 main 메서드를 사용할까?

2026. 2. 2. 23:39·Language/ColorIt_Java

※[컬러잇 자바] 시리즈는 "왜?"라는 질문을 중심으로 자바의 기초문법에서 고급 자바기술까지 알아보는 컬러잇 개발블로그 시리즈입니다.

 

컬러잇 자바시리즈 6편. 이전까지 우리는 클래스에 대해 다루고, 클래스와 변수에 대해서 배우고, 그리고 생성자를 통해 객체를 생성하는 이유와 방법에 대해서 알아보았습니다. 이번에는 실제로 자바 코드를 실행시켜보기 위해, 그 기본이 되는 "main"이라는 메서드와 그 메인 메서드를 이루고 있는 요소들에 대해서 알아보겠습니다.


태초마을

이제 여러분은 실제로 클래스와 객체에 대해서 배워봤습니다. 이제는 실제로 자바를 실행시켜서, 객체를 불러오고, 객체의 요소에 직접 접근해볼 수 있습니다.

public class Main{
    public static void main(String[] args){

    }
}

갓 생성된 자바파일을 열어보면 이런 구조를 가지고 있습니다. 여기서 중요한 것이 바로 main이라는 메서드입니다.

 

자바는 객체로 이루어졌다고 했습니다. 따라서 "자바 프로그램을 실행시키는 행동" 역시 객체의 메서드가 담당합니다. 그리고 그 메서드를 main이라는 메서드에서 담당하고 있죠. 따라서 자바 코드를 실행하면 가장 먼저 불러와지는 것이 이 main이라는 메서드입니다. 여기서 자바의 모든 것이 시작됩니다.

 

이번시간에는 직접 간단한 자바 프로그램을 실행해보기 전, 이 main 메서드와 관련된 내용들을 알아보겠습니다.


접근제어자

메서드 선언부에 보면 public이라는 키워드가 있습니다.

이전에 자바는 한 객체가 다른 객체의 메서드나 변수에 접근하며 프로그램이 진행된다고 했는데, 접근제어자를 사용하면 자신에게 접근할 수 있는 객체의 범위를 정할 수 있습니다.

 

또한 접근제어자는 메서드, 변수 뿐 아니라 생성자, 클래스에까지도 적용이 가능합니다. 즉, 변수, 메서드, 생성자, 클래스가 자기자신에게 접근할 수 있는 객체를 접근제어자를 통해 제어할 수 있다는 뜻입니다.

 

접근제어자의 종류는 몇 가지가 있는데, 모든 종류는 상속과 패키지라는 캐념을 알아야 자세히 알 수 있으므로 우선은 아래 두 가지만 알면됩니다.

 

public

아무 객체나 접근할 수 있습니다.

 

private

그 어느 객체도 접근할 수 없습니다. 오로지 클래스 내부에서만 접근이 가능합니다

class Dog {
    public int age;
    private String name;

    public Dog() {
        age = 3;
        name = "멍멍이";
    }
}
class Person {
    public Dog dog = new Dog();
    public int dogAge;
    public String dogName;

    public void setAge(){
        dogAge = dog.age;
        dog.age = dog.age + 3;
    }

    public void setName() {
        dogName = dog.name;      //에러! 접근제어자가 private로 설정되어 접근할 수 없습니다.
        dog.name = "초코";       //에러! 접근제어자가 private로 설정되어 접근할 수 없습니다.
    }
}

늘 등장하는 개와 개 주인 예시에서 public으로 접근제어자가 설정된 Dog 객체의 age 변수와 생성자는 자유로운 접근이 가능합니다.

 

반면, 접근제어자가 private로 설정된 Dog 객체의 name 변수는 Person 객체, 그러니까 Dog 객체의 외부에서 접근하려하면 에러가 발생합니다.


정보를 숨기자

그렇다면 이 접근제어자를 왜 사용할까요?

 

만약 모든 변수, 메서드들이 public으로 설정되어있다고하면 문제가 발생할 수 있습니다.

예를 들어보면, Person 클래스에서 각 객체를 제대로 식별하기 위해서 주민번호를 내부 변수로 사용했다고 가정해봅시다.

 

class Person {
    public int number; //주민번호
}

만약 주민번호를 public으로 사용했다면, 누구나 해당 사람의 주민번호에 접근할 수 있습니다. 심지어는 주민번호를 모두 000000-0000000 으로 바꿔버릴 수도 있죠. 누구에게나 열려있는 변수인 셈입니다.

 

해커들은 Person 객체에 접근해 number 변수에 접근하는 코드를 심는 것은 일도 아니기 때문에 엄청난 보안문제가 될 것입니다.

 

class Person {
    private int number; //주민번호
}

반면 private 접근제어자를 사용하면, 외부에서는 해당 Person 객체의 number 변수에 접근할 수 없습니다. 접근하면 오류가 발생하죠. 즉, 외부에서 Person 객체를 찾아서 number 변수를 빼낼 수 없게됩니다.

 

이렇게 자바는 되도록이면 private 접근제어자를 사용해서 객체가 담고 있는 상태나 정보를 숨기는 것을 선호합니다. 자바 프로그래밍 시 유의할 점들을 다룬 <이펙티브 자바>라는 책은 아예 "public 접근제어자를 꼭 필요한 경우를 제외하고는 사용하지 말아라"라고 권고합니다.


게터와 세터

접근제어자를 private로 선언하는 것은 좋습니다. 하지만 외부에서 정보를 요구하면 어떻게 해야할까요? 예를들어, 주민번호를 입력받았다면 이 주민번호가 Person 객체의 주민번호와 맞는지 알아보아야합니다.

class Person {
    private int number; //주민번호

    public int getNumber() {
        return number;
    }
}

이럴 때에는 변수를 private로 선언하고, "private로 선언된 변수의 값을 알려주는 메서드"를 public으로 선언할 수 있습니다. 즉, 변수의 값을 알기 위해 변수에 직접 접근하는게 아니라 메서드를 통해 간접적으로 접근하는 것이죠.

 

이렇게되면 변수를 마치 public인 것처럼 사용할 수 있으면서도 정보를 은닉할 수 있는 이점이 있습니다.

 

반대로, 새로 사람이 가입해서 Person 객체가 생성되고, 주민번호를 입력해주어야한다면 어떡할까요?

class Person {
    private int number; //주민번호

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }
}

이럴 때에는 "private로 선언된 변수의 값을 설정할 수 있는 메서드"를 public으로 선언할 수 있습니다. 즉, 변수의 값을 직접 수정하는게 아니라 메서드의 매개변수에 값을 넘겨주어 간접적으로 값을 수정할 수 있는 것이죠.

 

값을 설정할 때 메서드를 사용하는 것과 사용하지 않는 것에는 어떤 차이가 있을까요?

기존에 변수의 접근제어자를 public으로 선언했을 때에는 외부에서 해당변수의 값을 변경하려하면 넋 놓고 바라보아야했습니다. 앞서 말했듯이 주민번호를 000000-0000000 으로 바꿔버려도 막을 수 없었죠.

 

하지만 이번에는 수정권한이 외부가 아니라 개발자가 설계한 메서드로 넘어왔습니다. 기존에는 외부에서 "내가 ~~로 값을 설정할거야"라고 했다면, 이제는 외부에서 메서드에게 "~~로 값을 변경해주세요"하고 값을 넘깁니다. 따라서 개발자는 변경하려는 값에 이상이 있는지 여부를 확인하고 값을 바꿀 수 있게됩니다.

 

이렇게 자바에서는 외부로 노출되는 변수를 최대한 줄이고 값을 제공하는 메서드와 값을 수정할 수 있는 메서드를 제공하는 것이 좋습니다. 이를 캡슐화라고 하죠. 그리고 값을 제공하는 메서드를 게터(getter), 값을 수정할 수 있는 메서드를 세터(setter)라고합니다.


정적멤버

정적변수

다시 메인메서드로 돌아와보면, static이라는 키워드가 있습니다. 이는 무엇일까요?

 

class Dog {
    int age;
    String name;
    String animal;
    
    public Dog() {
        age = 3;
        name = "멍멍이";
        animal = "개";
    }
}
class Cat {
    int age;
    String name;
    String animal;
    
    public Cat() {
        age = 3;
        name = "야옹이";
        animal = "고양이";
    }
}

기존 Dog 클래스에 이어서, 이번에는 Cat 클래스를 만들었습니다. 그리고 두 클래스를 구분하기 위해서 개인지 고양이인지 구분할 수 있는 animal이라는 변수를 만들었습니다.

 

여기서 모든 개 객체는 animal 값이 "개"일 것이고, 고양이 객체는 모든 animal 값이 "고양이"입니다. 하지만 위와 같이 설계하면 animal 변수가 같은 개 객체 사이에서도 달라질 수 있습니다.

어떤 개 객체는 animal 변수의 값이 "개"이지만, 가끔 이런 설정이 흐트러지거나 악성사용자에 의해서 animal 값이 Dog 객체임에도 불구하고 "고양이"라는 값을 가질 수 있습니다.

 

3살 뽀삐 강아지가 야옹이라고 울 수 없듯이, 모든 개 객체에는 하나의 통일된 animal 변수를 가져야합니다. 이는 만약 어디선가 개 객체에 접근해 animal 변수의 값을 변경시키면, 모든 개 객체의 animal 변수의 값이 변합니다.

 

즉, 정적변수란 같은 클래스라면 모든 객체가 똑같은 값을 가지는 변수입니다.

class Dog {
    int age;
    String name;
    static String animal = "개";

    public Dog() {
        age = 3;
        name = "멍멍이";
    }
}

정적변수는 static이라는 키워드를 사용합니다. 이 키워드를 사용하면 같은 클래스의 모든 객체들이 통일된 값을 가진다는 뜻입니다.

 

따라서 3살 뽀삐, 8살 멍멍이, 10살 바둑이 모두 animal 벼수가 "개"가 되는 것입니다.

class Dog {
    int age;
    String name;
    static final String animal = "개";

    public Dog() {
        age = 3;
        name = "멍멍이";
    }
}

다만 일반적으로 animal 변수가 변할 일은 없기 때문에, final이라는 키워드를 사용해 해당 값이 변경되지 않도록 막을 수 있습니다. 즉, static과 final로 선언하면 같은 클래스라면 모든 객체가 통일된 값을 가지고, 변경은 불허하는 셈이지요.

 

static final int age = 21;
final static int age2 = 22;

중요한 것은 final로 변수를 선언한 경우, 선언 이후에는 절대로 값을 수정할 수 없습니다. 따라서 선언과 대입을 동시에 해주어야합니다. 그리고 final과 static에는 순서가 굳이 필요하지 않습니다.


정적메서드

메서드 역시 정적으로 설정할 수 있습니다. 역시 메서드 선언부에 static 키워드를 사용하면 됩니다.

class Dog {
    int age;
    String name;
    static String animal = "개";

    public Dog() {
        age = 3;
        name = "멍멍이";
    }

    public static boolean isDog(){
        return true;
    }
}

때로는 굳이 자기자신이 속한 객체의 변수가 필요하지 않는, 단순한 기능을 제공하는 경우가 있습니다. 만약 개 객체라면, 해당 객체가 Dog 객체인지 여부를 알려주는 기능이 이에 속하겠네요.

 

이럴 때에는 정적메서드를 사용할 수 있습니다.

정적메서드는 정적변수와 달리 모든 클래스마다 같은 값을 공유한다는 특징이 잘 와닿지 않습니다. 메서드는 같은 클래스라면 객체마다 같은 값을 가지니까요. 그렇다면 정적메서드와 함께, 정적변수의 특징까지 알아보도록 하겠습니다.


정적멤버의 특징

class Dog {
    int age;
    String name;
    static String animal = "개";

    public Dog() {
        age = 3;
        name = "멍멍이";
    }

    public static boolean isDog(){
        return true;
    }
}
class Person {
    String animal = Dog.animal;    //개
    boolean isDog = Dog.isDog();  //true
}

정적메서드와 정적변수를 포함한 정적멤버의 특징 중 하나는 객체의 생성없이 즉시 사용할 수 있다라는 것입니다. 엄밀히 말하자면 반드시 객체의 생성없이 (클래스명).(정적멤버명)으로 접근해야한다는 것입니다.

 

class Dog {
    int age;
    String name;
    static String animal = "개";

    public Dog() {
        age = 3;
        name = "멍멍이";
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static boolean isDog(){
        age = 33;    //에러! 정적메서드는 정적메서드가 아닌 일반변수에 접근할 수 없습니다.
        setAge(5);   //에러! 정적메서드는 정적메서드가 아닌 일반메서드에 접근할 수 없습니다.
        return true;
    }
}

그래서 정적멤버의 중요한 특징은, 정적멤버는 자신의 클래스에서 정적멤버가 아닌 일반멤버에 접근하거나, 호출할 수 없습니다.

 

class Dog {
    int age;
    String name;
    static String animal = "개";

    public Dog() {
        age = 3;
        name = "멍멍이";
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static String getAnimal(){
        return animal;
    }
}

단, 정적멤버끼리는 서로 접근하거나 호출할 수 있습니다.


참조형변수와 정적멤버의 관계

참조형 변수를 정적멤버로 사용할 때와 일반멤버로 사용할 때의 예시를 한 번 알아보겠습니다.

class Person {
    Dog myDog = new Dog();

    public static void checkStatic() {
        String dogAge = myDog.age;    //에러! 정적메서드는 일반변수 myDog에 접근할 수 없습니다!

        String animal2 = Dog.animal;       //정적멤버끼리는 접근가능합니다.
        String animal3 = Dog.getAnimal();  //상동
    }
}

정적메서드에서 일반변수로 선언된 참조형 변수를 사용해 객체의 변수나 메서드에 접근한다면 오류가 발생합니다. 왜냐하면 정적메서드에서는 해당 메서드가 속한 클래스의 일반변수에 접근할 수 없기 때문입니다.

 

class Person {
    static Dog myDog = new Dog();

    public static void checkStatic() {
        int dogAge = myDog.age;
        String anima = myDog.animal;
        String animal = myDog.getAnimal();

        String animal2 = Dog.animal;
        String animal3 = Dog.getAnimal();
    }
}

하지만 참조형 변수를 정적변수로 선언한다면 정적메서드 내에서도 접근이 가능합니다. 왜냐하면 정적메서드 또는 정적변수끼리는 서로 자유롭게 사용이 가능하기 때문이죠.

 

class Person {
    public static void checkStatic() {
        Dog myDog = new Dog();

        String dogAge = myDog.age;
        String animal = myDog.animal;
        String animal = myDog.getAnimal();

        String animal2 = Dog.animal;
        String animal3 = Dog.getAnimal();
    }
}

그리고 정적메서드 내에 정적변수가 아닌 참조형 변수를 선언해도 해당 참조형 변수를 사용할 수 있습니다.

 

왜 이럴까요?

그 원인은 정적멤버의 탄생시기와 관련있습니다.

 

일반적인 객체의 변수와 메서드는 객체가 생성될 때 같이 생성됩니다. 하지만 정적멤버는 그렇지 않습니다. 정적변수나 정적메서드는 객체가 아닌, 자바 프로그램이 처음 실행될 때 생성됩니다. 그래서 객체의 생성없이도 정적멤버에 접근이 가능한 것입니다.

 

그래서 정적멤버에서 일반변수를 사용하지 못하는 이유도 이 때문입니다. 바로 위에서 말했듯이 정적멤버는 자바가 실행될 때 같이 만들어지기 때문에, 정적멤버는 일반변수를 사용하려하면 "이 일반변수가 지금 생성된건가?"라고 생각해서 일반변수를 사용할 수 없습니다.

 

정적메서드 내에서 일반 참조형 변수를 선언했을 때 해당 참조형 변수를 사용할 수 있는 이유 역시 자바가 실행되고 정적메서드가 탄생함에 따라 메서드 내부에 있는 참조형변수도 같이 선언되기 때문입니다.


다시 돌아와서: main과 static

public class Main{
    public static void main(String[] args){

    }
}

이제 public과 static에 대해서도 알아보았습니다. public은 어느 객체에서나 호출할 수 있다는 뜻이고, static은 객체의 생성없이도 언제나 객체가 호출 가능하다는 뜻입니다. 그리고 이 main 메서드를 호출하는 쪽은 자바죠.

 

마지막으로 매개변수로 전해지는 String[] args란 무엇일까요?

자바에서는 main 메서드가 시작되기 전에 자바에게 문자열 여러 개를 배열 형태로 넘겨줄 수 있습니다. 그래서 자바는 문자열을 받아서 메인메서드에게 매개변수로 전달해줍니다. 그래서 main 메서드에 매개변수가 존재하는 것이죠.


번외1: 용어정리

여태껏 많은 개념들이 등장했고, 용어들이 자주자주 섞인 편입니다. 따라서 한 번 용어를 재정립해보는 시간을 가져보도록 하겠습니다.

 

정적변수

오늘 배운 내용이죠, 객체의 생성없이 곧바로 접근할 수 있고, 모든 클래스들이 같은 값을 고유하는 변수입니다.

 

로컬변수(지역변수)

메서드 내부에서 선언된 변수입니다.

 

인스턴스 변수

메서드 내부에서 선언된 변수가 아니고, 정적변수가 아닌 변수에 해당합니다. 저번에 변수에 대해서 배웠던 "객체의 상태를 나타내기 위한 값"이 이 인스턴스 변수입니다.

 

정적메서드

오늘 배운 내용입니다. 객체의 생성없이 곧바로 접근할 수 있는 메서드입니다.

 

멤버

변수와 메서드를 합쳐서 멤버라고 칭합니다. 정적변수와 정적메서드를 모두 합쳐서 정적멤버라고 칭합니다.


번외2: 지역변수와 스코프

번외라고하기엔 아주 중요한 내용입니다. 모든 변수에는 살아있는 기간이라는 것이 존재하고, 이 기간을 변수의 스코프라고합니다. 이는 변수에 따라 다릅니다.

 

1. 정적 변수

정적변수는 자바가 실행되자마자 태어나고, 실행이 종료될 때 죽습니다. 따라서 살아있는 기간은 자바가 실행 중이라면 살아있는 셈이지요.

 

2. 인스턴스 변수

인스턴스 변수는 객체의 생성자가 호출되어 객체가 생성되었을 때 태어납니다. 이전에 객체에 대해서 다룰 때, "객체가 더 이상 아무런 객체와도 참조 중이 아니라면, 해당 객체는 쓸모 없어지고 곧 죽는다"라고 했습니다. 인스턴스 변수는 이 때 객체와 같이 죽습니다. 따라서 객체와 운명을 같이하는 셈이죠.

 

3. 로컬변수(지역변수)

로컬변수는 메서드 내부에서 생성되는 변수입니다. 이 로컬변수는 메서드 내에서 변수를 선언했을 때 태어납니다. 그리고 메서드가 끝나면 (return 문에 도달했다던가..)하면 변수가 죽습니다. 즉, 로컬변수는 선언 이후 메서드의 종료여부에 따라 운명이 달라지는 셈이지요.

public class Main{
    public static void main(String[] args){
        int age = 21;
    }

    age = age + 1;    //에러! java: <identifier> expected
    //해당 에러는 "나 이 변수 선언한 거 본 적 없는데? 나 이거 타입 몰라. 그러니까 타입을 명시해"라는 뜻입니다.
}

※여러분은 이제 main 메서드에 대해서 알았습니다. 한 번 실행해보세요!

따라서 로컬변수를 선언한 후에 메서드 밖에서 다시 그 로컬변수를 사용하려하면 에러가 발생합니다.

 

파이썬에서는 global이라는 키워드를 선언하면 메서드 내부에서 선언한 지역변수를 마치 인스턴스 변수인 양 사용할 수 있었습니다. 하지만 자바는 파이썬보다 문법이 엄격한 언어이기 때문에 반드시 변수의 스코프를 엄격하게 나눠놓는 편입니다.


번외3: 출력하기

아무리 값을 계산해도 이를 눈으로 확인해야합니다. 이 때 사용하는 메서드가 System.out.println() 메서드입니다.

 

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

앞서 배운 main 메서드에 이 출력함수 입력하고, 출력할 문장을 매개변수로 넘겨주면 출력됩니다.

이렇게 실제로 자바코드를 넣고, 출력해볼 수 있습니다.

기본형 변수는 모두 괄호에 넣으면 기본형 변수에 해당하는 값을 출력시켜줍니다.


오늘은 이렇게 자바를 실행하기 위한 마지막 퍼즐, main 메서드와 정적멤버, 그리고 접근제어자에 대해서 알아보았습니다. 이제 여러분은 자유로이 자바를 실행해볼 수 있습니다!

 

이제 여태까지 개념과 느낌이 애매했던 객체, 클래스, 변수, 생성자, 메서드를 다시 한 번 들여다볼 때입니다. 직접 실행해보며 클래스는 어떤 구조로 이루어져있는지, <컬러잇 자바> 시리즈에서 주구장창 나왔던 “객체와의 상호작용”은 무엇인지 알아볼 수 있는 것이죠.

 

따라서 다음편에서는 본격적으로 간단한 자바 프로그램을 하나 만들어볼 것입니다. 그 과정까지 끝나면, 여러분은 자바를 자유자재로 사용할 수 있는 기본적인 준비에 성공한 것입니다. 그럼 다음 편에서 뵙겠습니다. 감사합니다!

 

 

추가로..

오늘 배운 내용들은 단지 읽어보기에는 다소 어려운 내용들입니다. 직접 한 번 실행해보는 것 어떨까요? main 메서드가 static이니 static이 아닌 메서드를 새로 만들어보고, 정적멤버나 일반멤버끼리 접근하거나, 호출해보면서 오늘의 개념을 잘 다져두기를 바라겠습니다.

'Language > ColorIt_Java' 카테고리의 다른 글

[컬러잇자바] #7 - 간단한 자바프로그램 만들어보기  (0) 2026.02.09
[컬러잇자바] #5. 왜 생성자를 사용할까?  (0) 2026.01.26
[컬러잇자바] #4. 왜 메서드를 사용할까?  (1) 2026.01.19
[컬러잇자바] #3. 왜 변수와 타입을 사용할까?  (1) 2026.01.12
[컬러잇 자바] #2. 왜 객체를 사용할까?  (1) 2026.01.05
'Language/ColorIt_Java' 카테고리의 다른 글
  • [컬러잇자바] #7 - 간단한 자바프로그램 만들어보기
  • [컬러잇자바] #5. 왜 생성자를 사용할까?
  • [컬러잇자바] #4. 왜 메서드를 사용할까?
  • [컬러잇자바] #3. 왜 변수와 타입을 사용할까?
컬러잇
컬러잇
개발을 합니다.
  • 컬러잇
    Color_It!
    컬러잇
  • 전체
    오늘
    어제
    • 분류 전체보기 (7)
      • Language (7)
        • ColorIt_Java (7)
      • CS (0)
      • 개인 프로젝트 (0)
      • 팀 프로젝트 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 디디디 개발블로그
  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
컬러잇
[컬러잇자바] #6. 왜 main 메서드를 사용할까?
상단으로

티스토리툴바