Java

Java - 문자자료형 공부 / 자료형과 형변환 casting / 새로운 자료형의 필요성 / 객체와 클래스에 대한 공부 /

wy-family 2024. 11. 21. 00:37

 char - 문자자료형! 문자를 숫자로 맵핑을 해놨다. - 이걸 수치형자료라고도 함.

그래서 이런게 가능함.

char c = 'A';

라고 해서 c 를 출력하면 A 가 나온다.

그런데,

'A' 는 문자인데,

int a = 'A';

라고 하면 말이 되는가?

정수형과 문자형은 자료형이 다른데?

하지만, 'A' 는 아스키코드라고 문자랑 숫자로 맵핑을 해놓았어서,

'A'에 해당하는 65 이라는 숫자가 있다.

그래서

int a = 'A' 라고 하면, a 에 'A' 를 저장(할당)하는게 아니라, 65 을 저장하는 것.

그래서 a 를 출력하면, 아스키코드 수치인 65가 출력된다.

 

그리고 int b = 'B' + 1;

이것도 가능하다. b 를 출력하면 66 + 1 이라서 67이 출력된다.

 

 

 

 

그 문자-숫자 표가 아스키코드에 있다. ASCII

그런데 한국어나 일본어처럼 영어가 아닌 언어도 표현을 하기 위해서

유니코드 Unicode, UTF8 이라는 게 있음.

 


Book b;   // 변수 선언,  메모리에 b 라는 기억 공간이 생김.

new Book();    // 객체 생성,  메모리에 새롭게 객체를 만듦. 실체를 만듦. 실체 = instance // new 는 생성연산자 

b = new Book();   // 생성된 객체를 연결(저장)하는데, b 라는 기억 공간에 생성된 객체 정보를 집어넣는게 아니다.

 

생성된 객체 정보는 여러 가지 정보를 담고 있다. 선언된 변수 b 는 기억 공간 1개만 있다.

그래서 b 가 담아내고 있는 건, 생성된 객체 정보의 번지 정보 (위치 정보) 를 가리키고 있는 것.

b.title = "자바"

라고 할 때, 저 . (점 dot) 이 참조 연산자라고 해서, b 가 가리키고 있던 정보에서 title에 해당하는 곳에 "자바"라는 값을 저장하겠다~~ 라는 뜻.

 

 


casting 형변환에 대해서 설명해줄래?
Java에서 **Casting(형변환)**이란 데이터를 한 데이터 타입에서 다른 데이터 타입으로 변환하는 것을 의미합니다. 이는 주로 서로 다른 데이터 타입 간의 값을 다룰 때 발생하며, 자동 형변환명시적 형변환으로 나눌 수 있습니다.

1. 자동 형변환 (Implicit Casting)

Java에서 작은 데이터 타입이 더 큰 데이터 타입으로 변환될 때 자동으로 수행됩니다.
이 과정에서는 데이터 손실이 없기 때문에 별도의 명시가 필요하지 않습니다.

특징:

  • 작은 타입 → 큰 타입
  • 안전한 변환 (데이터 손실 없음)

예시:

int a = 10;
double b = a; // int → double로 자동 형변환
System.out.println(b); // 출력: 10.0
 

자동 형변환 가능한 순서:

byte → short → int → long → float → double

2. 명시적 형변환 (Explicit Casting)

큰 데이터 타입에서 작은 데이터 타입으로 변환하려면 명시적으로 형변환을 수행해야 합니다.
이 경우 데이터 손실이나 부정확한 값이 발생할 수 있으므로 주의해야 합니다.

형식:

타겟_타입 변수명 = (타겟_타입) 기존_변수명;

특징:

  • 큰 타입 → 작은 타입
  • 데이터 손실 가능성 존재
  • 명시적으로 (타겟_타입)을 사용해야 함

예시:

 
double a = 9.78;
int b = (int) a; // double → int로 명시적 형변환
System.out.println(b); // 출력: 9 (소수점 이하 잘림)

3. 객체 형변환 (Object Casting)

