Java

[Java] 07. 객체지향 프로그래밍 기본

Joo.v7 2024. 8. 27. 18:27

Chapter 1: 클래스(Class)와 객체(Object)

  • 클래스(Class)
  • 객체(Object)
  • 추상화(Abstraction)

Chapter 2: 캡슐화(Encapsulation)

  • 데이터와 메소드의 결합
  • 접근 가시성 제어
  • 왜 캡슐화를 해야 하는가?
  • 객체 데이터
  • 정적 메소드 사용

Chapter 3: Java와 객체지향

  • Hello, World Revisited
  • 단순한 클래스 정의
  • 새 객체 인스턴스화
  • this 키워드
  • 포함된 클래스 생성
  • 포함된 클래스에 접근

Lab 7-1 클래스를 만들고 사용

Chapter 4: 객체지향 시스템 정의

  • 상속(Inheritance)
  • 클래스 계층구조(Hierarchy)
  • 단일/다중 상속
  • 다형성(Polymorphism)
  • 추상 클래스(abstract class)
  • 인터페이스(interface)
  • Early/Late binding

Chapter 1: 클래스(Class)와 객체(Object)

클래스(Class)

 일반적인 행위(Method)와 상태(Data)를 설명하는 이름이 붙여진 statement의 구조

 

객체(Object)

  • 클래스의 인스턴스(instance)
  • 객체의 3가지 특징(3요소)
    • Identity(ID): 한 객체는 다른 객체와 구분될 수 있다.
    • Behavior(행위): 객체는 다른 작업을 수행함. - Method를 의미.
    • State(상태): 객체는 상태를 포함. - Data를 의미.

 

추상화(Abstraction)

  • 복잡한 것을 명확(단순)하게 만드는 것.
  • 어떤 것이 중요하고, 필요하고, 신뢰 가능한지에 대한 판단. (불필요한 것을 제거)
  • 캡슐화는 추상화의 강력한 도구.

 


 

Chapter 2: 캡슐화(Encapsulation)

데이터와 메소드의 결합

  • 데이터와 메소드를 하나의 캡슐로 결합, 캡슐 경계는 내/외부를 결정
  • 캡슐화(Encapsulation)의 중요한 두 가지 관점
    • 데이터와 기능을 단일 개체로 결합
    • 개체의 모든 멤버(메소드, 변수 등)에 대한 접근 가시성 제어

 

접근 가시성 제어

  • 메소드는 public, 외부에서 볼 수 있다.
  • 데이터는 private, 내부에서만 볼 수 있다.

public: withdraw(), deposit() / private: balance

* ADT(Abstract Data Type, 추상 데이터 타입) : 데이터 표현이 완전히 비공개인 유형

 

왜 캡슐화를 해야 하는가?

  • 캡슐화의 2가지 목적
    • 사용 제어: 개발자가 의도한 방식으로만 사용할 수 있도록 설계.
    • 변경의 영향 최소화: 내부 구현이 변경되어도 외부 영향은 최소화 되어야 하는데, public은 사용자도 접근할 수 있어서 사용자의 코드도 다 바꿔야한다. (나중에 코드 수정시 내가 한 변경이 다른 객체에 영향을 주지 않게 할 수 있다.)

(좌) 사용 제어, (우) 변경의 영향 최소화

 

객체 데이터

  • 객체 데이터는 개별 객체에 대한 정보를 설명한다. ex) balance, owner ...
  • 객체 내부에서 static 데이터를 제외한 모든 데이터 항목은 각각의 객체에 대한 정보다.
  • 객체 내의 데이터는 private로 유지되며, 객체의 메소드를 통해서만 access 하는게 좋다.

 

정적 메소드(Static Method) 사용

  • Static Method는 Static Data만 access할 수 있다.
  • Static Method는 클래스에서 호출된다. 객체가 아니다.

은행의 이자율은 각각의 계정 객체에 따라서가 아닌 클래스에 속한다.

 


 

Chapter 3: Java와 객체지향

