3주차는 6장 하나만 공부하면 되는데, 그 양이 꽤나 크다. 또한, 주제가 클래스로 객체 지향언어의 대표인 자바의 핵심 내용이라고 할 수 있다.

일주일 내내 이 단원을 붙잡고 있었는데, 한 번에 여러 개념들이 들어와 꽤나 혼란스러웠던 것 같다. 한 번 책을 읽고 노션에 정리해보았고 다시 한 번 읽어보며 복습했다.

6장 정리한 내용만 해도 꽤 양이 된다. 원하는 것이 있다면 Ctrl+F나 오른쪽의 목차를 이용해 빠르게 찾으면 좋을 것이다.

01 객체 지향 프로그래밍

  • 객체 : 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지면서 식별 가능한 것
    • 필드 : 속성
    • 메소드 : 동작

메소드 호출

리턴값 = 객체.메소드(매개값);

ex) int result = Calculator.add(10,7);

객체 간의 관계

  • 집합 관계
    • 부품 - 완성품 관계
    • ex. 엔진, 타이어, 핸들 - 자동차
  • 사용 관계
    • 객체 간 상호작용
    • 사람은 자동차를 사용함 → 사람은 자동차를 사용할 때 달린다, 멈춘다 등의 메소드를 호출함
  • 상속 관계
    • 부모 - 자식 관계로, 상위(부모) 객체를 기반으로 하위(자식) 객체를 생성하는 관계
    • 일반적으로 상위 객체는 종류, 하위 객체는 구체적 사물에 해당함
    • ex. 자동차(하위) - 기계(상위)

객체와 클래스

  • 클래스 = 설계도
  • 인스턴스 = 설계도(클래스)를 보고 만든 객체

흔히 클래스를 붕어빵 틀, 인스턴스를 붕어빵이라고들 한다.

클래스 선언

  • 클래스 이름은 식별자 작성 규칙에 따라 만들어야 함
    • 통상적으로 camelCase에 앞 글자를 대문자로 사용함(UpperCamelCase)

클래스이름.java 파일을 생성하고 클래스에 대한 코드를 작성한다.

public class Car{
} // 컴파일 하면 Car.class를 생성함
  • 하나의 소스 파일 당 여러 클래스를 선언하는 것도 가능함 → 클래스 수만큼 바이트 코드를 생성하고 컴파일하면 .class 를 클래스 개수만큼 생성하는 것

객체 생성과 클래스 변수

클래스로부터 객체를 생성하려면 new 연산자 사용해야 한다.

  • new : 클래스로부터 객체를 생성시키는 연산자, 힙 영역에 객체를 생성
    • 객체를 생성 후 주소를 반환 → 이를 클래스 변수에 저장하여 사용

자바의 객체 생성은 1) 클래스 변수 선언2) 변수에 인스턴스를 생성하여 저장하는 2개의 단계로 나뉜다.

Car a; // 1) 클래스 변수 a 선언
a = new Car(); // 2) 클래스 변수 a에 Car 클래스에 대한 인스턴스 생성 후 저장
  • 위 과정을 하나로 합쳐

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

    로 한 번에 클래스 변수 선언과 인스턴스 생성 및 저장을 할 수 있다.

실행 클래스와 라이브러리 클래스의 분리

  • 실행 클래스 : main을 호출하는 클래스
  • 라이브러리 클래스 : 다른 클래스에서 이용

클래스의 구성 멤버

public class ClassName {
    // 필드
    int fieldname;

    // 생성자
    ClassName() {...}

    // 메소드
    void methodName() {...}
}
  • 필드(Field) : 객체의 데이터를 저장
    • 변수와 비슷하지만 변수라고 부르지 않음
    • 생성자와 메소드 전체에서 사용되며 객체 소멸 시까지 존재
  • 생성자(Contructor) : 객체 생성 시 초기화 담당
    • new 연산자로 호출되는 블록
    • 클래스 이름이고 메소드와 유사한 형태지만 리턴값이 없음
  • 메소드(Method)
    • 객체 간의 데이터를 전달하는 수단

02 필드 Field

필드 : 객체의 정보를 저장하는 곳

필드 선언

  • 변수 선언 형태와 비슷함(클래스 멤버 변수 라고 부르기도 함)
  • 타입 필드 [ = 초기값]; [ ]는 생략 가능하다
    • 타입 : 기본, 참조 타입
    • 초기값 설정 안 하면 타입별 초기값이 저장됨(0, 0.0, false, null 등)

