풀스택 개발자 과정 11일차

너구·2026년 5월 20일

풀스택 성장과정

목록 보기
11/79

제어자 (Modifiers)

  • 접근 제어자(Access Modifiers)
    클래스/멤버에 대한 접근을 제어한다.

  • 비접근 제어자(Non-Access Modifiers)
    클래스/멤버의 용도나 제약 사항 등을 정의한다.


클래스 (Class)

객체 생성을 위한 틀, 설계도를 의미한다.
클래스는 속성과 메서드로 구성된다.
클래스에 속한 속성과 메서드들을 합쳐 클래스의 멤버(Member)라고도 부른다.

  • 속성(Property): 클래스에 속한 변수
  • 메서드(Method): 클래스에 속한 함수

클래스 정의하기

class클래스_이름{본문}

클래스 정의하기 예제(1)

아래에 표현된 클래스를 구현하라.

person
name: String
age: int
greeting():void

class Person { // 이름은 대문자로 시작해야 합니다

    // 속성 (필드), 멤버 변수
    String name; 
    int age;

    // 메서드 (클래스에 속한 함수)
    void greeting() {
        System.out.println("hello");
    };
}

public class Main {
    
}

이 코드는 person이라는 클래스를 만들고 그 안에 name, age 같은 속성과 greeting() 이라는 메서드를 작성한 코드이다.
String, int와 같은 변수를 사용해 사람의 정보를 저장하였고, void 메서드를 사용해 "hello"를 출력하게 만들었다.

클래스 정의하기 예제(2)

다음을 만족하는 클래스를 정의하라.

car
modelName: String
color: String
year: int
driv():void

class Car {
    String modleName;
    String color;
    int year;

    void drive() {
        System.out.println("brrrrrrr");
    }
}
public class Main {
    
}

이 코드도 위와 같다.


인스턴스(Instance)

클래스로부터 생성된 객체를 의미한다.
예를 들어 A클래스로부터 생성된 객체를 A의 인스턴스라고 부른다.

인스턴스 정의하기

클래스 객체_이름=new 생성자 호출

인스턴스 생성하기 예제(1)

Person 클래스의 인스턴스를 생성하고 속성값을 정의하라.

class Person {
    String name;
    int age;

    void greeting() {
        System.out.println("hello");
    }
}

public class Main {
    public static void main(String[] args) {
        
        //인스턴스 생성
        Person person = new Person();

        //속성할당
        person.name = "John Doe";
        person.age = 30;

        //속성에 접근하기
        System.out.println(person.name);
        System.out.println(person.age);

        //메서드 호출
        person.greeting();
    }
}

Person이라는 클래스를 만들고 그 안에 name, age같은 속성과 greeting()이라는 메서드를 작성한 코드이다.
String, int와 같은 변수를 사용해 사람의 정보를 저장하고 void 메서드를 사용해 "hello"를 출력하게 만들었다.
아까 쓴 코드와 동일하다.
그 다음 new Person()을 사용해 객체(인스턴스)를 생성하였고, person name, person.age를 통해 객체의 속성에 값을 저장하고 출력하였다.
마지막으로 person.greeting()을 호출하여 클래스 내부의 메서드를 실행하는 구조로 작성하였다.

인스턴스 생성하기 예제(2)

클래스 Car의 인스턴스를 생성하고 속성값을 정의하라.

class Car {
    String modelName;
    String color;
    int year;

    void drive() {
        System.out.println("brrrrrrr");
    }
}

public class Main {

    public static void main(String[] args) {
        Car car = new Car();

        car.modelName = "kia";
        car.color = "white";
        car.year = 2026;

        System.out.println(car.modelName);
        System.out.println(car.color);
        System.out.println(car.year);

        car.drive();
    }
    
}

위와 동일한 방법으로 작성하였다.


생성자(Constructor)

생성자는 객체를 생성하는 함수다.
생성자의 인자를 활용해 인스턴스의 속성을 할당할 수 있다.
클래스를 선언할 때 생성자가 없으면 컴파일러가 자동으로 기본 생성자를 추가한다.

생성자 예제(1)

생성자를 활용해 Person의 인스턴스에게 속성을 할당하라.

class Person {
    String name;
    int age;