Hello, World Revisited

  • 런타임의 클래스 호출
    • 클래스에 정적 main 메소드가 있으면, 컴파일러는 이를 프로그램 entry point로 만든다.
      (이때, main 메소드의 시그니처public static void main(String[] args)와 같아야 한다.
    • main 함수(progrm entry point)가 없으면 일종의 라이브러리가 된다.
  • main이 Static Method인 이유
    • Static Method는 런타임이 class의 instance를 만들 수 없다.
    • 만약, main이 동적 메소드라면 런타임은 실행시에 main 메소드를 호출하기 위해 객체를 생성해야 한다.
      ex) Example example = new Example();   example.main();

 

단순한 클래스 정의

  • data와 class 모두 Class 내에 위치.
  • method는 public, data는 private.
class BankAccount {
    	public void withDraw(int amount)
	{ ... }
	public void deposit(int amount)
	{ ... }
	private decimal balance;
	private String name;
}

 

새 객체 인스턴스화 (객체 생성)

  • Class 변수 정의는 객체를 생성하지 않음.
  • new 연산자를 사용해서 객체 생성. (클래스의 객체가 메모리에 생성)
class Program {
    public static void main(String[] args) {
        int age = 27;
        // BankAccount의 객체가 메모리에 생성되고 account(변수)가 이를 가리킴.
        BankAccount account = new BankAccount(); 
        Account.deposit(2200);
    }
}

 

this 키워드

  • 메소드를 호출하는 현재 객체, 즉 자기 자신을 참조함.
  • Static Method/Data는 객체에 속하지 않는다. 따라서 this로 호출 불가
/* 객체지향 언어에서 사용하는 일반적인 용법 */
class Time {
    public Time (int hour, int minite) {
        this.hour = hour;
        this.minite = minute;
    }
}

/* this를 반환하는 것은 객체 자신을 반환한다는 뜻이다. */
class Song {
    public Song setArtist(String artist) {
        this.artist = artist;
        return this;
    }
    public Song setTitle(String title) {
        this.title = title;
    }
}

 

포함된 클래스 생성

  • 클래스는 클래스를 포함할 수 있다.
/* Bank 클래스에 포함된 Account 클래스 -> 다른 클래스에서 호출: Bank.Account */
class Program {
	public static void main(String[] args) {
		Bank.Account account = new Bank.Account();
	}
}

class Bank {
	… class Account { ... }
}

 

포함된 클래스에 접근

포함된 클래스는 public 또는 private로 선언될 수 있음

class Bank {
    public class Account { ... }
    private class AccountNumberCreator { ... }
}

class Program {
    public static void main(String[] args) {
        Bank.Account			// 접근 가능
        Bank.AccountNumberCreator	// 접근 불가
    }
}
/* NumberSetter은 private지만, Account 내에 선언되었고, 
setup() 메소드는 account 메소드이기 때문에 access 가능. */
class Bank
{
    public class Account {
        public void setup()  {
            NumberSetter.set(this); // 접근 가능
            balance = 0;
        }
        private class NumberSetter {
            public static void set(Account account) {
                account.number = nextNumber++;
            }
            private static int nextNumber = 2311;
        }
        private int number;
        private int balance;
    }
}

 

Lab 7-1 클래스를 만들고 사용

2024.08.27 - [코딩 문제] - [코딩 문제] 은행 계좌 코드

 

[코딩 문제] 은행 계좌 코드

 

lightningtech.tistory.com

 


 

Chapter 4: 객체지향 시스템 정의

상속(Inheritance)

  • 상속은 "is a kind of" 관계를 지정.
  • 상속은 클래스 사이의 관계다.
  • 파생된 클래스는 존재하는 클래스에서 Specialization됨.

Musician class(Super class/Base class/Parent class), Violin Player class(Subclass)

 

클래스 계층구조(Hierarchy)

  • 상속과 관련된 클래스는 Class Hierarchy를 형성.

 

단일/다중 상속

  • Single Inheritance: 하나의 기본 클래스에서 파생.
  • Multiple Inheritance: 하나 or 그 이상의 클래스에서 파생.

 