필드 사용

  • 클래스 내부에서 사용하는 경우 필드 이름으로 읽고 변경
  • 클래스 외부에서 사용하는 경우 객체를 생성한 뒤 필드를 사용해야 함
    • . 연산자 : 객체 접근 연산자, 객체의 필드나 메소드 사용 시 사용
    • ex. myCar.speed = 60; myCar 객체의 speed 필드에 60 저장

03 생성자 Constructor

생성자 : 객체 생성 시 초기화를 담당함

  • new 연산자로 호출되는 중괄호 블럭, 객체 생성 시 초기화 담당
  • 모든 클래스에 하나 이상 존재

기본 생성자

[public] 클래스() {}

  • 반드시 존재, 어떠한 생성자라도 작성하지 않으면 바이트 코드에 빈 생성자를 추가함
    • 생성자를 작성한 경우, 기본 생성자를 추가하지 않음
  • 클래스가 public class로 선언되면 생성자도 public이 붙고, 클래스에 public이 붙지 않으면 생성자에도 public이 붙지 않음

생성자 선언

클래스(매개변수 선언,...){
    객체 초기화 코드
}
  • 리턴 타입 없음, 클래스 이름과 동일
  • 객체 초기화 코드 : 일반적으로 필드에 초기값 저장, 메소드를 호출하여 객체 사용 전 준비

생성자 호출문을 보고 생성자 작성하기

Car myCar = new Car("그랜저", "검정", 300);

2개의 String, 2개의 int가 매개변수로 들어가므로 코드는 아래와 같다.

public class Car{
    Car(String model, String color, int maxSpeed){...}
}

필드 초기화

  • 필드 선언 시 초기값을 부여하는 경우
    • 객체 생성 시에는 모두 같은 필드 값을 갖는다
    • 외부 값을 사용할 수 없음
  • 생성자를 이용하여 초기값을 부여하는 경우
    • 클래스 외부의 값으로 필드 값을 초기화하는 경우, 생성자의 매개변수로 받아 필드 값에 저장
public class Korean {
    // 필드
    String nation = "대한민국";
    String name;
    String ssn;
    
    // 생성자
    public Korean(String n, String s) {
        name = n;
        ssn = s;
    }
}
  • 일반적으로는 외부 값을 매개변수로 받아 초기화하는 경우를 제외하고 생성자를 통해 필드를 초기화함

this

  • 객체 자신을 참조함
  • this.필드이름 은 필드이름과 같음
  • 일반적으로 필드와 매개변수를 같은 이름으로 사용하는데, 동일한 이름일 경우 매개변수에 우선순위가 있으므로 this 를 사용해 객체 필드임을 명시함
public Korean(String name, String ssn){
    this.name = name; // Korean의 name 필드에 매개변수 name을 저장함
    this.ssn = ssn;
}

생성자 오버로딩

  • 매개 변수가 다른 생성자를 여러개 선언하는 것
    • 다양한 방법으로 객체를 생성할 수 있도록 함
public class Car{
    Car() {...}
    Car(String model) {...}
    Car(String model, String color) {...}
}
  • 매개 변수가 같으면 오버로딩이 아님

다른 생성자 호출: this()

  • 매개 변수의 수만 다른 생성자가 많아지면 같은 코드가 중복됨 ⇒ 생성자에서 다른 생성자를 호출하는 것으로 중복을 줄일 수 있음
클래스([매개변수,...]){
    this(매개변수,...);
    실행문;
}
  • 반드시 생성자의 첫줄에서만 허용됨

ex. 중복 코드를 this로 줄이기

기존 코드
기존의 코드는 중복된 부분이 많아 비효율적이다.

Car(String model){
    this.model = model;
    this.color = "검정색";
    this.maxSpeed = 100;
}
Car(String model, String color){
    this.model = model;
    this.color = color;
    this.maxSpeed = 100;
}
Car(String model, String color, int maxSpeed){
    this.model = model;
    this.color = color;
    this.maxSpeed = maxSpeed;
}

수정된 코드
수정된 코드에서는 첫 번째, 두 번째 코드는 모두 세 번째 생성자를 호출한다.

Car(String model){
    this(model,"검정색",100); // 세 번째 생성자 호출
}
Car(String model, String color){
    this(model,color,100); // 세 번째 생성자 호출
}
Car(String model, String color, int maxSpeed){
    this.model = model;
    this.color = color;
    this.maxSpeed = maxSpeed;
}

04 메소드 Method

메소드 : 객체의 동작0