객체 형변환은 상속 관계에 있는 클래스에서 사용됩니다. 주로 업캐스팅(Upcasting)과 다운캐스팅(Downcasting)으로 나뉩니다.

(1) 업캐스팅 (Upcasting)

  • 자식 클래스 → 부모 클래스
  • 자동으로 수행되며, 명시적 형변환이 필요 없음.

예시:

class Animal {}
class Dog extends Animal {}

Animal animal = new Dog(); // 업캐스팅 (자동 수행)
 

(2) 다운캐스팅 (Downcasting)

  • 부모 클래스 → 자식 클래스
  • 명시적 형변환이 필요하며, 형변환 실패 시 ClassCastException이 발생할 수 있음.

예시:

Animal animal = new Dog();
Dog dog = (Dog) animal; // 다운캐스팅 (명시적 형변환)

4. 형변환 시 주의사항

  • 데이터 손실: 명시적 형변환에서 큰 타입을 작은 타입으로 변환할 때 데이터 손실 가능성.
  • ClassCastException: 객체 다운캐스팅이 잘못되었을 경우 발생.
  • instanceof 연산자 사용: 다운캐스팅 전에 객체의 실제 타입을 확인하는 것이 좋음.

예시:

if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
} else {
    System.out.println("다운캐스팅 불가능");
}

아스키코드에 대해서 배웠어. char 과 int 사이의 casting 에 대해서 설명해줄래?
Java에서 char와 int 간의 형변환은 아스키코드를 기반으로 이루어집니다.

char는 내부적으로 유니코드(UTF-16)로 저장되며, 이는 숫자로 표현될 수 있기 때문에 int로 변환이 가능합니다. 반대로, 정수(int)를 문자(char)로 변환할 때는 해당 숫자가 유니코드 표의 문자로 변환됩니다.


1. char → int (문자에서 숫자로 변환)

char 타입을 int로 변환하면 해당 문자의 유니코드 값(아스키코드 포함)을 얻습니다.

예시:

char ch = 'A'; // 'A'의 유니코드 값: 65
int num = (int) ch; // 명시적 형변환
System.out.println(num); // 출력: 65
 

자동 형변환:

char는 내부적으로 숫자로 표현되기 때문에 명시적 형변환 없이도 자동 형변환됩니다.

char ch = 'a';
int num = ch; // 자동 형변환
System.out.println(num); // 출력: 97 ('a'의 유니코드 값)

2. int → char (숫자에서 문자로 변환)

정수 값을 char로 변환하면 해당 유니코드 값을 가지는 문자가 반환됩니다.

예시:

int num = 65;
char ch = (char) num; // 명시적 형변환 필요
System.out.println(ch); // 출력: A
 

3. 응용: 아스키코드의 활용

(1) 문자 연산:

char를 int로 변환하여 계산한 뒤 다시 char로 변환하면 원하는 결과를 얻을 수 있습니다.

 
char ch = 'A';
ch = (char) (ch + 1); // 'A'의 유니코드 값 65 + 1 = 66 ('B')
System.out.println(ch); // 출력: B

(2) 문자-숫자 차이 계산:

문자들 간의 유니코드 값 차이를 계산할 수 있습니다.

char ch1 = 'a';
char ch2 = 'A';
int diff = ch1 - ch2; // 97 - 65 = 32
System.out.println(diff); // 출력: 32
 

(3) 숫자를 문자로 변환:

숫자를 문자로 변환:

 
int digit = 5;
char ch = (char) (digit + '0'); // '0'의 유니코드 값 48
System.out.println(ch); // 출력: 5

4. char와 int 형변환에서 주의사항

1. 유효 범위 확인:

  • char는 0~65535의 범위를 가지므로, int에서 char로 변환 시 범위를 초과하는 값은 이상한 문자가 될 수 있습니다.
int num = 70000;
char ch = (char) num;
System.out.println(ch); // 예측 불가능한 결과

2. 음수 처리:

  • char는 음수를 표현할 수 없으므로, 음수를 변환하려 하면 이상한 결과가 나옵니다.
