본문 바로가기

개발공부/Java

패스트캠퍼스 환급챌린지 18일차 : 한 번에 끝내는 컴퓨터 공학 & 인공지능 복수전공 초격차 패키지 강의 후기

반응형

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

CH 3. 객체와 클래스 이해하기

 

자바 객체 지향 프로그래밍의 핵심: 클래스, 객체, 상속, 그리고 메소드 오버라이딩 🚀

 

1. 객체 지향 프로그래밍(OOP)이란?

객체 지향 프로그래밍(OOP)은 소프트웨어 시스템에서 데이터를 다루는 데 초점을 맞춘 프로그래밍 패러다임입니다. OOP의 핵심은 객체(Objects)라는 개념에 기반하며, 이 객체는 데이터(fields, attributes, properties)와 해당 데이터를 조작하는 코드(procedures, methods)를 함께 포함할 수 있습니다.

 

OOP는 현실 세계의 사물과 개념을 소프트웨어로 모델링하는 데 매우 효과적입니다. 예를 들어, '고객'이라는 객체는 '이름', '전화번호', '이메일'과 같은 데이터를 가질 수 있고, '주문하기', '정보 수정하기'와 같은 행동(메소드)을 수행할 수 있습니다.


2. 클래스와 객체의 구성: 설계도와 실체 

자바에서 클래스(Class)는 객체를 만들기 위한 설계도 또는 템플릿과 같습니다. 클래스는 객체가 가져야 할 데이터(멤버 변수)와 행동(메소드)을 정의합니다. 객체(Object)는 이 클래스를 바탕으로 생성된 실제 '인스턴스'입니다.

2.1. 클래스의 기본 구성 요소

클래스는 일반적으로 다음 요소들로 구성됩니다.

  • 멤버 변수(Member Variables / Fields): 객체의 상태(데이터)를 나타냅니다. 클래스 내부에 선언되며, 객체가 가질 수 있는 속성들을 정의합니다. 예를 들어,
  • Customer 클래스에는 name, number, email과 같은 멤버 변수가 있을 수 있습니다.
  • 생성자(Constructor): 객체를 생성할 때 호출되는 특별한 종류의 메소드입니다. 생성자는 새 객체를 사용할 준비를 하며, 종종 필수 멤버 변수를 설정하는 데 사용되는 인수를 받습니다.
  • 메소드(Methods): 객체의 행동을 나타냅니다. 특정 작업을 수행하는 코드 블록으로, 객체의 데이터를 조작하거나 다른 작업을 수행합니다. 예를 들어,
  • Customer 클래스에는 getName(), getNumber(), getEmail()과 같은 메소드가 있을 수 있습니다.

Customer 클래스 예시:

public class Customer {
    // 멤버 변수 (Fields) - 고객의 속성
    private String name;    // 고객 이름
    private String number;  // 전화번호
    private String email;   // 이메일

    // 생성자 (Constructor) - Customer 객체를 생성할 때 호출
    public Customer(String name, String number, String email) { // [cite: 479]
        this.name = name;   // this 키워드는 현재 객체를 지칭 [cite: 559]
        this.number = number;
        this.email = email;
    }

    // 멤버 메소드 (Methods) - 고객 객체의 행동
    public String getName() { // [cite: 482]
        return name;
    }

    public String getNumber() {
        return number;
    }

    public String getEmail() {
        return email;
    }

    // 편의 메소드: 고객 정보 출력 (나중에 toString() 오버라이딩으로 대체 가능)
    public void printCustomerInfo() {
        System.out.println("고객 이름: " + this.name + ", 전화번호: " + this.number + ", 이메일: " + this.email);
    }
}

2.2. 객체 생성 및 활용

클래스를 정의했다면, 이제 이 클래스를 이용해 실제 객체를 만들고 사용할 수 있습니다.

public class CustomerApp {
    public static void main(String[] args) {
        // Customer 클래스를 이용하여 customer1 객체 생성
        Customer customer1 = new Customer("김철수", "010-1234-5678", "kim@example.com"); // [cite: 616]

        // customer1 객체의 메소드 호출하여 정보 가져오기 및 출력
        System.out.println("고객 1 이름: " + customer1.getName());
        customer1.printCustomerInfo();

        // 전화번호 대신 이메일로 소통하고 싶은 고객 (메소드 오버로딩 또는 다른 생성자 사용 가능)
        // 새로운 Customer 객체 생성 시 이메일만 제공하는 생성자도 만들 수 있습니다.
        Customer customer2 = new Customer("이영희", null, "lee@example.com"); // 전화번호는 null [cite: 567]
        customer2.printCustomerInfo();
    }
}

2.3. 캡슐화와 접근 제어 

캡슐화(Encapsulation)는 OOP의 중요한 원칙 중 하나로, 데이터(멤버 변수)와 이 데이터를 다루는 메소드를 하나로 묶는 것을 의미합니다. 또한, 외부 코드에서 객체의 내부 작동에 직접 접근하는 것을 제한하여 데이터의 무결성을 보호합니다. 이는 "쓰기 쉽고 부작용을 줄이는" 코드를 만드는 데 기여합니다.

자바는 접근 제어자(Access Modifier)를 통해 캡슐화를 구현합니다.

Modifier Class (클래스 내) Package (패키지 내) Subclass (하위 클래스) World (전체)
public Y Y Y Y
protected Y Y Y N
(default) Y Y N N
private Y N N N
 
  • public: 어디서든 접근 가능합니다.
     
  • protected: 같은 패키지 내 또는 상속 관계에 있는 하위 클래스에서 접근 가능합니다.
     
  • default (package-private): 아무런 접근 제어자를 지정하지 않으면 기본적으로 같은 패키지 내에서만 접근 가능합니다.
     
  • private: 해당 클래스 안에서만 접근 가능합니다.

일반적으로 멤버 변수는 private으로 선언하여 외부에서 직접 접근을 막고, public 메소드(게터/세터)를 통해 간접적으로 접근하도록 하여 캡슐화를 유지합니다.


3. 상속(Inheritance): 코드 재사용의 강력한 도구 

상속(Inheritance)은 객체 지향 프로그래밍에서 한 객체 또는 클래스가 다른 객체 또는 클래스를 기반으로 하여 유사한 구현을 유지하는 메커니즘입니다. 이는 부모-자식 관계를 형성하여 코드를 재사용하고 확장하는 데 도움을 줍니다.

자바의 모든 클래스는 java.lang.Object 클래스를 암묵적으로 상속받습니다. Object 클래스는 모든 객체의 최상위 계층이며, 모든 객체는 이 클래스의 메소드를 구현합니다.

상속 예시: Animal과 Dog

  • Animal 클래스 (부모 클래스 또는 슈퍼클래스)는 move(), eat()과 같은 일반적인 동물의 행동을 정의할 수 있습니다.
  • Dog 클래스 (자식 클래스 또는 서브클래스)는 Animal 클래스를 상속받아 move()와 같은 행동을 물려받고, bark()와 같은 개만의 고유한 행동을 추가할 수 있습니다.
// 부모 클래스 (Superclass)
class Animal {
    public void move() {
        System.out.println("동물이 움직입니다.");
    }

    public void eat() {
        System.out.println("동물이 먹이를 먹습니다.");
    }
}

// 자식 클래스 (Subclass) - Animal을 상속받음
class Dog extends Animal {
    public void bark() {
        System.out.println("개가 멍멍 짖습니다.");
    }
}

public class InheritanceExample {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.move(); // Animal 클래스에서 상속받은 move() 메소드 호출
        myDog.eat();  // Animal 클래스에서 상속받은 eat() 메소드 호출
        myDog.bark(); // Dog 클래스 자체의 bark() 메소드 호출
    }
}

4. 메소드 오버라이딩 (Method Overriding): 부모의 행동을 재정의 

메소드 오버라이딩(Method Overriding)은 객체 지향 프로그래밍의 한 기능으로, 하위 클래스(자식 클래스)가 이미 상위 클래스(부모 클래스)에 의해 제공된 메소드의 특정 구현을 제공하도록 허용합니다. 즉, 부모 클래스로부터 상속받은 메소드의 동작을 자식 클래스에서 자신의 필요에 맞게 변경하는 것을 말합니다.

java.lang.Object 클래스의 toString() 메소드는 모든 객체가 문자열 표현을 가질 수 있도록 기본 구현을 제공합니다. 하지만 이 기본 구현은 객체의 메모리 주소 등을 반환하므로, 객체의 실제 내용을 파악하기 어렵습니다. 이때 toString() 메소드를 오버라이딩하여 객체의 유용한 정보를 문자열로 반환하도록 만들 수 있습니다.

@Override 어노테이션:

자바에서 어노테이션(Annotation)은 자바 소스 코드에 추가될 수 있는 구문 메타데이터(syntactic metadata)의 한 형태입니다. 클래스, 메소드, 변수, 매개변수 및 자바 패키지에 애노테이션을 달 수 있습니다.

@Override 애노테이션은 컴파일러에게 "이 메소드는 상위 클래스의 메소드를 오버라이딩하는 것"임을 알려주는 역할을 합니다. 이는 오버라이딩 규칙을 제대로 지켰는지 검사하여 오류를 줄이는 데 도움을 줍니다.

메소드 오버라이딩 예시: toString() 메소드

Customer 클래스에서 Object 클래스로부터 상속받은 toString() 메소드를 오버라이딩하여 고객 정보를 보기 좋게 출력하도록 변경해 봅시다.

// Customer 클래스 (이전 예제에서 이어짐)
public class Customer {
    private String name;
    private String number;
    private String email;

    public Customer(String name, String number, String email) {
        this.name = name;
        this.number = number;
        this.email = email;
    }

    // @Override 애노테이션을 사용하여 toString() 메소드 재정의
    @Override // [cite: 185]
    public String toString() { // [cite: 186, 188]
        return "고객 정보: [이름: " + name + ", 전화번호: " + number + ", 이메일: " + email + "]";
    }

    // 다른 getter 메소드들... (생략)
    public String getName() { return name; }
    public String getNumber() { return number; }
    public String getEmail() { return email; }
}

public class OverrideExample {
    public static void main(String[] args) {
        Customer customer = new Customer("박지민", "010-7777-8888", "park@example.com");

        // 오버라이딩된 toString() 메소드 호출
        System.out.println(customer.toString());
        // 또는 객체를 직접 출력해도 toString()이 자동 호출됨
        System.out.println(customer);

        // 만약 부모 클래스(Object)의 toString() 결과를 보고 싶다면 super 키워드를 사용합니다.
        // public String toString(){ return super.toString(); } [cite: 230]
    }
}

이제 Customer 객체를 System.out.println()으로 출력하면 우리가 정의한 형식으로 고객 정보가 나타납니다.

4.1. super 키워드: 부모 클래스 멤버 접근

super 키워드는 하위 클래스에서 상위 클래스의 멤버(변수 또는 메소드)에 접근할 때 사용됩니다. 예를 들어, 오버라이딩된 메소드 내에서 부모 클래스의 원래 메소드를 호출하고 싶을 때 super.메소드이름() 형태로 사용합니다.


5. 정리

  • 클래스는 객체의 설계도이며, 객체는 그 설계도를 통해 만들어진 실제 인스턴스입니다.
  • 캡슐화는 데이터와 메소드를 묶고 외부 접근을 제어하여 코드의 안정성을 높입니다.
  • 상속은 코드 재사용성을 높여 개발 시간을 단축하고 유지보수를 용이하게 합니다.
  • 메소드 오버라이딩은 상속받은 메소드의 동작을 자식 클래스에서 재정의할 수 있게 하여 다형성(Polymorphism)을 구현하는 기초가 됩니다.

 

오늘의 실습

오늘의 느낀점

오버로딩과 오버라이딩의 차이! 오늘 드디어 오버라이딩을 다시 봤다. 확실히 처음배울때랑 한참 자바를 써보고 다시 한 번 정리하는 느낌이 다르다. 차곡차곡 지식이 다시 한번 쌓이는 느낌!

 

 

https://fastcampus.info/4n8ztzq

 

(~6/20) 50일의 기적 AI 환급반💫 | 패스트캠퍼스

초간단 미션! 하루 20분 공부하고 수강료 전액 환급에 AI 스킬 장착까지!

fastcampus.co.kr

 

반응형