메소드 선언부

method signature라고도 한다.

리턴타입 메소드이름 (매개변수선언) {
    코드
}
  • 리턴 타입 : 메소드 실행 후 반환할 결과값
    • 반환값이 없는 경우 void로 작성함
    • ex. 전원을 켜는 powerOn()메소드는 반환값이 없지만 divide()메소드는 반환값이 나눗셈의 결과임

        powerOn(); // 반환값이 없으므로 그냥 호출
        double result = divide(10,5); // 나눗셈의 결과를 실수형으로 받기 위해 double형 변수 선언
      
    • 반환값이 중요하지 않은 경우 divide(10,5); 와 같이 반환값을 저장하지 않을 수도 있음
  • 메소드 이름 : camelCase로 작성하는것이 관례
  • 매개 변수 선언
    • divide를 예시로 하면

      double divide(int x, int y){...} 으로 int형 매개변수 2개를 받는다

      따라서 호출시 2개의 int값을 주어야 한다

      double result = divide(10,20);

매개 변수의 개수를 모르는 경우

  1. 매개 변수를 배열 타입으로 선언한다

    선언: int sum1(int[] values){...}

    호출: 배열을 넘겨준다

     // 1. 배열 변수를 넘기기
     int[] values = {1,2,3};
     int result = sum1(values);
     // 2. 배열 객체를 넘기기
     int result = sum1(new int[] {1,2,3});
    
  2. 을 사용해 매개변수를 선언한다

    선언: int sum2(int ... values){...}

    호출: 값을 쉼표로 나열한다

     int result = sum2(1,2,3);
    
    • 으로 선언된 매개 변수는 배열 타입이므로 위와 같이 배열을 매개변수로 사용해도 됨

return문

  • 메소드 선언에 반환 타입이 있으면 return문으로 반환값을 지정해야 한다.
  • return 반환값;
  • 같은 블럭 내 return문 이후의 코드는 실행되지 않음

반환값이 없는 void

  • 반환값 없음
  • return 을 사용해 메소드를 종료할 수 있음

메소드 호출

객체 내부에서는 메소드 이름만으로 호출하고 외부에서는 클래스를 통해 객체를 생성한 뒤 참조 변수를 이용해 메소드를 호출한다.

객체 내부에서 호출

  • 메소드 이름과 매개 변수에 맞게 호출한다.

    ex. Calculator 클래스의 println() 메소드를 호출하는 경우 그냥 println("메세지"); 로 호출

객체 외부에서 호출

  • 클래스로부터 객체를 생성하고, 참조 변수와 도트 연산자(.)로 메소드를 호출한다.

    ex. Car 클래스로부터 객체를 생성해 myCar라는 참조 변수로 run() 메소드를 호출할 때는 myCar.run();

메소드 오버로딩

  • 클래스 내의 동명의 메소드를 여러 개 선언하는 것
  • overload : 과적 = 하나의 메소드명으로 여러 기능을 하기에 붙여진 이름
  • 매개 변수의 타입, 개수, 순서 중 하나가 달라야 함
    • 매개 값을 다양하게 받을 수 있도록 함
    • 반환값만 다른 것은 메소드 오버로딩이 아님(JVM이 메소드를 선택하는 데 다른 도움울 주지 못하기 때문)

05 인스턴스 멤버과 정적 멤버

객체마다 동일한 필드값을 가질 경우, 모든 객체마다 같은 필드 값을 갖고 있게 하므로 메모리 낭비가 발생한다. 이를 해결하기 위해서, 객체마다 동일한 값을 갖는 필드는 클래스에 저장하여 공유하도록 둘 수 있다.

자바에서는 클래스 멤버(필드, 메소드)를 객체가 갖는 인스턴스 멤버와 클래스가 갖고 있는 정적 멤버로 나누었다.

인스턴스 멤버

인스턴스 멤버 : 인스턴스 생성 후 사용할 수 있는 필드 & 메소드, 각각 인스턴스 필드, 인스턴스 메소드라고 한다.

인스턴스 멤버 선언

public class Car {
    //필드
    int gas;
    
    //메소드
    void setSpeed(int speed) {...}
}

Car 클래스의 필드와 메소드는 인스턴스 멤버이므로 사용하려면 객체를 생성해야 한다.

Car myCar = new Car(); // Car 객체 생성
myCar.gas = 10;
myCar.setSpeed(10);

Car yourCar = new Car();
yourCar.gas = 20;
yourCar.setSpeed(20);