    // 생성자의 주요 용도 - 속성값 정의
    Person(String name, int age) { // 클래스와 이름이 같다
        // this = 현재 클래스 => 멤버 변수라고 표현합니다.
        this.name = name;
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        
        Person person = new Person("John Doe", 30);

        System.out.println(person.name);
        System.out.println(person.age);
    }
    
}

앞에 클래스 부분은 위에 했던 것과 동일하다.
person(String name, int age)는 생성자로, 클래스 이름과 같은 이름으로 작성하였다.
객체가 생성될 때 자동으로 실행되도록 만들었고, 전달받은 값을 객체의 속성에 저장하도록 하였다.
this.name, this.age는 현재 객체의 멤버 변수에 접근하는 코드이며, 매개변수와 멤버 변수의 이름이 같기 때문에 this를 사용해 구분하였다.
new Person("John Doe", 30)을 사용해 객체를 생성하면서 이름과 나이를 한 번에 전달하도록 작성하였다.
마지막으로 print를 사용해 객체 안에 저장된 name과 age 값을 출력하도록 작성하였다.

생성자 예제(2)

생성자를 활용해 Car의 인스턴스에게 속성을 전달하라.

class Car {
    String modelName;
    String color;
    int year;

    Car(String modelName, String color, int year) {
        this.modelName = modelName;
        this.color = color;
        this.year = year;
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car("KIA", "white", 2026);

        System.out.println(car.modelName);
        System.out.println(car.color);
        System.out.println(car.year);
    }
    
}

이 또한 위 코드와 같다


생성자 오버로딩(Contructor Overloading)

여러개의 생성자를 통해 객체의 생성 과정을 유연하게 만들 수 있다.

생성자 오버로딩 예제

나이 정보가 없거나 보호하고 싶은 경우 사용하기 위해 person에 이름만 입력받는 생성자를 추가하라.

class Person {
    String name;
    int age;

    // 첫번째 생성자 - 이름만 입력받음
    Person(String name) {
        // 두번째 생성자
        this(name, 0);
        // 나이 정보가 없거나 밝히고 싶지 않은 경우
    }

    // 두번째 생성자 - 이름과 나이 모두 입력받음
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        
        // 두번째 생성자로 객체 생성
        Person john = new Person("John Doe", 30);
        // 첫번째 생성자로 객체 생성
        Person jane = new Person("Jane Doe");

        System.out.println(john.age);
        System.out.println(jane.age);
    }
    
}

먼저 person 클래스를 만들고 이름과 나이를 저장할 변수를 선언하였다.
그 다음 Person(String name)으로 첫번째 생성자를 만들었다.
생성자 안에서는 this(name,0)을 사용하였다.
this()를 통해 이름만 입력하면 나이는 자동으로 0을 넣게 만들었다.

두번째 생성자는 Person(String name, int age) 형태로 이름과 나이를 모두 입력받는다.
그리고 this.name = name; this.age = age; 를 사용해 입력받은 값을 개체 안에 저장하도록 하였다.

main 함수에서는 객체를 두 가지 방식으로 생성했다.
이름과 나이를 모두 입력한 경우와 이름만 입력한 경우이다.
그렇기 때문에 john.age -> 30 jane.age -> 0이 출력된다.


정적 변수(Static Varialbles)

정적 변수는 클래스의 속성이다.
따라서 인스턴스가 아니라 클래스를 사용해 접근해야 한다.
정적 변수는 클래스가 직접 관리하는 데이터가 필요할 때 사용한다.

정적 변수 예제

Person 클래스에 생성된 인스턴스의 개수를 세는 정적 변수 population을 추가하라.

class Person {
    String name;

    //정적 필드
    static int population = 0;
    // static final : 상수

    // 생성자
    Person(String name) {
        this.name = name;
        population++; // 인스턴스가 생성될 때마다 1씩 증가
    }
}

public class Main {
    public static void main(String[] args) {
        Person john = new Person("John Doe");
        Person jane = new Person("Jane Doe");
        Person mary = new Person("mary Doe");

        System.out.println(Person.population);
        
    }
}

먼저 person 클래스를 만들고 이름을 저장할 변수를 선언하였다.
그리고 static int population = 0;를 사용해 정적 필드를 선언하였다.
그로인해 Person 객체가 몇 명 생성되었는지를 모든 객체가 함께 공유하게 된다.

그 다음 생성자를 만들었다.
this.name = name;을 통해 입력받은 이름을 객체 변수에 저장하였다.
그리고 population++;을 작성하였다.
객체가 하나 생성이 될 때마다 population 값이 1씩 증가하도록 만든 것이다.

main 함수에서는 객체를 총 3개 생성하였다.
객체가 생성될 때마다 생성자가 실행되고 population++;가 동작한다.
그 다음 print를 사용해 Person.population을 출력하면 전체 인구 수가 출력이 된다.

그렇기 때문에 최종 출력값은 3이 된다.


정적 메서드(Static Methods)

정적 메서드는 클래스에 속한 메서드이다.
자바에 내장된 Math 클래스처럼 주로 유틸리티 클래스를 구현하는 데 사용된다.
정적 메서드에서는 인스턴스 변수에 접근할 수가 없다.

정적 메서드 예제

자바에 내장된 Math 클래스의 유틸리티 기능(정적 메서드)을 활용하라.

public class Main {
    public static void main(String[] args) {
        // 정적 메서드는 클래스로 접근합니다
        System.out.println(Math.pow(2, 10));
        System.out.println(Math.max(3, 5));
        System.out.println(Math.abs(-3));
    }
}

Math 클래스의 정적 메서드를 사용해보았다.
pow는 제곱을 계산하는 메서드이다.
즉 2¹⁰ = 1024를 출력한다.

max는 두 숫자 중 더 큰 값을 반환하는 메서드이다.
따라서 5가 출력된다.

abs는 절대값을 반환하는 메서드이다.
그래서 -3을 3으로 바꾸어 출력한다.

Math 클래스의 메서드는 static 메서드이기 때문에 객체를 생성하지 않고 Math.메서드명() 형태로 바로 사용이 가능하다고 한다.


Getter/Setter

객체-지향 프로그래밍에서 캡슐화(Encapsulation)를 구현하는 방법이다.
캡슐화란 객체의 내부 데이터를 보호하고 객체의 변화로 인한 파급효과를 줄이기 위한 기법을 의미한다.

Getter 활용 예제

클래스 Person에서 name 변수가 firstName, lastName으로 분해되었다고 가정한다.
이를 바탕으로 Getter의 필요성을 나타내는 코드를 작성하라.

// 변경 전

class Person {
    String name;

    Person(String name) {
        this.name = name;
    }

    // getter
    String getName() {
        return name;
    }
}

// 변경 후
class Person2 {
    String firstName;
    String lastName;

    Person2(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    String getName() {
        return firstName + " " + lastName;
    }
}

public class Main {
    public static void main(String[] args) {
        
        Person person = new Person("John Doe");

        // 기존 코드 => 안바꿔도 됨 (결합도를 낮춤)
        System.out.println(person.getName());
    }
    
}

변경 전과 변경후를 비교해보면서 작성하였다.
처음에는 name 변수 하나만 사용하였지만, 이후 firstName과 lastName으로 구조가 변경되었다.
만약 Getter를 사용하지 않고 직접 변수에 접근했다면 기존 코드들을 모두 수정해야 했을 것이다.

Getter를 사용했기 때문에 내부 구조가 바뀌어도 메서드만 수정하면 기존 코드는 그대로 사용할 수 있다.
즉 Getter를 사용하면 클래스 내부 구조가 변경되더라도 외부 코드의 수정이 줄어들게 되며, 객체 간의 결합도를 낮출 수 있다라는 점을 확인할 수가 있다.


이번엔 클래스와 생성자, static, Getter와 같은 객체 지향 개념들을 공부해보았다.
이를 공부하면서 아직은 조금 어렵고 헷갈리는 부분도 많다는 걸 느꼈다.
특히 생성자 오버로딩이나 static 같은 개념은 처음에는 이해하기 힘들었지만 직접 코드를 따라 작성해보며 조금씩 감이 잡히기 시작했따.

또 Getter를 사용하는 이유처럼 단순히 코드를 작성하는 것뿐만 아니라 왜 이런 구조를 사용하는지도 배우게 되어 흥미로웠다.
아직 응용해서 혼자 작성하는 건 어렵지만 계속 반복해서 연습하다보면 언젠가 익숙해질 거라는 생각이 들었다.
얼른 익숙해져서 나도 멋있게 코딩하고 싶다.

0개의 댓글