
객체 지향
객체 지향은 우리가 현실 세계에서 사물을 인지하는 방식대로 프로그래밍 하려고 하는 데에서 출발했다.
세상에 존재하는 모든 사물은 객체(object)이다.
각각의 사물은 고유하다. 사물은 속성(property)을 가지고 있으며, 행위(method)를 한다.
그리고 인간은 사물을 분류(class)하여 인지한다.
e.g. 강호동(object), 유재석(object) 은 사람이라는 분류(class)에 속한다.
그리고 이 객체들은 나이, 키 등의 속성(property)과 걷다, 말하다 등의 행위(method) 를 가진다.
객체
object 를 번역하면 객체보다는 개체에 더 가깝다.
객체 지향에서의 객체는 '세상에 존재하는 유일무이한 사물' 에 가깝다.
그리고 이 객체는 속성과 기능을 가지고 있다.
클래스
객체를 특성(속성과 기능)에 따라 분류한 집합적 개념
클래스 vs 객체
클래스는 분류의 개념이고 객체는 실체이다.
e.g. 사람은 분류이기 때문에 나이(property)가 없고, 강호동은 실체이기 때문에 나이(property)가 있다.
인스턴스
클래스를 이용해 객체를 만들었다는 것을 강조할 때 객체를 인스턴스라고 표현한다.
클래스는 객체의 설계도이기도 하다.
클래스 객체명 = new 클래스();
클래스 멤버 vs 객체 멤버
클래스 멤버 = static 멤버 = 정적 멤버
객체 멤버 = 인스턴스 멤버
어떤 클래스(분류)의 모든 객체들이 같은 값을 갖는다면,
그 값을 각 객체마다 저장하는 대신, 클래스에 저장할 수 있다.
→ static 키워드를 붙임으로써 Static 영역에 단 하나의 저장 공간을 가지게 된다.
이렇게 static 인 멤버를 클래스 멤버라고 한다. vs static 이 아니면 객체 멤버라고 한다.
의 문 점 : 전역 변수 쓰지 말라니까요! 라며... 그러면 final 로 고정하는 게 좋지 않을까?
정적 멤버는 객체의 존재 여부와 관계없이 사용할 수 있다.
객체 없이 호출 → 클래스명.속성, 클래스명.메서드
주로 다음과 같은 경우에 정적 메서드를 사용한다.
① main() 메서드의 논리를 함수로 분할하여 사용하는 경우
② 정적 변수에 대한 getter, setter 메서드
③ 인스턴스를 만들지 않고 사용하는 유틸리티성 메서드
객체 멤버는 객체가 생성되어야만 heap 영역에 저장 공간이 할당된다.
객체가 생성되기 전까지 static 영역에서는 설계도처럼 이름만 존재한다.
클래스에 속한 속성이 아니고 객체마다 존재하는 속성이기 때문
인스턴스가 생성되어 힙영역에 배치되면, 이 주소를 객체 참조 변수에 저장한다.
객체 참조 변수는 스택 영역 안의, 스택 프레임 안에 생성된다.
만약 참조변수가 더이상 객체를 참조하지 않으면 가비지 컬렉터가 객체를 수거해간다.
참조 변수의 복사
기본 자료형 변수는 Call By Value, 하지만 참조 변수의 경우 Call By Reference
객체 참조 변수에는 주소가 저장되기 때문에
Mouse mickey = new Mouse();
mickey.age = 2;
Mouse jerry = mickey; → mickey 의 주소가 jerry 에 저장되고 (같은 Mouse 객체를 참조하게 됨)
jerry.age = 3; → 이 때, mickey 의 age 도 3 으로 바뀐다.
변수를 메서드의 인자나 반환값으로 사용하는 경우도 마찬가지다.
하지만 mickey 와 jerry 는 당연히 별도의 변수다.
따라서 이후 jerry 에 null 혹은 다른 객체의 참조를 할당할 때는 mickey 에는 아무 영향도 주지 못한다.
초기화
stack 영역의 지역변수는 초기화하지 않으면 쓰레기 값을 갖게 된다.
반면, static 영역의 클래스 멤버 변수와 heap 영역의 객체 멤버 변수는 초기화하지 않아도
기본값 (정수형 0, 부동소수점 0.0, 논리형 false, 객체 null) 으로 초기화된다.
공유 변수의 성격을 가지기 때문
객체 지향의 4대 특성
1. 캡슐화 Encapsulation: 정보 은닉
2. 상속 Inheritance: 재사용, 확장(extension)
3. 추상화 Abstraction: 모델링
4. 다형성 Polymorphism: 사용 편의, 오버라이딩과 오버로딩
추상화
추상화는 모델링이다. 자바는 class 키워드로 추상화를 지원하고 있다.
추상: 여러가지 개념에서 공통되는 특성을 추출하여 파악하는 것
그 중에서도 관심있는 특성만을 가지고 재조합하는 것
관심있는 특성? 우리는 어떤 객체들의 모든 속성을 나열할 필요가 없다.
어플리케이션 경계 (context) 에 따라 설계는 달라져야 한다.
추상화의 결과물은 모델이다. 자바에서는 클래스로 표현된다.
상속
상속은 재사용과 확장이다. 자바의 extends 키워드.
계층도가 아닌 분류도로 이해해야 한다.
상위 클래스의 특성을 하위 클래스에서 상속하고 (재사용)
거기에 필요한 특성을 추가할 수 있다 (확장)
상위 클래스로 갈수록 추상화, 일반화 ↔ 하위 클래스로 갈수록 구체화, 특수화
e.g. 동물 - 포유류 - 고래 ...
상속 관계에서 반드시 만족해야 하는 것
'하위 클래스'는 '상위 클래스'이다. (리스코프 치원 원칙, LSP)
'하위 클래스' is a (is a kind of) '상위클래스'
e.g. 고래는 포유류이다. 고래는 동물이다. 포유류는 동물의 한 분류다.
상속을 하면 상위 클래스에서 정의한 메서드를 다시 작성하지 않아도 사용할 수 있다 → 재사용
클래스 상속 구조에서 최상위 클래스는 Object, 모든 클래스는 Object 의 특성을 물려받는다.
e.g. toString() 메서드
다중 상속
자바는 다중 상속 - 여러 개의 클래스를 동시에 상속 받는 것 - 이 불가능하다.
다중 상속의 다이아몬드 문제 때문
대신 인터페이스를 도입했다.
구현 클래스 is able to 인터페이스 (구현 클래스는 인터페이스 할 수 있다) 의 관계
e.g. 고래는 헤엄칠 수 있다.
e.g. Serializable, Cloneable, Comparable, Runnable, ...
인터페이스를 구현하는 클래스는 인터페이스의 모든 기능들을 구현하도록 강제된다.
상위 클래스는 하위 클래스에 물려줄 특성이 많을수록 좋고 (LSP)
인터페이스는 구현을 강제할 메서드가 적을수록 좋다 (ISP)
상위 클래스가 빈약하면 불필요한 형변환이 발생할 수 있고, 상속으로 얻을 수 있는 이점이 줄어든다.
만약 하위 클래스마다 구현 내용이 달라야 하는 메서드가 있다면, 추상메서드로 해결할 수 있다.
메모리
하위 클래스의 인스턴스가 생성될 때 → 상위 클래스의 인스턴스도 함께 생성된다. (heap 영역)
따라서 어떤 클래스의 인스턴스가 생성될 때 Object 의 인스턴스도 함께 생성된다.
Penguin pororo = new Penguin(); → Penguin 의 인스턴스를 참조
Animal pingu = new Penguin(); → Animal 의 인스턴스를 참조
pingu 의 타입은 Animal 이다.
pingu 객체 참조 변수는 Penguin 의 속성과 메서드는 사용할 수 없다.
하지만 pingu 의 타입이 Animal 임에도 Penguin 에서 재정의된 메서드가 실행된다.
즉 상위 클래스 타입의 객체 참조 변수를 사용하더라도,
하위 클래스에서 오버라이딩한 메서드가 있다면 오버라이딩한 메서드가 호출된다.
(다형성) 상위 타입에 모든 하위 객체가 대입될 수 있다.
다형성
다형성은 사용 편의, 오버라이딩과 오버로딩이다.
메서드가 오버라이딩 되었다면, 오버라이딩된 메서드가 실행된다.
상위 클래스 - 하위 클래스 사이의 다형성, 인터페이스 - 구현 클래스 사이의 다형성이 있다.
↓ 참고 예제 ↓
자바 5에서 추가된 제네릭을 이용하면 하나의 함수만 구현해도 다수의 함수를 구현한 효과를 낼 수 있다.
캡슐화
캡슐화는 정보 은닉이다. 자바의 접근 제어자
- public - 전체
- protected - 같은 패키지 + 상속 관계 하위 클래스
- default - 같은 패키지
- private - 같은 클래스
음... 그런데 만약에 aaa.jar 파일 안에 package1 이 있고 bbb.jar 파일 안에 같은 이름을 가진 package1 이 있다면?
서로 접근 가능하게 될텐데... (;´・`)>
클래스 멤버 vs 객체 멤버
정적 멤버(클래스 멤버)는 어디에서나 '클래스명.멤버' 로 접근하는 것이 권장된다.
만약 객체를 생성하여 객체 참조 변수로 접근하게 되면,
메모리에서 힙 영역의 객체를 참조하고, 이 객체에서 다시 클래스를 참조하기 때문에 비효율적이다.
정적 메서드에서는 this 를 사용할 수 없다. 또한 인스턴스 멤버에 접근할 수 없다 (정적 멤버에만 접근 가능)
정적 메서드는 JVM 이 구동되면서 먼저 로드되며, 객체가 생성되지 않아도 호출이 가능하기 때문이다.
따라서 같은 클래스 (혹은 상속 관계의 하위 클래스) 이더라도, 객체를 생성하여 인스턴스 멤버를 호출해야 한다.
↓ 참고 예제 ↓
'Study > Booooooook' 카테고리의 다른 글
도메인 주도 설계 핵심 1-2장 (0) | 2024.07.19 |
---|---|
자바 객체 지향의 원리와 이해 5. SOLID (0) | 2024.05.25 |
자바 객체 지향의 원리와 이해 4. 객체 지향 (2) (0) | 2024.05.22 |
자바 객체 지향의 원리와 이해 2. 메모리 (0) | 2024.05.07 |
자바 객체 지향의 원리와 이해 1. Intro (0) | 2024.04.18 |

객체 지향
객체 지향은 우리가 현실 세계에서 사물을 인지하는 방식대로 프로그래밍 하려고 하는 데에서 출발했다.
세상에 존재하는 모든 사물은 객체(object)이다.
각각의 사물은 고유하다. 사물은 속성(property)을 가지고 있으며, 행위(method)를 한다.
그리고 인간은 사물을 분류(class)하여 인지한다.
e.g. 강호동(object), 유재석(object) 은 사람이라는 분류(class)에 속한다.
그리고 이 객체들은 나이, 키 등의 속성(property)과 걷다, 말하다 등의 행위(method) 를 가진다.
객체
object 를 번역하면 객체보다는 개체에 더 가깝다.
객체 지향에서의 객체는 '세상에 존재하는 유일무이한 사물' 에 가깝다.
그리고 이 객체는 속성과 기능을 가지고 있다.
클래스
객체를 특성(속성과 기능)에 따라 분류한 집합적 개념
클래스 vs 객체
클래스는 분류의 개념이고 객체는 실체이다.
e.g. 사람은 분류이기 때문에 나이(property)가 없고, 강호동은 실체이기 때문에 나이(property)가 있다.
인스턴스
클래스를 이용해 객체를 만들었다는 것을 강조할 때 객체를 인스턴스라고 표현한다.
클래스는 객체의 설계도이기도 하다.
클래스 객체명 = new 클래스();
클래스 멤버 vs 객체 멤버
클래스 멤버 = static 멤버 = 정적 멤버
객체 멤버 = 인스턴스 멤버
어떤 클래스(분류)의 모든 객체들이 같은 값을 갖는다면,
그 값을 각 객체마다 저장하는 대신, 클래스에 저장할 수 있다.
→ static 키워드를 붙임으로써 Static 영역에 단 하나의 저장 공간을 가지게 된다.
이렇게 static 인 멤버를 클래스 멤버라고 한다. vs static 이 아니면 객체 멤버라고 한다.
의 문 점 : 전역 변수 쓰지 말라니까요! 라며... 그러면 final 로 고정하는 게 좋지 않을까?
정적 멤버는 객체의 존재 여부와 관계없이 사용할 수 있다.
객체 없이 호출 → 클래스명.속성, 클래스명.메서드
주로 다음과 같은 경우에 정적 메서드를 사용한다.
① main() 메서드의 논리를 함수로 분할하여 사용하는 경우
② 정적 변수에 대한 getter, setter 메서드
③ 인스턴스를 만들지 않고 사용하는 유틸리티성 메서드
객체 멤버는 객체가 생성되어야만 heap 영역에 저장 공간이 할당된다.
객체가 생성되기 전까지 static 영역에서는 설계도처럼 이름만 존재한다.
클래스에 속한 속성이 아니고 객체마다 존재하는 속성이기 때문
인스턴스가 생성되어 힙영역에 배치되면, 이 주소를 객체 참조 변수에 저장한다.
객체 참조 변수는 스택 영역 안의, 스택 프레임 안에 생성된다.
만약 참조변수가 더이상 객체를 참조하지 않으면 가비지 컬렉터가 객체를 수거해간다.
참조 변수의 복사
기본 자료형 변수는 Call By Value, 하지만 참조 변수의 경우 Call By Reference
객체 참조 변수에는 주소가 저장되기 때문에
Mouse mickey = new Mouse();
mickey.age = 2;
Mouse jerry = mickey; → mickey 의 주소가 jerry 에 저장되고 (같은 Mouse 객체를 참조하게 됨)
jerry.age = 3; → 이 때, mickey 의 age 도 3 으로 바뀐다.
변수를 메서드의 인자나 반환값으로 사용하는 경우도 마찬가지다.
하지만 mickey 와 jerry 는 당연히 별도의 변수다.
따라서 이후 jerry 에 null 혹은 다른 객체의 참조를 할당할 때는 mickey 에는 아무 영향도 주지 못한다.
초기화
stack 영역의 지역변수는 초기화하지 않으면 쓰레기 값을 갖게 된다.
반면, static 영역의 클래스 멤버 변수와 heap 영역의 객체 멤버 변수는 초기화하지 않아도
기본값 (정수형 0, 부동소수점 0.0, 논리형 false, 객체 null) 으로 초기화된다.
공유 변수의 성격을 가지기 때문
객체 지향의 4대 특성
1. 캡슐화 Encapsulation: 정보 은닉
2. 상속 Inheritance: 재사용, 확장(extension)
3. 추상화 Abstraction: 모델링
4. 다형성 Polymorphism: 사용 편의, 오버라이딩과 오버로딩
추상화
추상화는 모델링이다. 자바는 class 키워드로 추상화를 지원하고 있다.
추상: 여러가지 개념에서 공통되는 특성을 추출하여 파악하는 것
그 중에서도 관심있는 특성만을 가지고 재조합하는 것
관심있는 특성? 우리는 어떤 객체들의 모든 속성을 나열할 필요가 없다.
어플리케이션 경계 (context) 에 따라 설계는 달라져야 한다.
추상화의 결과물은 모델이다. 자바에서는 클래스로 표현된다.
상속
상속은 재사용과 확장이다. 자바의 extends 키워드.
계층도가 아닌 분류도로 이해해야 한다.
상위 클래스의 특성을 하위 클래스에서 상속하고 (재사용)
거기에 필요한 특성을 추가할 수 있다 (확장)
상위 클래스로 갈수록 추상화, 일반화 ↔ 하위 클래스로 갈수록 구체화, 특수화
e.g. 동물 - 포유류 - 고래 ...
상속 관계에서 반드시 만족해야 하는 것
'하위 클래스'는 '상위 클래스'이다. (리스코프 치원 원칙, LSP)
'하위 클래스' is a (is a kind of) '상위클래스'
e.g. 고래는 포유류이다. 고래는 동물이다. 포유류는 동물의 한 분류다.
상속을 하면 상위 클래스에서 정의한 메서드를 다시 작성하지 않아도 사용할 수 있다 → 재사용
클래스 상속 구조에서 최상위 클래스는 Object, 모든 클래스는 Object 의 특성을 물려받는다.
e.g. toString() 메서드
다중 상속
자바는 다중 상속 - 여러 개의 클래스를 동시에 상속 받는 것 - 이 불가능하다.
다중 상속의 다이아몬드 문제 때문
대신 인터페이스를 도입했다.
구현 클래스 is able to 인터페이스 (구현 클래스는 인터페이스 할 수 있다) 의 관계
e.g. 고래는 헤엄칠 수 있다.
e.g. Serializable, Cloneable, Comparable, Runnable, ...
인터페이스를 구현하는 클래스는 인터페이스의 모든 기능들을 구현하도록 강제된다.
상위 클래스는 하위 클래스에 물려줄 특성이 많을수록 좋고 (LSP)
인터페이스는 구현을 강제할 메서드가 적을수록 좋다 (ISP)
상위 클래스가 빈약하면 불필요한 형변환이 발생할 수 있고, 상속으로 얻을 수 있는 이점이 줄어든다.
만약 하위 클래스마다 구현 내용이 달라야 하는 메서드가 있다면, 추상메서드로 해결할 수 있다.
메모리
하위 클래스의 인스턴스가 생성될 때 → 상위 클래스의 인스턴스도 함께 생성된다. (heap 영역)
따라서 어떤 클래스의 인스턴스가 생성될 때 Object 의 인스턴스도 함께 생성된다.
Penguin pororo = new Penguin(); → Penguin 의 인스턴스를 참조
Animal pingu = new Penguin(); → Animal 의 인스턴스를 참조
pingu 의 타입은 Animal 이다.
pingu 객체 참조 변수는 Penguin 의 속성과 메서드는 사용할 수 없다.
하지만 pingu 의 타입이 Animal 임에도 Penguin 에서 재정의된 메서드가 실행된다.
즉 상위 클래스 타입의 객체 참조 변수를 사용하더라도,
하위 클래스에서 오버라이딩한 메서드가 있다면 오버라이딩한 메서드가 호출된다.
(다형성) 상위 타입에 모든 하위 객체가 대입될 수 있다.
다형성
다형성은 사용 편의, 오버라이딩과 오버로딩이다.
메서드가 오버라이딩 되었다면, 오버라이딩된 메서드가 실행된다.
상위 클래스 - 하위 클래스 사이의 다형성, 인터페이스 - 구현 클래스 사이의 다형성이 있다.
↓ 참고 예제 ↓
자바 5에서 추가된 제네릭을 이용하면 하나의 함수만 구현해도 다수의 함수를 구현한 효과를 낼 수 있다.
캡슐화
캡슐화는 정보 은닉이다. 자바의 접근 제어자
- public - 전체
- protected - 같은 패키지 + 상속 관계 하위 클래스
- default - 같은 패키지
- private - 같은 클래스
음... 그런데 만약에 aaa.jar 파일 안에 package1 이 있고 bbb.jar 파일 안에 같은 이름을 가진 package1 이 있다면?
서로 접근 가능하게 될텐데... (;´・`)>
클래스 멤버 vs 객체 멤버
정적 멤버(클래스 멤버)는 어디에서나 '클래스명.멤버' 로 접근하는 것이 권장된다.
만약 객체를 생성하여 객체 참조 변수로 접근하게 되면,
메모리에서 힙 영역의 객체를 참조하고, 이 객체에서 다시 클래스를 참조하기 때문에 비효율적이다.
정적 메서드에서는 this 를 사용할 수 없다. 또한 인스턴스 멤버에 접근할 수 없다 (정적 멤버에만 접근 가능)
정적 메서드는 JVM 이 구동되면서 먼저 로드되며, 객체가 생성되지 않아도 호출이 가능하기 때문이다.
따라서 같은 클래스 (혹은 상속 관계의 하위 클래스) 이더라도, 객체를 생성하여 인스턴스 멤버를 호출해야 한다.
↓ 참고 예제 ↓
'Study > Booooooook' 카테고리의 다른 글
도메인 주도 설계 핵심 1-2장 (0) | 2024.07.19 |
---|---|
자바 객체 지향의 원리와 이해 5. SOLID (0) | 2024.05.25 |
자바 객체 지향의 원리와 이해 4. 객체 지향 (2) (0) | 2024.05.22 |
자바 객체 지향의 원리와 이해 2. 메모리 (0) | 2024.05.07 |
자바 객체 지향의 원리와 이해 1. Intro (0) | 2024.04.18 |