인스턴스 멤버는 힙 영역에서 각각의 Car 객체 안에 저장된다.

인스턴스 메소드는 객체 밖 메소드 영역에 따로 저장된다.

this

객체 내부에서 인스턴스 멤버에 접근할 수 있다.

생성자와 메소드의 매개변수 이름이 동일한 경우 사용한다.

Car(String model){
    this.model = model;
}
void setModel(String model){
    this.model = model;
}

정적 멤버와 static

정적 : 고정된

정적 멤버 : 객체를 생성하지 않고 사용할 수 있는 필드 & 메소드, 각각 정적 필드, 정적 메소드라고 한다.

정적 멤버 선언

선언 시 static 키워드를 붙인다.

public class Car{
    // 정적 필드 초기값은 생략가능하다
    static int gas = 10;
    
    // 정적 메소드
    static void setSpeed(int speed){...}
}
    

선언 기준

  • 필드
    • 객체마다 가지고 있어야 하는 값은 인스턴스 필드
    • 클래스 공통의 값이면 정적 필드
  • 메소드
    • 인스턴스 필드를 포함하면 인스턴스 메소드
    • 인스턴스 필드를 포함하지 않으면 정적 메소드

정적 멤버 사용

정적 멤버는 클래스가 로드되면 사용할 수 있다.

클래스.필드;
클래스.메소드(매개값);

정적 멤버 사용 주의사항

  • 정적 멤버는 객체 생성 없이도 사용할 수 있다.
  • 정적 메소드 안에 인스턴스 필드 & 메소드 사용 불가
  • 객체 자신을 참조하는 this 사용 불가
  • 정적 메소드에서 인스턴스 멤버를 사용하기 위해서는 인스턴스를 생성한 후 참조해야 한다.

main 함수도 정적 메소드 이므로(public static void main) 인스턴스 멤버를 사용하기 위해서는 객체를 생성한 뒤 참조해야 한다.

public static void main(String[] args){
    Car mycar = new Car();
    myCar.speed = 10;
    myCar.run();
}

싱글톤

프로그램에서 단 하나의 객체만 만들도록 보장해야할 때, 이 객체를 싱글톤이라고 한다.

싱글톤 생성 방법

  • 클래스 외부에서 new 연산자 호출을 막아야 함
  • 생성자를 외부에서 호출할 수 없도록 생성자 앞에 private 접근 제한자를 붙임
public class Car {
    // 정적 필드, 자신의 객체를 생성해 초기화한다
    private static Car singleton = new Car();
    
    // 생성자
    private Car() {}
    
    // 정적 메소드, 정적 필드 값을 반환하도록 한다
    static Car getInstance() {
        return singleton;
    }
}
  1. private 생성자를 통해 외부에서 객체 생성을 차단
  2. static 필드를 통해 하나의 객체를 유지하며
  3. static 메서드로 객체를 반환

외부에서 객체를 얻는 방법은 정적 메소드를 호출하는 것뿐이다. 정적 필드에서 객체를 생성해 초기화했으므로 하나의 객체만 반환한다. 따라서, 여러 개의 Car 클래스 변수를 선언해도 같은 객체 하나만을 참조한다.

Car myCar = Car.getInstance();
Car yourCar = Car.getInstance();

여기서 위의 myCar와 yourCar는 같은 객체를 참조한다.

final 필드

final : 프로그램 실행 도중 수정할 수 없음

final 필드를 초기화하는 방법

  1. 필드 선언 시 값을 저장하기
  2. 생성자에서 값을 저장하기, 외부 값을 받아 초기화하는 경우 이 방법을 사용한다.

final 필드를 초기화하지 않으면 컴파일 에러가 발생한다

상수

변하지 않는 값인 상수는 객체마다 여러 값을 가질 필요가 없다.(static) 또한, 프로그램 실행 도중 값이 변할 필요도 없다.(final) 따라서 상수는 static final을 사용한다.

static final double PI = 3.14159;
  • 모두 대문자로 작성하고, 띄어쓰기는 _ 로 표기한다.
  • static 이므로 클래스에만 존재한다.
  • final 이므로 값이 변하지 않는다.

06 패키지와 접근 제한자

자바에서는 클래스를 관리하기 위해 패키지를 사용한다.

패키지는 물리적인 형태로는 폴더로 존재하는데, 클래스를 유일하게 만드는 식별자 역할을 한다.

클래스명이 동일하더라도 패키지가 다르면 다른 클래스로 인식하는데, 클래스 전체 이름이 상위패키지.하위패키지.클래스 로 구분하기 때문이다.