int num = -1;
char ch = (char) num;
System.out.println(ch); // 이상한 문자 출력

casting이 안 되는 것도 있어?
Java에서는 **형변환(casting)**이 불가능하거나 제한된 경우가 있습니다. 형변환은 데이터 타입 간의 변환 규칙에 따라 이루어지기 때문에, 타입 간 호환성이 없으면 형변환이 허용되지 않습니다. 아래에서 형변환이 불가능하거나 제한적인 상황을 설명하겠습니다.

1. 완전히 호환되지 않는 타입 간 형변환

서로 완전히 다른 데이터 타입은 형변환이 불가능합니다. 예를 들어, 기본 데이터 타입과 참조 타입 간에는 직접적인 형변환이 안 됩니다.

예시:

int a = 100;
String str = (String) a; // 불가능: 기본 타입과 참조 타입 간 형변환 불가

해결 방법:

  • 기본 타입을 참조 타입으로 변환하려면 Wrapper 클래스를 사용하거나, 문자열 변환 메서드(String.valueOf())를 사용합니다.
int a = 100;
String str = String.valueOf(a); // 올바른 변환

2. 상속 관계가 없는 클래스 간 형변환

두 클래스가 상속 관계에 있지 않다면 객체 간 형변환은 불가능합니다.

예시:

class Animal {}
class Car {}

Animal animal = new Animal();
Car car = (Car) animal; // 불가능: 상속 관계가 없음

해결 방법:

  • 상속 관계를 통해 형변환을 지원하도록 설계해야 합니다.

3. 잘못된 다운캐스팅

다운캐스팅은 부모 클래스의 객체를 자식 클래스 타입으로 변환하는 작업인데, 객체가 실제로 자식 클래스의 인스턴스가 아닐 경우 형변환이 실패합니다.

예시:

class Animal {}
class Dog extends Animal {}

Animal animal = new Animal();
Dog dog = (Dog) animal; // 불가능: Animal은 Dog의 인스턴스가 아님

해결 방법:

  • instanceof를 사용해 객체 타입을 확인한 후 형변환해야 합니다.
if (animal instanceof Dog) {
    Dog dog = (Dog) animal; // 안전한 다운캐스팅
} else {
    System.out.println("형변환 불가");
}

4. 기본 타입 간 불가능한 형변환

서로 호환되지 않는 기본 데이터 타입 간에는 형변환이 불가능합니다.

예시:

  • boolean ↔ 다른 기본 타입 간의 형변환은 불가능합니다.
boolean flag = true;
int num = (int) flag; // 불가능
  • char ↔ boolean 형변환도 불가능합니다.
char ch = 'A';
boolean flag = (boolean) ch; // 불가능

5. 런타임 시 실패할 수 있는 경우

형변환 자체는 컴파일러에서 통과하지만, 런타임 시 실패하는 경우도 있습니다.

예시:

Object obj = "Hello";
Integer num = (Integer) obj; // 컴파일은 되지만 런타임 시 ClassCastException 발생

형변환이 불가능한 경우 대처 방법

  1. 호환성을 확인:
    • 참조 타입에서는 instanceof로 타입을 확인.
    • 기본 타입 간에는 명시적 형변환 또는 Wrapper 클래스를 사용.
  2. 의도한 변환 수행:
    • 기본 타입을 문자열로 변환: String.valueOf() 사용.
    • 문자열을 기본 타입으로 변환: Integer.parseInt() 또는 Double.parseDouble() 사용.
  3. 데이터 구조 변경:
    • 필요한 경우 상속 관계를 재설계하거나, 타입 간의 변환을 위한 메서드를 추가.

기본 자료형, 기본적인 Data type 만으로는 이 세상 모든 것들을 표현하기에는 부족함. 그래서 object, class의 등장이 필요!

object, class를 modeling하는 이유와 단계적인 방법을 설명해줄래? 구조에 대한 이야기도 해주면 좋아.

객체와 클래스를 모델링하는 이유와 단계적인 방법은 객체 지향 프로그래밍(OOP)의 핵심 개념과 밀접하게 관련이 있습니다. 여기서는 그 이유, 단계, 그리고 모델링의 구조를 상세히 설명하겠습니다.


