Nick Dev

[JAVA] 객체 지향의 4대 특성 - 캡!상추다 본문

Java

[JAVA] 객체 지향의 4대 특성 - 캡!상추다

Nick99 2024. 12. 11. 12:50
반응형

이 내용을 정독하면 객체 지향의 4대 특성에 대한 오해가 풀리고 완벽히 이해할 수 있다
우리가 알고 있는

붕어빵틀과 붕어빵 비유

,

is a 관계

잘못된 비유모호한 표현들을 바로 잡자!!!

객체 지향이란?

  • 기계에 맞춰 절차적으로 프로그래밍하지 않고 사물을 인지하는 방식대로 프로그래밍하는 것
  • 객체 지향의 4대 특성
    • 캡상추다
    • 캡슐화, 상속, 추상화, 다형성

1. 추상화 = 모델링

⭐ 추상화란?

  • 구체적인 것을 분해해서 관찰자가 관심 있는 특성만 가지고 재조합 하는 것
  • 즉, 현실 사물의 특성들 중 해당 애플리케이션의 context(경계)에 맞는 특성만 가지고 재조합하는 것 = 모델링
    • 추상화의 결과 = 재조합의 결과 = 모델링의 결과 = 모델 = Class

Application Context?

  • Application Boundary라고 생각할 수 있다
  • 같은 사물이라도 내 애플리케이션의 문맥, 즉 관심 영역이 무엇인지에 따라 관심있는 특성이 달라진다
    • 병원 애플리케이션 : 사람 → 환자
    • 은행 애플리케이션 : 사람 → 고객

📌 자바에서 추상화 지원하는 방법

  • class 키워드를 통해 지원

개발자가 class를 만드는 과정이 곧 모델링하는 과정이고 그게 곧 추상화를 하고 있는 것이다


클래스 ↔ 객체

구분 방법

  • 생물일 경우 → 나이 물어보기
  • 무생물일 경우 → 제조일자 물어보기

클래스

  • 분류에 대한 개념
  • 같은 속성과 기능을 가진 객체를 총칭하는 개념
  • 객체의 설계도

객체

  • 실체
  • 세상에 존재하는 유일무이한 객체

클래스, 메서드, 객체는 메모리 어디에 저장될까?

public class Mouse {
        public String name;
        public int age;
        public static int countOfTail = 1;

        public void sing() {
                System.out.println(name + " 찍찍!!");
        }
}

--------------------------------------------------
public class MouseDriver {
        public static void main(String[] args) {
                Mouse mickey = new Mouse();

                mickey.name = "미키";
                mickey.age = 50;

        }
}

클래스는 static 영역에

  • static 영역은 클래스들의 놀이터다
  • 기본적으로 클래스는 static 영역에 생성된다
  • main(), countOfTail과 같은 static 변수, static 메서드static 영역에 단 1개 생성된다
  • static 변수 : 같은 클래스의 모든 객체들이 같은 값을 가지고 있을 때 활용한다
    • static 멤버 = 클래스 멤버 = 정적 멤버
    • 그림을 잘보면 클래스 내부에 메모리 공간이 확보
      • 인스턴스 변수는 heap 영역에 객체 생성되면 각 객체 안에 메모리 공간 할당된다
  • static 메서드 : 객체들에 존재 여부에 관계 없이 쓸 수 있는 메서드
    • 주로 유틸리티성 메서드를 정적 메서드로 구성

메서드는 stack 영역에

  • stack 영역은 메서드들의 놀이터다
  • 여는 중괄호({)를 만나면 stack 영역에 스택 프레임이 생성된다
    • 분기 처리되는 { 이건 해당 메서드 안에 생성된다
  • 닫는 중괄호(})를 만나면 스택 프레임 사라진다
  • Mouse mickey = new Mouse(); 에서 Mouse객체의 참조 변수인 mickey는 이 스택 프레임안에 존재함
    • mickeyheap에 생성되어 있는 Mouse 객체의 참조값(주소값)을 갖고 있다 (포인팅하고 있다고 생각하면 됨)

객체는 heap 영역에

  • heap 영역은 객체들의 놀이터다
  • Mouse mickey = new Mouse();를 통해 객체가 생성되면 Mouse 객체는 heap 영역에 생성된다

정리

이름 다른 이름 서식지
static 변수 클래스 속성(멤버), 정적 변수 … static 영역
인스턴스 변수 객체 속성(멤버), 객체 변수, … heap 영역
local 변수 지역 변수 stack 영역(해당 스택 프레임 내부)

2. 상속 = 재사용 + 확장

⭐ 정의

  • 객체 지향에서 상속은 상위 클래스의 특성을 하위 클래스에서 상속하고 거기에 더해 필요한 특성을 추가, 즉 확장해서 사용할 수 있다는 의미
    • 즉, 상속이라는 워딩보단 재사용 & 확장이 더 맞는 워딩
  • 상위 클래스쪽으로 갈수록 추상화, 일반화됐다고 말함
  • 하위 클래스쪽으로 갈수록 구체화, 특수화됐다고 말함

상속 관계에서 반드시 만족해야하는 문장

  • 하위 클래스는 상위 클래스다
    • 포유류동물이다 → OK
    • 고래포유류다 → OK
    • 고래동물이다 → OK
    • 객체 지향 설계 5원칙 LSP(리스코프 치환 원칙)

⭐ 상속 관계는 is a 관계다? → 아님!!

  • 하위 클래스는 하나의 상위 클래스다
    • 명확하지 않은 표현이다
  • is a 대신에 is a kind of 관계가 더 명확한 표현이다
    • 하위 클래스 is a kind of 상위 클래스
    • 포유류 is a kind of 동물 → 포유류는 동물의 한 분류다

⭐ 기억해야할 3문장!!!

  1. 객체 지향의 상속은 상위 클래스의 특성을 재사용하는 것이다
  2. 객체 지향의 상속은 상위 클래스의 특성을 확장하는 것이다
  3. 객체 지향의 상속은 is a kind of 관계를 만족해야 한다

자바가 다중 상속을 지원하지 않는 이유

  • 만약 다중 상속을 지원한다면, 인어가 사람과 물고기를 확장하고 있다고 할 때,
    • swim() 메서드를 수행하면 사람의 swim()을 실행해야할지 물고기의 swim()을 실행해야 할지 모호해진다 → 다중 상속의 다이아몬드 문제
  • 다중 상속을 지원하지 않는 대신 인터페이스를 도입다중 상속의 득은 취하고 실은 버림

인터페이스란?

  • 인터페이스는 클래스가 ‘무엇을 할 수 있다’라고 하는 기능을 구현하도록 강제하는 것이다
  • 구현 클래스 is able to 인터페이스
    • 구현 클래스는 인터페이스 할 수 있다
    • 고래는 헤엄칠 수 있다

상속과 인터페이스 특징

  • 상위 클래스는 물려줄 특성이 많을수록 좋음
  • 인터페이스는 구현을 강제할 메서드가 적을수록 좋음
    • ISP(인터페이스 분할 원칙) 때문에

상속과 메모리

public class Animal {
        public String name;

        public void showName() {
                System.out.println(name + "입니다");
        }
}

public class Whale {
        public String habitat;

        @Overriding
        public void showName() {
                System.out.println("overriding: " + name + "입니다");
        }

        public void showHabitat() {
                System.out.println(habitat + "에 살아요");
        }

        //Overloading
        public void showHabitat(String param) {
                System.out.println(habitat + "에 살아요" + param);
        }
}

public class Driver {
        public static void main(String[] args) {
                Whale theWhale = new Whale();

                theWhale.name = "고래고래1";
                theWhale.habitat = "남극";

                theWhale.showName();
                theWhale.showHabitat();

                Animal aWhale = new Whale();

                aWhale.name = "하나의 고래";
                // aWhale.habitat = "북극";

                aWhale.showName();
                // aWhale.showHabitat(); 

        }
}
  • 하위 클래스의 인스턴스(Whale)를 생성하면 자동으로 먼저 상위 클래스들의 인스턴스부터 생성된다
    • Whale theWhale = new Whale(); 을 실행하면 Heap 영역에 **Whale 클래스의 인스턴스와 **Animal 클래스의 인스턴스Object 클래스의 인스턴스도 생성된다
  • awhale 객체 참조 변수사실은 Whale이지만 자신은 Whale인지 모르고 Animal이라고만 알고 있다 ( → 암묵적 형변환)
    • 그래서 aWhale 참조 변수는 habitat 관련된 것들을 수행할 수 없다

3. 다형성 : 사용 편의성

정의

  • Polymorphism
  • 객체 지향에서 다형성이란 오버라이딩오버로딩이라고 할 수 있다

Overriding

  • 상위 클래스의 메서드를 재정의

Overloading

  • 같은 메서드 이름, 다른 인자 목록으로 다수의 메서드를 하나의 이름으로 **중복 정의**

여기서 다형성이란?

  • AnimalshowName()Whale에서 Overriding한 경우, 상위 클래스 타입의 객체 참조 변수를 사용하더라도 자동으로 하위 클래스에서 overriding한 메서드가 호출된다
    • Animal aWhale = new Whale();
    • 이 경우, aWhale.showName() 호출할 때 AnimalshowName()이 호출되지 않고 WhaleshowName()이 호출된다

만약 다형성이 지원되지 않는다면?!

  • 오버로딩이 지원되지 않아 인자의 조합마다 메서드를 각각 선언해야 한다면 매우 많은 메서드를 작성해야 한다
    • addIntDouble(int, double)
    • addDoubleInt(double, int)
  • 하지만 하나의 메서드명을 가지고 여러 인자 목록을 허용하면 매우 편리해진다 → 사용 편의성이 좋다
    • add(int, double)
    • add(double, int)
  • 오버라이딩의 경우에도 하위 클래스가 재정의한 메서드를 자동으로 알아서 호출해준다 → 사용 편의성 좋다

4. 캡슐화 : 정보 은닉

정의

  • 자바에서 정보 은닉은 접근 제어자private, default, protected, public 을 통해 가능하다

기억해야할 2가지

  • 상속받지 않았다면 인스턴스 변수객체 생성한 후 객체 참조 변수를 이용해 접근해야 함
  • 클래스 변수클래스명.클래스 변수명 형식으로 접근하는 것을 권장

⭐ Reference Type은 Call By Reference일까? → 아님!!!!!!

  • 자바는 무조건 Call By Value
  • 다만, 그 Value를 어떻게 해석하는지 기본형인지 참조형인지에 따라 다른 것 뿐이다!!!!!
    • 기본 자료형 변수는 변수가 저장하고 있는 값을 그 값 자체로 해석
    • 참조 자료형 변수는 저장하고 있는 값을 주소로 해석
    • 결국 참조 자료형도 객체를 넘기는게 아니라 주소값을 넘기는것!!!!!!
Animal ref_a = new Animal();
Animal ref_b = ref_a;

ref_a.age = 10;
ref_b.age = 20;

System.out.println(ref_a.age);    // 20
System.out.println(ref_b.age);    // 20

  • 그림과 같이 실제 객체를 넘기는게 아닌 ref_a가 저장하고 있는 Animal 객체의 주소값을 넘기는거다 → 그래서 자바는 Call By Value
  • 참조 자료형이기 때문에 ref_a 의 value인 100주소값으로 해석하는 것이고
  • 만약 기본 자료형이였다면 이 100을 그 값 자체인 100이라고 해석했을 것이다

⭐ 정리

  • 기본 자료형 변수는 값을 값 자체로 판단 (편견없이)
  • 참조 자료형 변수는 값을 주소, 즉 포인터로 판단
  • 기본 자료형이든 참조 자료형이든 변수를 복사할 때 일어나는 일은 같다!!!!!!!
    • 해당 변수가 가지고 있는 값을 그대로 복사해서 넘겨준다
반응형

'Java' 카테고리의 다른 글

[JAVA] volatile ⁉  (0) 2024.12.11
[JAVA] Thread vs Process  (0) 2024.12.11
[JAVA] HashMap의 내부 구현 방식  (0) 2024.12.11
[JAVA] ArrayList의 내부를 뜯어보자  (0) 2024.12.11
[JAVA] try-with-resources 써야 돼?  (0) 2024.12.11