패키지 선언

클래스가 어떤 패키지에 속하는지 선언하는 것을 패키지 선언이라고 한다.

package 상위패키지.하위패키지;

public class 클래스이름 { ... }

Image

예를 들어 위 사진처럼 Member 클래스가 있다면

package so.dohyunk58.springbootstudy;
public class Member { ... }

로 클래스가 시작된다.

클래스만 따로 이동한다면 그 클래스를 사용할 수 없다. 만약 클래스를 이동해야한다면, 패키지 전체를 이동시켜야 한다.

import문

클래스나 인터페이스가 다른 패키지 소속이라면 import문으로 가져와 사용할 수 있다.

import 상위패키지.하위패키지.클래스이름;
import 상위패키지.하위패키지.*;

여러 클래스들이 동일한 패키지 소속이면 * 을 사용한다.

주의사항

상위패키지를 import해도 하위패키지가 import되는 것이 아님

import com.hankook.*;
import com.hankook.project.*;

따라서 위의 코드처럼 hanbook의 모든 클래스를 import해도 그 하위패키지인 project의 클래스를 사용하려면 두 번째 코드처럼 하위 패키지를 import 해야 한다.

패키지는 다르지만 클래스 이름이 동일한 경우 import하는 방법

// com.a의 Tire와 com.b의 Tire가 있는 경우
...
import com.a;
import com.b;
public class Car{
    com.a.Tire tire1 = new com.a.Tire();
    com.b.Tire tire2 = new com.b.Tire();
}

접근 제한자

클래스/인터페이스와 이들의 멤버로의 접근을 제한할 수 있다.

아래는 접근 제한자의 종류이다.

image.png

접근 제한자 설명
public 외부 클래스가 자유롭게 사용 가능
protected 같은 패키지 or 자식 클래스에서 사용 가능
private 외부에서 사용할 수 없음
default 위의 접근 제한자가 없으면 적용됨, 같은 패키지에서만 사용 가능

클래스의 접근 제한

클래스를 같은 패키지나 다른 패키지에서 접근 가능하도록 default, public 등을 선언할 수 있다.

생성자의 접근 제한

new 연산자로 생성자를 호출할 때의 접근 제한을 설정할 수 있다.

접근제한자 클래스이름() {...} 으로 생성자에 접근 제한자를 붙일 수 있다.

아래는 생성자에 붙이는 접근 제한자의 종류이다.

  • public : 모든 패키지에서 생성자 호출
  • default : 같은 패키지에서만 생성자 호출 가능
  • protected : 같은 패키지 및 자신 클래스에서 생성자 호출 가능
  • private : 오직 클래스 내부에서만 생성자 호출 가능

필드와 메소드의 접근 제한

필드와 메소드도 동일하게 4개의 접근 제한자를 가질 수 있다.

아래 코드처럼 앞부분에 접근 제한자를 붙여서 사용한다.

//필드
접근제한자 [static] 타입 필드;
// 메소드
접근제한자 [static] 리턴타입 메소드() {}

Getter & Setter

객체지향 프로그래밍에서는 객체 필드를 외부에서 접근하는 것을 막는다.(private)

따라서 외부에서 값을 설정하거나 불러올때 메소드를 사용한다. 이때, 값을 설정하는 메소드를 setter, 값을 불러오는 메소드를 getter라고 한다.

setter의 예시로, 속력을 음수로 설정할 수 없도록 setSpeed() 메소드를 생성할 경우, 아래와 같이 조건을 붙여 필드 값을 설정할 수 있다.

void setSpeed(double speed){
    if(speed < 0){
        this.speed = 0;
        return;
    } else {
        this.speed = speed;
    }
}

getter의 에시로, 속력을 마일에서 km로 환산해서 반환하는 메서드를 생성할 수 있다.

double getSpeed(){
    double km = speed*1.6;
    return km;
}

추가로, 반환값이 boolen인 경우 getter는 is로 시작하는 것이 관례이다.

ex. public boolean isStop() { return stop; }

숙제 01 중요 용어 정리하기

💡 어렵거나 중요하다고 생각하는 용어를 혼공 용어 노트에 정리하고 공유하기

혼공자바에는 혼공 용어 노트라는 작은 용어집이 있다. 이곳에 챕터별로 중요한 용어가 정리되어 있는데, 그중에서 이번 6장을 공부하며 어려웠던 단어 몇 가지를 정리해보고자 한다. 용어 노트에 적는 것은 칸이 너무 작아서 이 블로그를 활용하고자 한다.