다형성(Polymorphism)

  • 기본 클래스에 선언된 메소드가 파생된 클래스에 따라 다양한 방식으로 구현될 수 있다.
  • 메소드 이름은 기본 클래스에 존재.
  • 메소드 구현은 파생된 클래스에 존재.

Overriding(오버라이딩): super class에서 정의된 메소드를 sub class에서 재정의

 

추상 클래스(abstract class)

  • 직접 인스턴스 생성 X, 주로 상속을 통해 다른 클래스들이 공통으로 가져야 할 메서드나 속성 정의에 사용.
  • Java에서는 abstract 키워드를 사용.

 

* 스타크래프트 예시

/* abstract class: Unit.java */
public abstract class Unit {
    protected String name;
    protected int hp;
    protected int attackPower;

    public Unit(String name, int hp, int attackPower) { // 생성자: 초기화 역할
        this.name = name;
        this.hp = hp;
        this.attackPower = attackPower;
    }

    public void setHp(int hp) {
        this.hp = hp;
    }

    public int getHp() {
        return this.hp;
    }

    public String getName() {
        return this.name;
    }

    public int getAttackPower() {
        return this.attackPower;
    }

    public void attack(Unit unit) {
        System.out.println(this.name + "이 " + unit.name + "을 공격합니다");
        unit.setHp(unit.getHp() - this.attackPower);
    }
}
/* Zergling.java: Unit.java를 상속받음 */
public class Zergling extends Unit{
    public Zergling(String name, int hp, int attackPower) {
        super(name, hp, attackPower);
    }
}
/* marine.java: Unit.java를 상속받음.
   다형성: Overriding -> attack 메소드 */
public class Marine extends Unit{
    public Marine(String name, int hp, int attackPower) {
        super(name, hp, attackPower);
    }

    public void attack(Unit unit) { // Overriding
        System.out.println(this.name + "이 " + unit.name + "을 원거리 공격합니다");
        unit.setHp(unit.getHp() - this.attackPower);
    }
}

 

인터페이스(interface)

  • 메소드의 선언만 포함하며, 실제 구현은 포함 X.
  • Super class에서 선언. Sub class에서 구현.
  • interface(Super class)implements(Sub class) 키워드 사용
interface Drawable {
    void draw(); // 메소드 시그니처만 정의
}

interface Resizable {
    void resize();
}

class Shape implements Drawable, Resizable { // interface는 다중 상속 가능
    @Override
    public void draw() {
        System.out.println("Drawing shape");
    }

    @Override
    public void resize() {
        System.out.println("Resizing shape");
    }
}

 

Early/Late binding

  • Early binding(Static binding)
    • 메소드 호출이 컴파일 타임에 결정.
    • 주로 Method Overloading에서 발생,
    • 컴파일러는 메소드 호출 시점에 적절한 메소드를 선택(메소드 시그니처에 따라 메소드는 구분되기 때문에)
  • Late binding(Dynamic binding)
    • 메소드 호출이 런타임에 결정.
    • 주로 Method Overriding에서 발생.
    • 런타임에 메소드의 실제 구현이 호출. (프로그램 돌려봐야 알기 때문에)

 

2024.08.27 - [코딩 문제] - [코딩 문제] 분수 계산(사칙연산) 코드

 

[코딩 문제] 분수 계산(사칙연산) 코드

 

lightningtech.tistory.com

 


 

 

출처: https://github.com/gikpreet/class-programming_with_java/tree/master

 

GitHub - gikpreet/class-programming_with_java

Contribute to gikpreet/class-programming_with_java development by creating an account on GitHub.

github.com

 

'Java' 카테고리의 다른 글

[Java] Getter / Setter 메소드  (0) 2024.08.28
[Java] 08. 참조 타입  (2) 2024.08.28
[Java] 06. 배열  (0) 2024.08.25
[Java] 배열의 출력, 비교, 복사, 정렬  (0) 2024.08.25
[Java] 05. 메소드와 파라미터*  (0) 2024.08.23