객체지향의 4대 특성 - 캡!상추다
- 캡슐화 (Encapsultation): 정보 은닉(information hiding)
- 상속
(Inheriance)재사용 - 추상화 (Abstaction) : 모델링
- 다형성 (Polymorphism) : 사용 편의
클래스 vs. 객체 = 붕어빵틀 vs.붕어빵?
금형기계 붕어빵틀 = new 금형기계();- 붕어빵틀은 붕어빵을 만드는 팩터리
클래스와 객체를 구분하는 간단한 방법 - 나이 물어보기
- 사람의 나이는 몇살인가 -> 클래스
- 김연아의 나이는 몇살인가 -> 객체
- 뽀로로의 나이는 몇살인가 -> 객체
- 펭귄의 나이는 몇살인가 -> 클래스
클래스는 분류에 대한 개념이지 실체가 아니다!
- 클래스 : 객체 = 펭귄 : 뽀로로 = 사람: 김연아
추상화 : 모델링
- 여러가지 사물이나 개념에서 공통되는 특성이나 속성따위를 추출하여 파악하는 작용
- 구체적인 것을 분해해서 관찰자가 관심있는 특성만 가지고 재조합하는 것
- 구체적인 것을 분해해서 관심 영역 (어플리케이션 경계)에 있는 특성만 가지고 재조합하는 것 = 모델링
추상화의 개념
- 상속을 통한 추상화, 구체화
- 인터페이스를 통한 추상화
- 다형성을 통한 추상화
모델
- 실제 사물을 정확히 복제하는게 아니라 목적에 맞게 관심 있는 특성만을 추출해서 표현하는 것
- 추상화를 통해 실제 사물을 단순하게 묘사
클래스 (class)
- 분류, 집합 같은 속성과 기능을 가진 객체를 총칭하는 개념
- 클래스 설계에서 추상화가 사용된다
- 클래스 설계를 위해서는 어플리케이션 경계를 정해야한다 (관심사)
- 객체 지향해서 추상화의 결과는 클래스다
객체 (object)
- 객체는 유일무이하다
- 객체 = 클래스의 인스턴스
- 클래스를 통해 object를 만들었다는 것을 강조하기 위해 instance라고 표현
사람 클래스 (Human class)
- 속성 (명사로 표현되는 특성) - 시력, 몸무게, 혈액형, 키, 나이 등
- 메서드(동사로 표현되는 기능/행위) - 먹다, 자다, 일하다, 운전하다 등
추상화와 T메모리
public class Mouse {
public String name;
public int age;
public int countOfTail;
public void sing(){
System.out.println(name+ "찍찍!");
}
}
public class MouseDriver {
public static void main(String[] args){
Mouse mickey = new Mouse();
mickey.name = "미키";
mickey.age = 85;
mickey.countOfTail =1;
mickey.sing();
mickey = null;
Mouse jerry = new Mouse();
jerry.name = "제리";
jerry.age = 75;
jerry.countOfTail=1;
jerry.sing();
}
}
java.lang / Mouse name, age,counOfTail, sing() / MouseDriver main(args : String[]) | |
-> main() 메서드를 실행하기 직전 T메모리
- Mouse에서 name, age, countOfTail은 이름만 존재, 이 세개의 속성은 Mouse 클래스에 속한 속성이 아닌 Mouse객체에 속한 속성이기 때문에, 객체가 생성되야만 속성의 값을 저장하기 위해 메모리 공간이 힙 영역에 할당된다
- Mouse mickey // Mouse 객체에 대한 참조 변수 mickey를 만든다
- new Mouse() // Mouse 클래스의 인스턴스 변수를 하나 만들어 힙에 배치한다
- 대입문 // Mouse 객체에 대한 주소(포인터)를 참조 변수 mickey에 할당한다
java.lang / Mouse name, age,counOfTail, sing() / MouseDriver main(args : String[]) | |
main() 스텍 프레임 mickey args |
: Mouse name null age 0 countOfTail 0 sing() |
-> Mouse mickey = new Mouse();를 실행한 후의 T메모리
java.lang / Mouse name, age,counOfTail, sing() / MouseDriver main(args : String[]) | |
main() 스텍 프레임 mickey args |
: Mouse name 미키 age 85 countOfTail 1 sing() |
-> mickey.countOfTail=1을 실행한 후의 T메모리
java.lang / Mouse name, age,counOfTail, sing() / MouseDriver main(args : String[]) | |
main() 스텍 프레임 mickey null args |
-> mickey = null 을 실행한 후의 T메모리
- 객체 참조변수 mickey는 더 이상 힙 영역에 존재하는 Mouse 객체(:Mouse)를 참조하지 않고, GC의 대상이되어 삭제된다
java.lang / Mouse name, age,counOfTail, sing() / MouseDriver main(args : String[]) | |
main() 스텍 프레임 jerry mickey null args |
: Mouse name 제리 age 73 countOfTail 1 sing() |
-> jerry.countOfTail=1을 실행한 후의 T메모리
- 힙 영역의 Mouse 객체는 이전의 Mouse 객체가 아니고 새로운 Mouse 객체다
클래스 멤버 vs. 객체 멤버 = static 멤버 vs.인스턴스 멤버
- 객체는 유일무이하게 존재하는 실체이기에 속성에 값을 가지고, 클래스는 개념이면서 분류체계이므로 속성에 값을 가질 수 없다.
- 모든 쥐 객체들이 공통된 값을 갖는 속성을 클래스 레벨로 옮긴다 = static
- Mouse 객체가 모두 같은 값을 갖는 꼬리 개수 속성이 있음에도 Mouse 객체 수만큼 메모리를 잡아먹게 된다
- countOfTail 속성에 접근하기 위해 객체를 이용해 객체_참조_변수.countOfTail로 접근하 수 있으며, 클래스명을 이용해 클래스명.countOfTail로 직접 접근할 수 있다.
- 클래스 멤버들은 static 키워드와 함께 사용되고 T메모리의 static 영역에 상주하게 되므로 정적(static) 멤버라고도 함
- 객체 멤버들은 객체가 클래스의 인스턴스이므로 인스턴스 멤버라고도 함
- 클래스 멤버 = static 멤버 = 정적 멤버
- 객체 멤버 = 인스턴스 멤버
클래스 설계 | 클래스 멤버 | static | 클래스 멤버 속성 |
클래스 멤버 메서드 | |||
객체 멤버 | 객체 멤버 속성 | ||
객체 멤버 메소드 |
정적 메서드 사용하기 좋은 시점
정적 메서드는 객체들의 존재 여부와 관계없이 사용할 수 있는 메서드로, 정적 멤버들은 객체가 아닌 클래스에 속해있으며, 클래스는 jvm 구동시 T메모리 스태틱 영역에 바로 배치되기 때문이다.
- main() 메서드는 static이어야 하며
- 정적 변수에 대한 접근자 메서드(getter, setter)
- 클래스의 인스턴스를 만들지 않고 사용하게 되는 유틸리성 메서드
지역변수 vs 멤버 변수
- 지역 변수는 별도 초기화하지 않으면 쓰레기 값을 갖는다
- 지역 변수는 별도 초기화해야한다.
- 멤버 변수(속성)은 자동으로 초기화해준다
- 정수형 0, 부동소수점 0.0, 논리형 false, 객체 null
- 지역 변수는 한 지역에서만 사용하는 변수, 멤버 변수는 공유 변수 성격을 가지고 있다.
- 객체 변수는 하나의 객체 안에서 다수의 객체 메서드가 공유하는 변수이며, 클래스 변수는 전역 변수로서 프로그램 어디서든 접근 가능
- 객체 멤버인 경우, 생성자를 통해 초기화하며, 정적 멤버는 정적 실행 영역을 통해 초기화한다.
상속 : 재사용 + 확장
- 객체 지향의 상속은 계층도/조직도 (부모-자식)이 아니라 분류도이다.
- 상위 클래스의 특성을 하위 클래스에서 상속(특성 상속)하고 거기에 더해 필요한 특성을 추가, 확장해서 사용할 수 있다는 의미다.
- 상위 - 하위 , 슈퍼 - 서브
- 상위 클래스쪽으로 갈수록 추상화, 일반화되며 하위 클래스로 갈 수록 구체화, 특수화되었다
- 하위클래스는 상위클래스다 - LSP(리스코프 치환 원칙)
- 클래스 상속 구조에서 최상위 클래스는 Object이며, 모든 클래스는 결국 Object의 특성을 물려받으며 어떤 클래스의 인스턴스든 toString()을 사용할 수 있다.
- inheritance라는 키워드는 존재하지 않고 extends(확장)이 존재한다.
- 하위 클래스 is a 상위 클래스 => 하위 클래스 is a kind of 상위 클래스
- 객체 지향의 상속은 상위클래스의 특성을 재사용하는 것이다.
- 객체 지향의 상속은 상위클래스의 특성을 확장하는 것이다.
상속과 인터페이스
상속 | 인터페이스 | |
관계 | 하위 클래스 is kind of 상위 클래스 | 구현 클래스 is able to 인터페이스 |
해석 | 하위 클래스는 상위 클래스의 한 분류다 | 구현 클래스는 인터페이스 할 수 있다. |
예제 | 고래는 동물의 한 분류다 | 고래는 헤엄칠 수 있다. |
-> 상위 클래스는 물려줄 특성이 풍성할수록 좋고(LSP 리스코프 치환원칙), 인터페이스는 구현을 강제할 메서드의 개수가 적을 수록 좋다 (ISP 인터페이스 분할원칙)
인터페티스는 be able to 형태
- Serializable 인터페이스 : 직렬화할 수 있는
- Cloneable 인터페이스 : 복제할 수 있는
- Comporable 인터페이스 : 비교할 수 있는
- Runnable 인터페이스 : 실행할 수 있는
상속과 T메모리
public class Animal {
public String name;
public void showName(){
System.out.printf("안녕 나는 %s야. 반가워 \n", name);
}
}
public class Penguin extends Animal{
public String habitat;
public void showHabitat(){
System.out.printf("%s는 %s에 살아\n", name, habitat);
}
}
public class Driver {
public static void main(String[] args){
Penguin pororo = new Penguin();
pororo.name= "뽀로로";
pororo.habitat ="남극";
pororo.showName();
pororo.showHabitat();
Animal pingu = new Penguin();
pingu.name="핑구";
//pingu.habitat = "ebs";
pingu.showName();
//pingu.showHabitat();
//Penguin happyfeet = new Animal();
}
}
- pingu 객체 참조변수가 가르키고 있는 것은 Penguin이 아닌 Animal 인스턴스다
- 따라서 펭귄의 서식지와 서식지를 알려주는 메서드를 사용할 수 없다.
다형성: 사용편의성
- 객체 지향에서 다형성이라면, 오버라이딩과 오버로딩이라고 할 수 있다.
오버라이딩
- 같은메서드 이름, 같은 인자목록으로 상위클래스의 메소드를 재정의
- 하위 클래스가 재정의한 메서드를 알아서 호출해 줌으로써 형변환이나 instaceof 연산자를 써서 하위클래스가 무엇인지 신경쓰지 않아도 된다. => 깔끔한 코드 유지
오버로딩
- 같은메서드 이름, 다른 인자목록으로 다수의 메서드를 중복 정의
- 자바5에서 추가된 제네릭을 사용하면 하나의 함수만 구현해도 다수의 함수를 구현한 효과를 낼 수 있다.
캡슐화 : 정보은닉
- 접근제어자
- private - 본인만 접근 가능
- [default] - 같은 패키지 내의 클래스에서 접근 가능
- protected - 상속 / 같은 패키지 내의 클래스 내에서 접근가능
- public - 모두가 접근 가능
- 상속을 받지 않았다면 객체 멤버는 객체를 생성한 후 객체 참조 변수를 이용하여 접근해야 한다
- 정적 멤버는 클래스명.정적멤버 형식으로 접근하는 것을 권장
- 일관된 형식으로 접근하고, 공통적인 특성으로, 메모리 물리적 접근방법이 더 효율적이기 때문
참조 변수의 복사
public class CallByValue {
public static void main(String[] args){
int a=10;
int b=a;
b=20;
System.out.println(a); // 10
System.out.println(b); // 20
}
}
- call by reference 참조에 의한 호출 : 기본 자료형 변수는 저장하고 있는 값을 그 값 자체로 해석
public class CallByReference {
public static void main(String[] args){
Animal2 ref_a = new Animal2();
Animal2 ref_b = ref_a;
ref_a.age = 10;
ref_b.age = 20;
System.out.println(ref_a); // 20
System.out.println(ref_b); // 20
}
}
class Animal2{
public int age;
}
- call by address 주소에 의한 호출 : 객체 참조 변수는 저장하고 있는 값을 주소(포인터)로 해석
- ref_a와 ref_b는 완전히 다른 변수다. 다만 같은 값을 가지고 있고 컴퓨터는 그 값을 주소로 활용한다. 두 변수는 같은 객체를 참조한다.
- ref_a에 null을 할당하거나 다른 객체의 참조를 할당해보면 ref_b에는 아무런 영향도 주지 못한다
main() 스텍 프레임 ref_b 100 ref_a 100 |
: Animal age 10 |
main() 스텍 프레임 ref_b 100 ref_a 100 |
: Animal age 20 |
-> CallByValue에 의한 실행 전과 후의 T메모리 (참조를 주소값으로 표시)
[참고]
스프링 입문을 위한 자바 객체 지향의 원리와 이해
형변환
- 변수의 자료형이 변환되는 것
- 특정 자료형의 값을 다른 자료형의 변수에 대입 가능
암묵적 형변환
서로 다른 자료형을 연산 혹은 대입하는 경우, 자바 컴파일러가 자료형을 통일한다
원칙 : 표현범위가 좁은 데이터 타입에서 넓은 데이터 타입으로의 변환만 허용된다
why? 데이터가 손실 되기 때문
명시적 형변환 (Explict Conversion)
: 데이터의 손실을 감수하더라도 강제로 형변환 시키는 형태
자료형 b = (변환할 자료형) a;
ex. 실수형을 정수형으로 변환하는 경우 소수점이하 자리는 버려진다
'JAVA > 객체지향의 원리' 카테고리의 다른 글
[객체지향의 원리와 이해 4] 자바가 확장한 객체 지향 (0) | 2023.06.27 |
---|---|
[객체지향의 원리와 이해 2] 자바의 절차적 / 구조적 프로그래밍 (0) | 2023.06.26 |
[객체지향의 원리와 이해 1] 사람을 사랑한 기술 (0) | 2023.06.26 |
[OOP] interface / 인터페이스 (0) | 2022.09.07 |
[OOP] abstract / 추상화 (0) | 2022.09.05 |