기계중심의 기계어에서 조금 더 인간을 편하게 하는 어셈블리어, C, C++, 자바로 발전해 온 과정 모두 로우 레벨의 기계가 아닌 하이 레벨의 인간을 배려하기 위한 과정
그러나 절차적/구조적 프로그래밍까지의 과정은 인간이 기계를 이해하려는 노력에서 크게 벗어나지 못함
➡️ "왜 우리가 기계 종속적인 개발을 해야 하는가?"하는 의문
➡️ "우리가 눈으로 보고, 느끼고, 생활하는 현실 세계처럼 프로그래밍할 수는 없을까?"라는 고민
기존의 구조적 프로그래밍 언어에서 가장 중요한 것은 "함수"
함수는 코드를 논리적인 단위로 구분하고 분할해서 정복하는 것.(Devide and Conquer)
함수로 인해 프로그래밍이 조금 더 편해지고 나서 더욱 파격적인 제안이 나왔는데, 그것이 바로 "객체 지향"
"우리가 주변에서 사물을 인지하는 방식대로 프로그래밍 할 수 있지 않겠는가"하는 것이 객체 지향의 출발
0과 1로 대변되는 기계에 맞춰 사고하던 방식을 버리고 현실세계를 인지하는 방식으로 프로그램을 만들자는 것
사물을 하나하나 이해하기보다는 사물을 분류(Class)해서 이해하는 것이 인간의 인지법
클래스는 분류에 대한 개념이지 실체가 아님 <-> 객체는 실체
클래스를 이용해 object를 만들었다는 것을 강조할 때 object라는 표현보다는 클래스의 인스턴스(instance)라는 표현을 씀
객체(object) = 클래스의 인스턴스
사람이라는 분류(class) 안에 김연아(object), 박지성(object), 손흥민(object)들이 존재하고 객체(object)들은 나이, 몸무게, 키 등의 속성(property)과 먹다, 자다, 운동하다 등의 행위(method)룰 가지고 있다.
객체 지향에서는 우리가 주변에서 실제 사물을 인지 및 사고하는 방식대로 객체 단위의 프로그래밍이 가능
➡️ 객체 지향은 인간의 인지 및 사고 방식까지 프로그래밍에 접목하는 인간(개발자) 지향을 실천하고 있는 것
➡️ 객체 지향은 직관적
캡슐화(Encapsulation): 정보 은닉(Information hiding)
상속(Inheritance): 재사용
추상화(Abstraction): 모델링
다형성(Polymorphism): 사용 편의
추상화란 구체적인 것을 분해해서 관심 영역(애플리케이션 경계,Context)에 있는 특성만 가지고 재조합하는 것
= 모델링
모델은 실제 사물을 정확히 복제하는 게 아니라 목적에 맞게 관심 있는 특성만을 추출해서 표현하는 것
➡️ 추상화를 통해 실제 사물을 단순하게 묘사하는 것
모델링(추상화)은 객체 지향에서 클래스를 설계할 때, 그리고 데이터베이스의 테이블을 설계할 때 필요한 기법
- OOP의 추상화는 모델링이다.
- 클래스 : 객체 == 판다 : 푸바오
- 클래스 설계에서 추상화가 사용된다.
- 클래스 설계를 위해서는 애플리케이션 경계부터 정해야 한다.
- 객체 지향에서 추상화의 결과는 클래스다.
- 상속을 통한 추상화, 구체화
- 인터페이스를 통한 추상화
- 다형성을 통한 추상화
클래스와 객체 관계를 자바에서는 어떻게 표현할까?
클래스 객체_참조_변수 = new 클래스();
클래스 | 객체참조변수 | = | new | 클래스 | ( ) |
---|---|---|---|---|---|
객체참조변수의 자료형(Type) | 생성된 객체를 참조 할 수 있는 변수 | 할당문 | 새로운 | 만들고자 하는 객체의 분류 | 메서드 |
새로운 객체를 하나 생성해 그 객체의 주소값(포인터)을 객체 참조 변수에 할당
new 클래스( ) -> 클래스의 인스턴스를 생성하기 위해 객체 생성자를 호출
객체명 | 미키마우스 | 제리 |
---|---|---|
속성들 | 성명 : 미키마우스 국적 : 미국 나이 : 91 종교 : 기독교 신장 : 70cm 체중 : 3kg 애완동물 : 플루토 여자친구 : 미니마우스 꼬리 1개 | 성명 : 제리 국적 : 미국 나이 : 89 친구 : 톰 여자친구 : null 꼬리 : 1개 |
------- | ------------------------- | --------------- |
행위들 | 달리다( ) 먹다( ) 휘파람불다( ) 데이트하다( ) 울다( ) | 달리다( ) 먹다( ) 장난치다( ) |
객체들을 관찰해 쥐 클래스 설계를 한다.
클래스 설계에서 제일 중요한 것은 추상화.
추상화를 통해 애플리케이션 경계에서 관심 있는 특성들만 뽑아 온다.
추상화의 결과물은 모델, 모델은 자바에서 클래스로 표현
클래스 모델을 표현하는 국제 표준 표기법은 UML 클래스 다이어그램
⬇️ 쥐 클래스의 UML 클래스 다이어그램 (쥐 클래스의 논리적 설계)
쥐 |
---|
성명 나이 꼬리수 |
--------------------------------------------------------------- |
먹다( ) |
⬇️ 쥐 클래스의 물리적 설계
Mouse |
---|
+name: String +age: int +countOfTail: int |
--------------------------------------------------------------- |
+eat( ):void |
⬇️ 예제 코드
package abstraction01;
public class Mouse{
public String name;
public int age;
public int countOfTail;
public void eat() {
System.out.println(name + "찍찍!!!");
}
}
------------------------------------------
package abstraction01;
public class MouseDriver {
public static void main(String[] args) {
Mouse mickey = new Mouse();
mickey.name = "미키"
mickey.age = "91"
mickey.countOfTail = 1;
mickey.eat();
mickey = null;
Mouse jerry = new Mouse();
jerry.name = 제리;
jerry.age = 89;
jerry.countOfTail = 1;
jerry.eat();
}
}
- 스태틱 영역 메모리에 java.lang 패키지, MouseDriver 클래스, Mouse 클래스가 위치함
- Mouse클래스의 name, age, countOfTail에는 변수 저장 공간은 없는 상태
➡️ 위 세개의 속성은 Mouse 클래스에 속한 속성 X , 객체에 속한 속성이기 때문
➡️ 객체가 생성돼야만 속성의 값을 저장하기 위한 메모리 공간이 스태틱 영역이 아닌 힙 영역에 할당
-참고-
UML 표기법에서 클래스 멤버는 밑줄, 객체 멤버는 밑줄 없이 표현
따라서 main() 메서드는 밑줄 존재,eat() 메서드는 밑줄 없이 표현
클래스 멤버와 객체 멤버를 구분하는 자바 키워드는 static
Mouse mickey -> Mouse 객체에 대한 참조 변수 mickey를 만든다.
스택 메모리 영역에 main()스택 프레임 생성되어있음, args 변수 공간 맨 아래에 확보
main()스택 프레임 내부에 mickey 변수 메모리 공간 생성
new Mouse -> 객체 생성자 호출
힙 영역에 : Mouse 인스턴스 메모리 공간 생성
힙 영역에 저장된 Mouse 클래스의 인스턴스의 시작 주소가 100번지라고 가정하면
스택 메모리 영역의 mickey(객체 참조 변수)에 할당되는 값은 100
힙 영역의 인스턴스 : Mouse의 name에 "미키" 할당됨
메모리상의 변화 없음
객체 참조 변수 mickey가 참조하는 Mouse 객체의 eat() 메서드가 코드 실행 영역에서 실행
mickey의 값 100 -> null로 바뀜
따라서 객체 참조 변수 mickey는 더 이상 힙 영역에 존재하는 Mouse 객체(: Mouse)를 참조 X
Garbage Collector가 아무도 참조하지 않는 Mouse 객체(: Mouse)를 제거
클래스는 개념이면서 분류 체계일 뿐 속성에 값을 가질 수 없다.
그러나 위의 질문에서 보면 쥐는 클래스인데도 꼬리 개수에 답이 있다.
꼬리 개수는 객체의 속성이지만 모든 객체가 같은 값을 가지고 있기 때문
이러한 경우 우측 메모리에서 보면 쥐 클래스의 모든 쥐 객체들(:Mouse)은 같은 countOfTail 값을 가질 것
public class Mouse{
public String name;
public int age;
public static int countOfTail = 1;
public void eat() {
System.out.println(name + "찍찍!!!");
}
이제 countOfTail 속성은 우측 메모리의 스태틱 영역에 단 하나의 저장 공간을 갖게 된다.
( 힙 영역의 Mouse 클래스 내부 countOfTail로 변경 )
countOfTail 속성에 접근하기 위해서는 객체를 이용해 객체참조변수.countOfTail로 접근 가능
클래스를 이용해 클래스명.countOfTail로도 접근 가능
클래스 설계 | 정적 멤버 (클래스 멤버) ------------------------- 인스턴스 멤버 (객체 멤버) | static ------- heap | 정적 멤버 속성 (클래스 멤버 속성) 정적 멤버 메서드 (클래스 멤버 메서드) --------------------------------------------- 인스턴스 멤버 속성 (객체 멤버 속성) 인스턴스 멤버 메서드 (객체 멤버 메서드) |
---|
정적 메서드는 객체들의 존재 여부에 관계없이 쓸 수 있는 메서드
정적 멤버들은 객체가 아닌 클래스에 속해 있음
일단 main() 메서드는 당연히 정적 메서드여야 함
main()메서드의 논리를 함수로 분할해서 사용하는 경우
정적 변수에 대한 접근자 메서드(getter)와 설정자 메서드(setter)로 사용하는 용도
이름 | 다른 이름 | 사는 곳 |
---|---|---|
static 변수 | 클래스[멤버] 속성, 정적 변수, 정적 속성... | 스태틱 영역 |
인스턴스 변수 | 객체[맴버] 속성, 객체 변수... | 힙 영역 |
local 변수 | 지역 변수 | 스택 영역(스택 프레임 내부) |
정적 속성의 경우 스태틱 영역에 클래스가 배치될 때 클래스 내부에 메모리 공간이 확보됨
객체 속성의 경우 속성명만 있지 실제 메모리 공간은 확보하지 않음
객체 속성은 힙 영역에 객체가 생성되면 바로 그때 각 객체 안에 멤버 속성을 위한 메모리 공간 할당
스택 영역안에 생기는 변수를 지역 변수라 함
지역 변수는 개발자가 별도로 초기화하지 않으면 쓰레기 값 가짐
정적 속성과 객체 속성은 별도의 초기화를 해주지 않아도 기본값으로 초기화 됨
➡️ 멤버 변수는 공유 변수의 성격을 가지고 있기 때문
김종민, '스프링 입문을 위한 자바 객체 지향의 원리와 이해', 위키북스 참고