1. 객체와 클래스를 모델링하는 이유

  1. 현실 세계의 문제를 소프트웨어로 표현하기 위해
    • 현실 세계는 객체(사람, 자동차, 책 등)로 구성되어 있습니다. 이를 소프트웨어에서 객체로 모델링하면 문제를 더 직관적이고 논리적으로 해결할 수 있습니다.
  2. 재사용성
    • 한 번 정의한 클래스는 여러 객체를 생성하거나 다른 프로그램에서도 재사용할 수 있습니다.
  3. 유지보수성과 확장성
    • 객체 단위로 프로그램을 설계하면 수정과 확장이 쉬워집니다. 코드의 특정 부분만 변경해도 전체 시스템에 미치는 영향을 최소화할 수 있습니다.
  4. 데이터와 동작의 결합
    • 객체는 데이터를 포함하고 그 데이터를 처리하는 메서드를 함께 정의합니다. 이 결합은 데이터를 안전하게 보호하고 코드를 이해하기 쉽게 만듭니다.

2. 객체와 클래스 모델링의 단계적인 방법

1단계: 문제 도메인 분석

  • 모델링하려는 현실 세계의 문제를 분석합니다.
  • 주요 개념, 속성, 행동을 추출합니다.
    예: 자동차 관리 시스템의 경우, 주요 객체는 자동차, 운전자, 정비사 등이 될 수 있습니다.

2단계: 객체 식별

  • 문제에서 중요한 객체(또는 개체)를 식별합니다.
  • 객체는 상태(속성)와 행동(메서드)을 가질 수 있어야 합니다.
    예: 자동차 객체의 속성은 색상, 모델, 속도이며, 행동은 운전, 멈춤 등이 될 수 있습니다.

3단계: 클래스 정의

  • 식별한 객체를 일반화하여 클래스를 정의합니다.
  • 객체의 속성(필드)과 행동(메서드)을 클래스 안에 캡슐화합니다.
    예:
public class Car {
    private String color;
    private String model;
    private int speed;

    public void drive() {
        System.out.println("The car is driving.");
    }

    public void stop() {
        System.out.println("The car has stopped.");
    }
}

4단계: 관계 정의

  • 클래스들 간의 관계를 정의합니다.
    • 연관(Relationship): 한 클래스가 다른 클래스를 참조합니다.
    • 상속(Inheritance): 한 클래스가 다른 클래스를 확장합니다.
    • 의존(Dependency): 한 클래스가 일시적으로 다른 클래스를 사용합니다.
    • 집합(Composition): 한 클래스가 다른 클래스를 포함합니다.

5단계: 객체 생성 및 테스트

  • 정의된 클래스를 기반으로 객체를 생성하고, 올바르게 작동하는지 테스트합니다.
    예:
public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        car.drive();
        car.stop();
    }
}

6단계: 설계 개선

  • 설계 패턴이나 원칙(SOLID, DRY, KISS 등)을 적용하여 모델을 개선합니다.
  • 코드 중복을 줄이고 가독성과 유지보수성을 높입니다.

3. 모델링 구조

객체와 클래스 모델링은 계층적이고 모듈화된 구조를 따릅니다.

  1. 객체(Object)
    • 실제 데이터와 행동을 캡슐화한 실체입니다.
      예: Car myCar = new Car();
  2. 클래스(Class)
    • 객체를 생성하기 위한 청사진(템플릿)입니다.
  3. 관계 구조
    • 상속(Inheritance): 부모-자식 관계로 기능을 확장합니다.
      예: Truck 클래스는 Car 클래스를 상속받을 수 있습니다.
    • 다형성(Polymorphism): 동일한 메서드가 서로 다른 구현을 가질 수 있습니다.
    • 캡슐화(Encapsulation): 데이터를 외부로부터 보호합니다.
    • 추상화(Abstraction): 불필요한 세부정보를 숨기고 중요한 부분만 드러냅니다.

4. 예시: 도서 관리 시스템 모델링

// Book 클래스
public class Book {
    private String title;
    private String author;

    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }

    public void displayInfo() {
        System.out.println("Title: " + title + ", Author: " + author);
    }
}

// Library 클래스
import java.util.ArrayList;

public class Library {
    private ArrayList<Book> books = new ArrayList<>();

    public void addBook(Book book) {
        books.add(book);
    }

    public void displayBooks() {
        for (Book book : books) {
            book.displayInfo();
        }
    }
}

// Main 클래스
public class Main {
    public static void main(String[] args) {
        Library library = new Library();
        Book book1 = new Book("Java Programming", "John Doe");
        Book book2 = new Book("Effective Java", "Joshua Bloch");

        library.addBook(book1);
        library.addBook(book2);

        library.displayBooks();
    }
}

5. 결론

객체와 클래스 모델링은 문제를 더 잘 이해하고, 유지보수와 확장성을 고려한 소프트웨어를 설계하는 데 필수적입니다. 위 단계를 따른다면 체계적이고 직관적인 모델링이 가능하며, 관계 구조를 명확히 하면 코드의 재사용성과 품질을 높일 수 있습니다.


객체가 무엇인지, 클래스가 무엇인지, 둘을 구분지어서 설명해줄래? 그리고 둘을 같이 섞어서도 설명해줄래?

객체(Object)와 클래스(Class)의 구분된 설명

1. 객체(Object)란?

  • 정의: 객체는 실제 존재하는 구체적인 실체를 의미하며, 소프트웨어에서 상태(데이터)와 행동(기능)을 포함하는 단위입니다.
  • 특징:
    1. 실제 데이터를 가짐: 객체는 메모리상에 존재하며 특정 값을 가집니다.
    2. 행동을 수행: 객체는 정의된 행동(메서드)을 통해 동작할 수 있습니다.
    3. 개별성: 동일한 클래스에서 생성된 객체라 하더라도 각각 독립적인 속성과 행동을 가질 수 있습니다.
  • 비유: 붕어빵 틀(클래스)에서 만들어진 붕어빵(객체). 붕어빵은 실제로 먹을 수 있는 실체입니다.
  • 예시:
Car myCar = new Car();
myCar.color = "Red";  // 상태(속성)
myCar.drive();        // 행동(메서드)

2. 클래스(Class)란?

  • 정의: 클래스는 객체를 생성하기 위한 **청사진(설계도)**입니다. 즉, 객체가 가져야 할 속성(필드)과 행동(메서드)을 정의한 추상적인 개념입니다.
  • 특징:
    1. 추상적: 클래스 자체는 메모리에 생성되지 않고, 객체가 생성될 때만 실제로 메모리에 할당됩니다.
    2. 설계와 정의: 클래스는 객체가 가질 속성과 행동을 설계합니다.
    3. 재사용성: 한 번 정의한 클래스를 사용해 여러 객체를 생성할 수 있습니다.
  • 비유: 붕어빵 틀이나 건물의 설계도와 같은 존재로, 직접 사용되는 것이 아니라 실체(객체)를 만들기 위한 기반입니다.
  • 예시:
public class Car {
    String color;
    int speed;

    public void drive() {
        System.out.println("The car is driving.");
    }
}

객체와 클래스의 차이점

구분객체(Object)클래스(Class)
정의 실질적으로 존재하며 메모리 상에 할당된 실체 객체를 생성하기 위한 추상적인 설계도
역할 상태를 저장하고 동작을 수행 객체가 어떤 상태와 동작을 가질지 정의
메모리 생성될 때 메모리에 할당됨 코드로만 존재하며 메모리에 직접 올라가지 않음
다수 생성 여부 동일 클래스에서 여러 객체를 생성할 수 있음 한 클래스는 설계도로 존재, 직접적으로 사용되지 않음
예시 Car myCar = new Car(); public class Car { ... }

객체와 클래스를 섞어서 설명

객체와 클래스는 같은 개념의 두 가지 다른 측면입니다.

  • **클래스(Class)**는 **객체(Object)**를 만들기 위한 설계도입니다.
    예를 들어, Car 클래스는 모든 자동차가 공통적으로 가져야 할 속성(예: 색상, 속도)과 행동(예: 운전, 정지)을 정의합니다.
  • 그러나 설계도만으로는 자동차를 실제로 사용할 수 없습니다. 클래스를 기반으로 한 객체가 있어야 비로소 사용할 수 있습니다.
    예를 들어, Car 클래스를 사용해 만든 myCar와 yourCar라는 두 객체는 각각 독립적인 상태와 행동을 가질 수 있습니다.

코드로 섞어서 설명

// 클래스 정의: 자동차의 설계도
public class Car {
    String color;
    int speed;

    public void drive() {
        System.out.println("The car is driving at " + speed + " km/h.");
    }
}

// 객체 생성 및 사용: 자동차 실체화
public class Main {
    public static void main(String[] args) {
        // 객체 1 생성
        Car myCar = new Car();
        myCar.color = "Red";
        myCar.speed = 100;
        myCar.drive(); // 출력: The car is driving at 100 km/h.

        // 객체 2 생성
        Car yourCar = new Car();
        yourCar.color = "Blue";
        yourCar.speed = 80;
        yourCar.drive(); // 출력: The car is driving at 80 km/h.
    }
}
  1. 클래스(Class): Car는 자동차 객체가 어떤 속성과 동작을 가져야 하는지 정의합니다.
  2. 객체(Object): myCar와 yourCar는 각각 Car 클래스를 기반으로 생성된 독립적인 실체입니다.
    • myCar는 빨간색이고 100km/h로 달립니다.
    • yourCar는 파란색이고 80km/h로 달립니다.

결론

  • 클래스는 객체의 설계도를 제공하며, 객체는 이 설계도를 기반으로 생성된 실제 실체입니다.
  • 클래스를 사용하지 않고 객체를 만들 수 없고, 객체가 없다면 클래스는 단지 코드로만 존재할 뿐입니다.
  • 클래스와 객체는 함께 사용됨으로써 OOP의 강력함을 발휘합니다.

클래스 간 관계 정의를 상세히 설명하기

클래스 간의 관계를 이해하기 위해 각각의 개념을 비유와 코드 예제로 설명하겠습니다.


1. 연관 (Association)

정의:

  • 한 클래스가 다른 클래스를 참조하여 데이터를 공유하거나 동작을 수행하는 관계입니다.
  • 두 클래스는 독립적이지만, 서로 연결되어 있습니다.

비유:

  • 교수와 학생 관계
    • 교수와 학생은 독립적인 존재이지만, 교수는 자신이 가르치는 학생들을 알고 있고, 학생은 자신이 배우는 교수를 알고 있습니다.

코드 예시:

// Student 클래스
public class Student {
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

// Professor 클래스
public class Professor {
    private String name;
    private Student student; // 연관 관계

    public Professor(String name, Student student) {
        this.name = name;
        this.student = student;
    }

    public void teach() {
        System.out.println(name + " is teaching " + student.getName());
    }
}

// Main 클래스
public class Main {
    public static void main(String[] args) {
        Student student = new Student("Alice");
        Professor professor = new Professor("Dr. Smith", student);
        professor.teach(); // 출력: Dr. Smith is teaching Alice
    }
}

2. 상속 (Inheritance)

정의:

  • 한 클래스가 다른 클래스를 확장하여 기존의 속성과 메서드를 물려받는 관계입니다.
  • 부모-자식 관계로, 재사용성과 확장성을 제공합니다.

비유:

  • 동물과 개 관계
    • 동물은 일반적인 개념이고, 개는 동물의 특성을 상속받아 추가적인 특성을 더한 구체적인 개념입니다.

코드 예시:

// Animal 클래스 (부모 클래스)
public class Animal {
    public void eat() {
        System.out.println("This animal eats food.");
    }
}

// Dog 클래스 (자식 클래스)
public class Dog extends Animal {
    public void bark() {
        System.out.println("The dog barks.");
    }
}

// Main 클래스
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();  // 부모 클래스의 메서드 호출
        dog.bark(); // 자식 클래스의 메서드 호출
    }
}

3. 의존 (Dependency)

정의:

  • 한 클래스가 다른 클래스의 기능을 일시적으로 사용하는 관계입니다.
  • 두 클래스는 긴밀히 연결되지 않으며, 특정 작업에서만 잠시 사용됩니다.

비유:

  • 요리사와 레시피 관계
    • 요리사는 특정 요리를 만들 때 레시피를 참고하지만, 요리사가 계속 레시피에 의존하지는 않습니다.

코드 예시:

// Recipe 클래스
public class Recipe {
    public void showRecipe() {
        System.out.println("Recipe: Boil water, add ingredients, stir.");
    }
}

// Chef 클래스
public class Chef {
    public void cook(Recipe recipe) { // 의존 관계
        recipe.showRecipe();
        System.out.println("Chef is cooking based on the recipe.");
    }
}

// Main 클래스
public class Main {
    public static void main(String[] args) {
        Recipe recipe = new Recipe();
        Chef chef = new Chef();
        chef.cook(recipe); // 출력: Recipe와 함께 요리를 수행
    }
}

4. 집합 (Composition)

정의:

  • 한 클래스가 다른 클래스를 포함하여 강하게 연결된 관계입니다.
  • 포함된 클래스는 포함하는 클래스의 일부로 간주되며, 포함하는 클래스가 삭제되면 포함된 클래스도 삭제됩니다.

비유:

  • 자동차와 엔진 관계
    • 자동차는 엔진을 포함하며, 자동차가 없어지면 엔진도 존재할 이유가 없습니다.

코드 예시:

// Engine 클래스
public class Engine {
    public void start() {
        System.out.println("Engine starts.");
    }
}

// Car 클래스
public class Car {
    private Engine engine; // 집합 관계

    public Car() {
        this.engine = new Engine();
    }

    public void drive() {
        engine.start();
        System.out.println("Car is driving.");
    }
}

// Main 클래스
public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        car.drive(); // 출력: Engine starts. Car is driving.
    }
}

요약 표

관계 유형정의비유특징

연관 클래스 간 서로 참조하는 관계 교수 ↔ 학생 독립적 클래스 간 연결
상속 한 클래스가 다른 클래스를 확장 동물 → 개 부모-자식 관계로 속성/동작 상속
의존 한 클래스가 다른 클래스를 일시적으로 사용하는 관계 요리사 ↔ 레시피 느슨한 연결, 특정 작업에서만 사용
집합 한 클래스가 다른 클래스를 포함하는 관계 자동차 → 엔진 강한 연결, 포함된 클래스는 포함하는 클래스에 의존

추가 설명

각 관계를 구분짓는 핵심은 클래스 간의 결합 정도사용 목적입니다.

  • 느슨한 결합이 필요한 경우(의존, 연관), 클래스 간 독립성을 유지할 수 있습니다.
  • 강한 결합이 필요한 경우(상속, 집합), 클래스 간의 기능과 데이터를 더 밀접하게 연결합니다.

클래스를 선언(혹은 정의)하고 만드는 방법은 Java 프로그래밍에서 매우 중요합니다. 아래는 클래스를 선언하고 사용하는 방법을 단계적으로 설명합니다.


1. 클래스 선언(정의)의 기본 구조

// 기본 클래스 구조
[접근제어자] class 클래스명 {
    // 필드 (속성)
    데이터타입 필드명;

    // 생성자
    클래스명(매개변수들) {
        // 필드 초기화
    }

    // 메서드 (동작)
    반환타입 메서드명(매개변수들) {
        // 동작 정의
    }
}

2. 클래스 선언의 요소

1) 접근 제어자

  • 클래스 접근 범위를 결정합니다. 주로 다음 중 하나를 사용합니다:
    • public: 모든 곳에서 접근 가능.
    • default(생략 시): 같은 패키지 내에서만 접근 가능.

2) 클래스명

  • 클래스 이름은 관례적으로 대문자로 시작합니다. (예: Car, Person)

3) 필드 (Fields)

  • 클래스 내부의 데이터를 저장합니다.
  • 객체가 생성되면 이 필드는 객체의 상태를 나타냅니다.

4) 생성자 (Constructor)

  • 객체가 생성될 때 호출되어 초기값을 설정합니다.
  • 이름은 클래스 이름과 동일하며, 반환 타입이 없습니다.

5) 메서드 (Methods)

  • 클래스의 동작을 정의합니다.
  • 메서드는 특정 작업을 수행하며, 반환값이 있을 수도 있고 없을 수도 있습니다.

3. 클래스 선언 및 객체 생성 실습

예제 1: 기본 클래스

// 클래스 선언
public class Person {
    // 필드
    String name;
    int age;

    // 생성자
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 메서드
    public void introduce() {
        System.out.println("Hi, my name is " + name + " and I am " + age + " years old.");
    }
}

// 객체 생성 및 사용
public class Main {
    public static void main(String[] args) {
        // Person 객체 생성
        Person person1 = new Person("Alice", 25);
        person1.introduce(); // 출력: Hi, my name is Alice and I am 25 years old.
    }
}

예제 2: 계산기 클래스

// 클래스 선언
public class Calculator {
    // 메서드: 두 숫자의 합을 반환
    public int add(int a, int b) {
        return a + b;
    }

    // 메서드: 두 숫자의 차를 반환
    public int subtract(int a, int b) {
        return a - b;
    }
}

// 객체 생성 및 사용
public class Main {
    public static void main(String[] args) {
        Calculator calc = new Calculator();
        int sum = calc.add(5, 3);        // 5 + 3 = 8
        int difference = calc.subtract(5, 3); // 5 - 3 = 2

        System.out.println("Sum: " + sum);          // 출력: Sum: 8
        System.out.println("Difference: " + difference); // 출력: Difference: 2
    }
}

4. 클래스 선언 시 주의 사항

이름 규칙:

  • 클래스 이름은 대문자로 시작하며 CamelCase를 따릅니다.
  • 필드와 메서드는 소문자로 시작하며 CamelCase를 따릅니다.

접근 제어자와 캡슐화:

  • 필드는 보통 private로 선언하여 직접 접근을 막습니다.
  • 대신 getter와 setter 메서드를 제공하여 접근합니다.
  • 예:
public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

 

클래스와 객체의 구분:

  • 클래스는 설계도이고, 객체는 이 설계도로 만들어진 실체입니다.
  • 예:
Person person1 = new Person("John", 30); // 객체 생성

5. 연습 문제

문제: 자동차 클래스를 작성하세요.

  1. 클래스 이름: Car
  2. 필드: brand(String), speed(int)
  3. 메서드:
    • accelerate(int amount): speed를 증가시킵니다.
    • brake(int amount): speed를 감소시킵니다.
    • displayStatus(): 현재 속도와 브랜드를 출력합니다.

풀이 예시:

public class Car {
    private String brand;
    private int speed;

    public Car(String brand) {
        this.brand = brand;
        this.speed = 0; // 초기 속도는 0
    }

    public void accelerate(int amount) {
        speed += amount;
        System.out.println("Accelerated by " + amount + " km/h.");
    }

    public void brake(int amount) {
        speed -= amount;
        if (speed < 0) speed = 0; // 속도는 음수가 될 수 없음
        System.out.println("Braked by " + amount + " km/h.");
    }

    public void displayStatus() {
        System.out.println("Brand: " + brand + ", Speed: " + speed + " km/h.");
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car("Toyota");
        car.displayStatus(); // 출력: Brand: Toyota, Speed: 0 km/h.
        car.accelerate(50);  // 출력: Accelerated by 50 km/h.
        car.displayStatus(); // 출력: Brand: Toyota, Speed: 50 km/h.
        car.brake(20);       // 출력: Braked by 20 km/h.
        car.displayStatus(); // 출력: Brand: Toyota, Speed: 30 km/h.
    }
}

이 코드를 참고하여 원하는 클래스를 직접 작성해보세요!