싱글톤

싱글톤이라는 단어는 디자인패턴에 대해 검색하다가 찾아본 적이 있다. 애용하는 인터넷 사이트인 리팩터링 구루에서 설명하는 싱글톤 패턴과 더불어 객체 지향 프로그래밍(OOP)에 대해서도 정리할 것이다.

혼공자바에서는 싱글톤을 전체 프로그램에서 하나의 클래스에 단 하나의 객체(인스턴스)만 만들도록 보장해야하는 상황에서 생성된 객체라고 설명한다. 생성자가 호출되는 만큼 객체가 생성되기 때문에 new 연산자로 생성자를 호출할 수 없도록 생성자 앞에 private을 붙여 막고, 필드에 자기 자신의 객체를 static으로 선언하여 구현한다.

public class Car {
    // 정적 필드, 자신의 객체를 생성해 초기화한다
    private static Car singleton = new Car();
    
    // 생성자
    private Car() {}
    
    // 정적 메소드, 정적 필드 값을 반환하도록 한다
    static Car getInstance() {
        return singleton;
    }
}

리팩터링 구루에서는 싱글톤을 다음과 같이 소개한다.

싱글턴은 클래스에 인스턴스가 하나만 있도록 하면서 이 인스턴스에 대한 전역 접근​(액세스) 지점을 제공하는 생성 디자인 패턴입니다.

그리고 싱글톤이 전역 변수와 같이 전역 접근을 제공하지만, 다른 코드가 인스턴스를 덮어쓰지 못하도록 보호할 수 있다고 한다.

싱글톤 패턴을 적용하는 사례는 다음과 같다.

  1. 클래스에 모든 클라이언트가 사용할 수 있는 단일 인스턴스만 있어야 할 때 (ex. 프로그램 내에서 공유되는 하나의 데이터베이스 객체)
  2. 전역 변수를 엄격하게 제어해야 할 때

오버로딩

오버로딩의 사전적 의미는 과적으로, 프로그래밍에서는 하나의 메소드 이름으로 여러 기능을 담는 것을 의미한다. 메소드 오버로딩과 생성자 오버로딩이 있는데, 이중 메소드 오버로딩은 매개변수의 타입, 개수, 순서 중 하나가 달라야 한다. 생성자 오버로딩은 매개 변수가 다른 생성자를 여러 생성하는 것이다.

지금은 간단해보이지만 7장에서 배울 오버라이딩과는 전혀 다른 뜻을 가지고 있다. 오버라이딩을 배우기 전에 오버로딩에 대해서 정확히 이해하고 가는 것이 중요하다.

숙제 02 OOP 개념에 대해서 정리하기

💡 객체 지향 프로그래밍 OOP의 개념 정리하기

객체 지향 프로그래밍은 데이터를 객체라는 것으로 정의하고, 그 객체들은 클래스라는 객체의 설계도에 의해 구성되는 체계이다.

객체-클래스에 대한 예시

객체와 클래스에 관한 예시 중 가장 유명한 것 중 하나는 붕어빵일 것이다. 붕어빵 틀은 붕어빵을 만들 수 있는 설계도이다. 따라서 붕어빵 틀은 클래스라고 할 수 있다. 붕어빵은 붕어빵 틀에서 만들어지는 물건으로 객체라고 할 수 있다. 붕어빵 틀에서 붕어빵을 여러 개 만들 수 있듯, 클래스를 통해 객체를 여러 개 만들어 낼 수도 있다.

클래스의 계층 구조

클래스는 계층 구조를 가질 수 있다.

클래스 예시

예를 들어, 개라는 클래스와 고양이라는 클래스가 있을 때, 두 클래스는 모두 숨을 쉬거나, 네 발로 걷거나, 잠을 자는 등의 공통점이 있다. 따라서, 두 클래스의 공통점을 모은 기초 동물 클래스를 정의한 다면, 동물 클래스 아래에 개 클래스와 고양이 클래스가 존재할 수 있다.

추상화나 하위 클래스의 기능 구체화 같은 경우 7장 상속에서 더 깊이 다룰 예정이므로 이 이상 깊이 객체와 클래스 관계를 설명하지는 않을 것이다. 다만, 클래스와 위와 같이 계층을 이룰 수 있다는 점을 미리 생각해두고 7장에 진입하면 한결 이해가 쉬울 것이다.

카테고리:

업데이트: