[Java] 클래스

artp·2025년 1월 17일
0

java

목록 보기
9/32
post-thumbnail

7. 클래스

클래스는 자바에서 객체를 생성하기 위한 설계도입니다. 객체는 클래스에서 정의된 속성기능(메서드)을 실제로 사용할 수 있는 실제 모습(instance)입니다. 자바에서 클래스와 객체를 활용하면 객체지향 프로그래밍의 핵심 개념인 캡슐화(데이터 보호), 상속(재사용), 다형성(다양한 동작)을 쉽게 구현할 수 있습니다.

7.1 객체지향 프로그래밍

객체지향 프로그래밍(OOP)은 데이터를 객체라는 단위로 묶어 설계하는 프로그래밍 방식입니다.

1. 캡슐화

데이터와 동작(메서드) 등 프로그램에 필요한 모든 자원을 하나의 객체로 묶고, 외부에서 접근을 제한합니다. 이를 통해 객체의 데이터를 보호하고 외부에서 잘못된 접근을 못하게 막을 수 있습니다.

2. 상속

상속은 한 클래스의 데이터와 기능을 다른 클래스가 이어받는 것을 말합니다. 상속을 통해 클래스끼리 부모-자식 관계가 생깁니다.
기존 클래스를 재사용하여 새로운 클래스를 작성합니다.

3. 다형성

동작이나 형태가 다른 기능을 하나의 이름으로 사용할 수 있게 하는 것을 의미합니다.
같은 이름의 메서드나 객체가 다양한 형태로 동작할 수 있습니다. 자바에서는 오버라이딩과 오버로딩 등을 통해 다형성을 지원합니다.

4. 추상화

객체의 구체적인 구현을 숨기고, 인터페이스를 통해 필요한 기능만 제공합니다.
객체마다 데이터와 동작을 구체적으로 정의하지 않고 객체들의 공통적인 데이터와 동작만 추출해 선언해두는 것입니다. 이렇게 선언한 클래스를 추상화 클래스라고 합니다.

7.2 클래스와 객체

클래스와 객체를 현실에 빗대어 설명할 때 자동차를 예로 많이 듭니다. 자동차는 설계도를 바탕으로 제작하는데, 이때 설계도가 클래스, 설계도로 구현한 자동차가 객체입니다. 설계도를 기반으로 자동차를 여러 대 만들 수 있듯, 클래스를 기반으로 객체를 여러 개 생성할 수 있습니다.

7.2.1 클래스 선언

클래스는 class 키워드를 사용하여 선언합니다.

예제

public class Car {
	// 필드
    String color;
    int speed
    
    // 메서드
    void drive() {
    	System.out.println("The car is driving.");
    }
}

7.2.2 클래스 멤버

클래스에는 '필드, 메서드, 생성자'라는 3가지 구성 요소가 있습니다. 이들을 클래스의 멤버라고 합니다.

1. 필드(Field)

  • 클래스가 가지는 속성을 나타내며, 멤버 변수라고도 부릅니다.
  • 클래스 내부에서 정의된 변수로, 객체의 데이터를 저장하는 데 사용됩니다.

필드의 종류

1. 인스턴스 변수

  • 객체가 생성될 때마다 새로 생성되는 변수입니다.
  • 객체마다 고유한 값을 가질 수 있습니다.
  • 클래스에서 선언하지만, 각 객체마다 별도로 초기화됩니다.
  • 객체별로 다른 속성을 저장해야 할 때 사용합니다.
예제
public class Person {
	String name; // 인스턴스 변수
    int age; // 인스턴스 변수 
}

public class Main {
	public static void main(String[] args) {
    	Person person1 = new Person();
        person1.name = "홍길동"; // 각 객체에서 고유한 값으로 초기화
        person1.age = 25; // 각 객체에서 고유한 값으로 초기화
        
        Person person2 = new Person();
        person2.name = "윤봉길"; // 각 객체에서 고유한 값으로 초기화
        person2.age = "22"; // 각 객체에서 고유한 값으로 초기화
        
        System.out.println(person1.name + "님은 " + person1.age + "살입니다.");
        System.out.println(person2.name + "님은 " + person2.age + "살입니다.");
    }
}
출력
홍길동님은 25살입니다.
윤봉길님은 22살입니다.

2. 클래스 변수

  • 클래스 전체에서 공유되는 변수입니다.
  • static 키워드를 사용하여 선언하며, 클래스 로드 시 한 번만 초기화됩니다.
  • 모든 객체가 같은 값을 공유하며, 클래스 이름을 통해 직접 접근할 수 있습니다.
예제
public class Calculator {
	static double PI = 3.14159; // 클래스 변수
    
    static double calculateCircleArea(double radius) {
    	return PI * radius * radius; // 원의 넓이 구하기
    }
    
public class Main {
	public static void main(String[] args) {
    	System.out.println("원의 넓이: " + Calculator.calculateCircleArea(10));
    }
}
출력
원의 넓이: 314.159

3. 지역 변수

  • 메서드나 블록 내부에서 선언되는 변수입니다.
  • 메서드가 실행되는 동안만 유효하며, 메서드가 종료되는 시점에 메모리에서 삭제됩니다.
  • 초기화하지 않으면 사용할 수 없습니다.
예제
public class Main {
	public static void main(String[] args) {
    	int localVariable = 10;
        System.out.println("지역 변수: " + localVariable);
    }
}
출력
지역 변수: 10

2. 메서드(Method)

프로그래밍을 하다 보면 특정 작업을 여러 번 수행해야 할 때가 있습니다. 동일한 작업을 반복적으로 작성하지 않기 위해, 해당 작업을 수행하는 코드를 별도로 정의하고 필요할 때 가져다 쓸 수 있습니다. 이처럼 특정 작업을 수행하는 코드 블록을 함수라고 하며, 자바에서는 클래스 안에 정의한 함수를 메서드라고 부릅니다.

메서드의 특징

  • 클래스가 가지는 기능을 나타냅니다.
  • 클래스 내부에서 동작을 정의하는 코드 블록입니다.
  • 메서드를 사용하면 코드의 재사용성가독성이 향상됩니다.

형식

[접근 제한자] 반환형 메서드명(매개변수1, 매개변수2, ...) {
	// 메서드 본분
    return 반환값; // 반환형이 void가 아닌 경우 반드시 반환값 필요
}

1. 접근 제한자

  • 메서드의 접근 범위를 제한합니다.
  • public, protected, default, private 키워드로 설정 가능합니다.
  • 아무것도 명시하지 않으면 같은 패키지 내에서만 접근 가능합니다.

2. 반환형

  • 메서드가 실행 후 반환하는 값의 자료형입니다.
  • 반환값이 없으면 void로 선언하며, 이 경우 return 문은 생략 가능합니다.

3. 메서드명

  • 메서드의 이름은 동작을 명확히 나타내도록 작성해야 하며, 카멜 표기법으로 작성합니다.

4. 매개변수

  • 메서드가 외부에서 전달받는 값을 저장하는 변수입니다.
  • 매개변수의 자료형은 전달받는 값과 같아야 합니다.
  • 매개변수가 없으면 괄호를 비워둡니다.

5. 메서드 본문

  • 메서드가 수행할 작업을 작성합니다.

메서드 예제

public class Car {
	// 메서드 정의
    public void drive() {
    	System.out.println("The car is driving.");
    }
    
    public int add(int a, int b) {
    	return a + b; // 두 숫자의 합을 반환
    }
}

메서드 호출

public class Main {
	public static void main(String[] args) {
    	Car car = new Car();
        car.drive(); // 출력: The car is driving.
        
        int sum = car.add(5, 15);
        System.out.println("Sum: " + sum); // 출력: Sum: 15
    }
}

3. 생성자 (Constructor)

생성자는 클래스의 객체를 생성하고 초기화하는 데 사용되는 특별한 메서드입니다.
클래스의 설계도에 따라 객체를 생성할 때, 필요한 초기값을 설정하거나 초기 작업을 수행하는 역할을 합니다.

생성자의 주요 특징

  1. 객체 생성 시 자동 실행:

    • 객체가 생성될 때 자동으로 호출되며, 객체의 초기 상태를 설정합니다.
  2. 클래스 이름과 동일:

    • 생성자의 이름은 반드시 클래스 이름과 동일해야 합니다.
  3. 반환형 없음:

    • 반환형을 명시하지 않습니다. 반환형을 작성하면 일반 메서드로 간주됩니다.
  4. 오버로딩 가능:

    • 생성자도 오버로딩이 가능합니다.
      즉, 매개변수의 개수나 타입이 다른 여러 개의 생성자를 정의할 수 있습니다.
  5. 명시적 호출:

    • 생성자는 new 키워드를 사용하여 객체를 생성할 때 호출됩니다.
  6. 기본 생성자 제공:

    • 개발자가 생성자를 정의하지 않으면 컴파일러가 기본 생성자(매개변수가 없는 생성자)를 자동으로 추가합니다.

생성자의 기본 구조

public class ClassName {
    // 생성자
    public ClassName() {
        // 초기화 작업
    }
}

생성자의 역할

1. 객체 생성과 초기화

  • 생성자는 객체가 생성될 때 필요한 초기값을 설정하거나, 리소스를 준비하는 작업을 수행합니다.

예제

public class Person {
    String name;
    int age;

    // 생성자
    public Person(String name, int age) {
        this.name = name; // 초기화 작업
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person("홍길동", 30); // 객체 생성과 초기화
        System.out.println(person.name); // 출력: 홍길동
        System.out.println(person.age);  // 출력: 30
    }
}

2. 생성자 오버로딩

  • 동일한 이름의 생성자를 매개변수의 타입, 개수, 순서를 다르게 하여 여러 개 정의할 수 있습니다.

예제

public class Person {
    String name;
    int age;

    // 기본 생성자
    public Person() {
        this.name = "Unknown";
        this.age = 0;
    }

    // 매개변수가 있는 생성자
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person person1 = new Person(); // 기본 생성자 호출
        Person person2 = new Person("홍길동", 30); // 매개변수 있는 생성자 호출

        System.out.println(person1.name + ", " + person1.age); // 출력: Unknown, 0
        System.out.println(person2.name + ", " + person2.age); // 출력: 홍길동, 30
    }
}

3. 기본 생성자 (Default Constructor)

  • 기본 생성자매개변수가 없는 생성자를 말합니다.
  • 개발자가 생성자를 하나도 정의하지 않으면, 컴파일러가 자동으로 기본 생성자를 추가합니다.
  • 개발자가 생성자를 정의하면, 기본 생성자는 자동으로 추가되지 않으므로 필요하면 명시적으로 정의해야 합니다.

예제

public class Car {
    String color;

    // 기본 생성자를 정의하지 않으면, 컴파일러가 자동으로 추가
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car(); // 기본 생성자 호출
        System.out.println(car.color); // 출력: null (초기화되지 않은 필드)
    }
}

4. 생성자에서 다른 생성자 호출

  • 생성자 내부에서 다른 생성자를 호출할 수 있으며, this() 키워드를 사용합니다.
  • 생성자 코드를 재사용하거나 기본값을 설정할 때 유용합니다.
  • this()같은 클래스 내의 다른 생성자를 호출하는 특별한 문법입니다.
  • 자바는 생성자를 호출하는 역할을 this() 키워드에 부여하여, 생성자 간의 코드 재사용을 가능하게 했습니다.

예제

public class Person {
    String name;
    int age;

    // 기본 생성자
    public Person() {
        this("Unknown", 0); // 다른 생성자(매개변수가 있는 생성자) 호출
    }

    // 매개변수가 있는 생성자
    public Person(String name, int age) {
        this.name = name; // 전달받은 값을 필드에 저장
        this.age = age;   // 전달받은 값을 필드에 저장
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person(); // 기본 생성자 호출
        System.out.println(person.name + ", " + person.age); // 출력: Unknown, 0
    }
}

생성자의 접근 제한자

  • 생성자에도 접근 제한자를 사용할 수 있습니다.
  • public, protected, default, private 모두 사용 가능하며, 객체 생성 범위를 제어할 수 있습니다.

예제: 생성자의 접근 제한자

public class Singleton {
    private static Singleton instance;

    // private 생성자
    private Singleton() {
    }

    // getInstance()를 통해 객체 생성
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

❗this와 this()

1. this의 기본적인 역할

  • this는 현재 생성된 객체 자기 자신을 참조합니다.

  • 객체의 멤버(필드, 메서드)에 접근할 때 주로 사용됩니다.

  • 주요 역할

    1. 필드와 지역 변수 구분

      • 생성자나 메서드 내부에서, 필드와 지역 변수의 이름이 같을 때 구분하기 위해 사용됩니다.
      public class Person {
          String name;
      
          public Person(String name) {
              this.name = name; // this를 사용해 필드와 지역 변수를 구분
          }
      }
    2. 현재 객체의 메서드 호출

      • 객체가 자신의 메서드를 호출할 때 사용됩니다.
      public void display() {
          System.out.println("Hello from " + this.name);
      }

2. this()의 특별한 역할: 생성자 호출

  • this()는 같은 클래스 내의 다른 생성자를 호출하는 특별한 문법입니다.
  • 자바는 생성자를 호출하는 역할this() 키워드에 부여하여, 생성자 간의 코드 재사용을 가능하게 했습니다.

this()로 생성자를 호출하는 이유

  1. 코드 중복 제거
    • 생성자에서 공통적으로 수행해야 하는 작업이 있을 때, this()를 사용하면 해당 작업을 중복해서 작성하지 않아도 됩니다.
  2. 초기화 로직 통합
    • this()를 사용하면 초기화 작업을 하나의 생성자에 집중시킬 수 있어, 코드 유지보수가 쉬워집니다.

3. this()의 사용 규칙

  1. 같은 클래스 내의 생성자를 호출

    • this()현재 클래스 내의 다른 생성자를 호출할 때만 사용할 수 있습니다.
    • 다른 클래스의 생성자를 호출하려면 super()를 사용해야 합니다.
  2. 생성자 내부에서만 사용 가능

    • this()는 생성자 내부에서만 사용할 수 있으며, 일반 메서드나 다른 곳에서는 사용할 수 없습니다.
  3. 생성자의 첫 줄에서만 사용 가능

    • this()는 반드시 생성자의 첫 번째 줄에서 호출되어야 합니다.
    • 이유는, 객체가 생성될 때 초기화 작업이 순차적으로 이루어져야 하기 때문입니다.

예제

public class Person {
    String name;
    int age;

    // 기본 생성자
    public Person() {
        this("Unknown", 0); // 다른 생성자를 호출
    }

    // 매개변수가 있는 생성자
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

4. this()와 일반 this의 차이

  • this

    • 현재 객체의 필드나 메서드를 가리킵니다.
    • 객체 내부에서 자기 자신을 참조할 때 사용됩니다.
  • this()

    • 현재 클래스의 다른 생성자를 호출합니다.
    • 생성자 간의 코드 재사용을 위해 사용됩니다.

예제

public class Person {
    String name;

    // 기본 생성자
    public Person() {
        this("Unknown"); // this()로 다른 생성자 호출
    }

    // 매개변수가 있는 생성자
    public Person(String name) {
        this.name = name; // this로 필드와 지역 변수 구분
    }
}

7.2.3 객체 생성

객체는 클래스로부터 new 연산자를 통해 생성됩니다.
new 키워드 뒤에는 객체를 생성할 클래스명이 오고, 뒤에 소괄호와 세미콜론이 붙습니다. 이렇게 하면 해당 클래스에 정의된 생성자가 호출되며 객체가 생성됩니다.

형식

new 클래스명();
  • 이 코드는 클래스의 생성자를 호출하며, 객체를 메모리에 저장합니다.

객체를 변수에 저장

객체를 생성한 후에는 메모리의 위치(주소)를 저장하여 사용해야 합니다. 이를 위해 참조 변수를 사용합니다.
객체의 참조 변수를 선언할 때 자료형은 객체를 생성한 클래스명과 동일해야 합니다.
참조 변수에 저장되는 값은 실제 값이 아니라 객체가 저장된 메모리 주소입니다.

형식

클래스명 변수명 = new 클래스명();

예제: 클래스 정의

public class Car {
	// 필드
    String color;
    int speed;
    
    // 메서드
    public void drvie() {
    	System.out.println("The car is driving.");
    }
}

예제: 객체 생성 및 사용

public class Main {
	public static void main(String[] args) {
    	// 객체 생성
        Car myCar = new Car(); // Car 클래스의 객체 생성
        
        // 객체 사용
        myCar.color = "Green"; // 필드 초기화
        myCar.speed = 120; // 필드 초기화
        
        myCar.drive(); // 메서드 호출
    }
}

출력

The car is driving.

7.2.4 실습: 클래스와 객체

클래스 정의

public class Student {
	// 필드
    String name;
    int age;
    
    // 메서드
    void study() {
    	System.out.println(name + " is studying.");
    }
}

객체 생성 및 사용

public class Main {
	public static void main(String[] args) {
    	// 객체 생성
        Student student = new Student(); // 기본 생성자 호출
        student.name = "홍길동"; // 필드 초기화
        student.age = 20; // 필드 초기화
        
        student.study(); // 메서드 호출
    }
}

출력

홍길동 is studying.

7.3 클래스 심화

7.3.1 static

static 키워드는 해당 필드나 메서드가 특정 객체가 아니라 클래스 자체에 속하도록 정의합니다.
static 멤버는 객체 생성 없이도 사용 가능합니다.

예제

public class Calculator {
	static int add(int a, int b) {
    	return a + b;
    }
}

public class Main {
	public static void main(String[] args) {
    	int result = Calculator.add(5, 10); // 객체 생성 없이 호출 가능
        System.out.println("Result: " + result);
    }
}

출력

Result: 15

7.3.2 접근 제한자

접근 제한자는 클래스와 클래스 구성 요소에 접근할 수 있는 권한을 나타냅니다.
접근 제한자는 클래스 멤버의 접근 범위를 제어합니다.

public

  • 같은 패키지든 다른 패키지든 상관없이 어디서든 접근할 수 있습니다. 클래스, 필드, 메서드, 생성자에 모두 사용할 수 있습니다.

protected

  • 같은 패키지의 클래스나 다른 패키지의 상속받은 클래스에서 접근할 수 있습니다. 클래스에는 사용할 수 없고 필드, 메서드, 생성자에만 사용할 수 있습니다.

private

  • 같은 클래스에서만 접근할 수 있습니다. protected와 마찬가지로 필드, 메서드, 생성자에만 사용할 수 있습니다.

default

  • 접근 제한자를 따로 명시하지 않으면 자동으로 defaut 권한이 적용됩니다. 같은 패키지의 클래스에서만 접근할 수 있고 클래스, 필드, 메서드, 생성자 모두에 사용할 수 있습니다.

7.3.3 게터 메서드와 세터 메서드

캡슐화를 구현하기 위해 필드는 보통 private으로 선언하여 외부에서 직접 접근하지 못하도록 보호합니다. 대신, 외부와의 접근은 게터(getter)세터(setter) 메서드를 통해 제어합니다.
게터와 세터는 필드 값을 안전하게 읽거나 수정할 수 있는 방법을 제공합니다.

게터 메서드(getter)

게터 메서드는 private 접근 제한자가 붙은 필드를 외부에서 읽을 수 있게 하는 메서드입니다.

  • 반환형은 필드의 자료형과 동일합니다.
  • 메서드 이름은 보통 get + 필드명으로 작성하며, 첫 글자는 대문자로 합니다.

예제

public String getName() {
	return name; // 필드 값을 반환
}

세터 메서드(setter)

세터 메서드는 private으로 보호된 필드의 값을 외부에서 설정하거나 변경할 수 있도록 하는 메서드입니다.

  • 반환형은 void입니다.
  • 메서드 이름은 보통 set + 필드명으로 작성하며, 첫 글자는 대문자로 합니다.
  • 매개변수는 필드의 자료형과 동일하며, 필드에 설정할 값을 전달받습니다.

예제

public String setName(String name) {
	this.name = name; // 필드 값을 설정
}

게터와 세터 사용 예제

클래스 정의

public class student {
	// 필드
    private String name;
    private int age;
    
    // getter
    public String getName() {
    	return name; // 필드 값을 반환
    }
    public int getAge() {
    	return age; // 필드 값을 반환
    }
    
    // setter
    public void setName(String name) {
    	this.name = name; // 필드 값을 설정
    }
    public void setAge(int age) {
    	if (age > 0) { // 유효성 검사
        	this.age = age;
        } else {
        	System.out.println("나이는 반드시 0 이상이어야 합니다.");
        }
    }
}

객체 생성 및 사용

public class Main {
	public static void main(String[] args) {
    	// 객체 생성
        Student student = new Student(); // 기본 생성자
        
        // 세터를 사용하여 필드 값 설정
        student.setName("홍길동");
        student.setAge(20);
        
        // 게터를 사용하여 필드 값 읽기
        System.out.println("이름: " + student.getName()); // 출력: 이름: 홍길동
        System.out.println("나이: " + student.getAge()); // 출력: 나이: 20
    }
}

게터와 세터 사용 이유

  • 데이터 보호
    필드를 private으로 선언하여 외부에서 직접 접근을 차단하고, 무분별한 수정으로부터 데이터를 보호합니다.
  • 유효성 검사
    세터 메서드에서 값 설정 시 조건을 추가하여 유효한 값만 필드에 저장하도록 할 수 있습니다.
  • 읽기 전용 또는 쓰기 전용 제공
    필드를 읽기 전용(getter만 제공)으로 만들거나, 쓰기 전용으로(setter만 제공) 설정할 수 있습니다.
profile
donggyun_ee

0개의 댓글