-
자바 객체 지향의 원리와 이해Java 2021. 2. 1. 16:26
[스프링 입문을 위한 자바 객체 지향의 원리와 이해] 로 학습 한 내용
1. 자바와 절차적/구조적 프로그래밍
[하나의 프로그램이 실행될 때 프로그램이 메모리를 사용하는 방식] [객체지향 프로그램이 메모리를 사용하는 방식]
[1] main() 메서드 실행시 메모리 사용 방식
1) JRE는 우선 프로그램 안에 main() 메서드가 있는지 확인한다
2) JRE는 Start 클래스에서 main() 메서드 발견
3) main() 메서드가 확인되면 JRE는 프로그램을 실행하기위한 사전준비를함-> JVM 부팅
4) JVM은 목적파일을 받아 실행
5) JVM이 하는 일
(1) 전처리 : java.lang 패키지를 static영역에 배치, 작성한 모든 class와 import 패키지를 static영역에 배치
(2) stack영역에 stack frame할당
(3) 메서드 인자 args를 저장할 변수공간 할당(스택 맨 밑에 확보)
===> 이렇게 메모리 할당 후 첫 명령문 실행!
* 여는 중괄호를 만날 떄 마다 스택프레임이 생성된다 (class 정의 여는 중괄호 제외)
닫는 중괄호 만나면 스택프레임 소멸
* main() 메서드 가 끝나면 JRE는 JVM종료, JRE자체도 운영체제상의 메모리에서 사라진다
[2] 변수의 위치
static : class변수 / stack : 지역변수 / heap : 객체변수
[3] 변수의 종류
지역변수 : 스택프레임에 종속적인 지역변수
전역변수 : 스택프레임에 독립적인 전역변수(=공유변수, 속성,프로퍼티,필드)
** 전역변수 사용을 자제해야하는 이유 : 프로젝트 규모에 따라 코드가 커지면서 여러 메서드에서 전역 변수의 값을 변경하기 시작하면 T 메모리로 추적하지않는ㄴ 이사 전역 변수에 저장돼 있는 값을 파악하기 쉽지 않다.
** 전역상수는 괜찮~!!
[4] 멀티 스레드 / 멀티 프로세스의 이해
멀티 스레드(Multi Thread)의 T 메모리 모델은 스택 영역을 스레드 개수만큼 분할해서 쓰는 것이다.
멀티 스레드는 하나의 T 메모리만 사용하는데 스택 영역만 분할해서 사용하는 구조다.
멀티 스레드는 하나의 T 메모리 안에서 스택영역만 분할한 것이기 때문에, 하나의 스레드에서 다른 스레드의 스택영역에선 접근할 수 없지만, 스태틱과 힙 영역은 공유해서 사용한다. 따라서 멀티프로세스 대비 메모리를 적게 사용할 수 있는 구조다.
멀티 프로세스(Multi Process)는 다수의 데이터 저장 영역, 즉 다수의 T메모리를 갖는 구조다.
멀티 프로세스는 각 프로세스마다 각자의 T 메모리가 있고 각자 고유의 공간이므로 서로 참조할 수 없다.
멀트 프로세스는 하나의 프로세스가 다른 프로세스의 T 메모리 영역을 절대 침범할 수 없는 메모리에 안전한 구조이지만 메모리 사용량은 그만큼 크다.
요약 :
메모리는 static / stack / heap 영역으로 나뉘고 static과 stack에 어떻게 쌓이는지
2. 자바와 객체지향
자바의 4가지 특성
캡슐화 (Encapsulation) : 정보은닉
상속 : 재사용
추상화 (Abstraction) : 모델링
다형성 (Polymorphism) : 사용편의
[1] 추상화 : 구체적인 것을 분해해서 관심 영역(애플리케이션 경계)에 있는 특성만 가지고 재조합하는것 = 모델링
객체 : 세상에 존재하는 유일무이한 사물
클래스 : 분류,집합 같은 속성과 기능을 가진 객체를 총칭하는 개념
==> 세상에 존재하는 유일무이한 객체를 특성(속성+기능)에 따라 분류해 보니 객체를 통칭할 수 있는 집합적 개념, 즉 클래스(분류)가 나오게 된다.
** 클래스를 이용해 object를 만들었다는 것을 강조할 때는 object라는 표현보다 클래스의 인스턴스(instance)라는 표현을 쓴다. 객체(object) = 클래스의 인스턴스
** 애플리케이션의 경계 : 컨텍스트(context)
요점 :
- OOP의 추상화는 모델링이다
- 클래스 : 객체 = 펭귄 : 뽀로로
- 클래스 설계에서 추상화가 사용된다
- 클래스 설계를 위해서는 애플리케이션 경계부터 정해야 한다
- 객체지향에서 추상화의 결과는 클래스다
- 상송을 통한 추상화,구체화
- 인터페이스를 통한 추상화
- 다형성을 통한 추상화
★ 자바는 객체 지향의 추상화를 class를 통해 지원하고 있다 ★
클래스 참조변수 = new 클래스();
==> 클래스 인스턴스, 즉 객체를 생성하기 위해 객체 생성자를 호출
ex) Mouse mickey = new Mouse();
1) Mouse mickey: Mouse 객체에 대한 참조변수 mickey를 만든다
2) Mouse 클래스의 인스턴스를 하나 만들어 힙에 배치한다
3) Mouse 객체에 대한 주소(포인터)를 참조변수 mickey에 할당한다
클래스 멤버 = static 멤버 = 정적멤버
객체 멤버 = 인스턴스 멤버
<< 정적메서드 사용 예 >>
정적 메서드는 객체의 존재 여부에 관계없이 사용할 수 있다. 정적 멤버들은 객체가 아닌 클래스에 속해있으며 JVM구동시 T 메모리 스태틱영역에 바로 배치되기때문에 객체 존재여부와 관계없이 쓸 수 있다.
1) main 메서드
2) getter / setter
3) 클래스의 인스턴스를 만들지 않고 사용하는 유틸리티성 메서드 (Math 클래스)
** 정적 속성인 겨우 T메모리의 스태틱 영역에 클래스가 배치될 때 클래스 내부에 메모리 공간이 확부된다
** 객체 속성은 스태틱 영역에는 속성명만 있고 메모리 공간은 확보하지않는다. 힙 영역에 객체가 생성되면 바로 그 때 각 객체 안에 멤버 속성을 위한 메모리 공간이 할당된다
[2] 상속 : 재사용+확장
- 객체 지향의 상속은 상위 클래스의 특성을 재사용한느 것이다.
- 객체 지향의 상속은 상위 클래스의 특성을 확장하는 것이다.
- 객체 지향의 상속은 is a kine of 관계를 만족해야 한다.
- 인터페이스는 be able to 라는 표현의 형태로 만드는것이 좋다
즉 상위 클래스는 하위 클래스에게 특성(속성,메서드)를 상속해주고, 인터페이스는 클래스가 '무엇을 할 수 있다'라는 기능을 구현토록 강제한다
상속과 T메모리
pororo 인스턴스가 생성(5번째 줄)됐을 때 메모리 상태
** 하위클래스의 인스턴스가 생성될 때 상위 클래스의 인스턴스도 생성된다
[3] 다형서이 사용편의성
다형성과 T메모리
상위클래스인 Animal을 상속받아 재정의했기때문에 (overriding) pingu객체에서 showName을 호출하면 Penguin에서 재정의한 메서드가 호출된다.
** 상위 클래스 타입의 객체 참조 변수를 사용하더라도 하위 클래스에서 오버라이딩(재정의 한) 매서드가 호출된다 **
[4] 캡슐화: 정보은닉
** UML표기법에서 접근제어자
** 속성이나 메서드 아래 밑줄을 사용한 경우 : 정적 멤버를 나타낸다
접근제어자가 객체 멤버(인스턴스 멤버)와 쓰일 때와 정적 멤버(클레스 멤버)와 쓰일 대를 비교해서 살펴보자
정적 멤버에 접근 할 때는 객체참조변수명.정적멤버 형식보다 클래스명.정적멤버 형식으로 접근하는편이 좋다
3. 자바가 확장한 객체지향
[1] 추상클래스
- 선언부는 있는데 구현부가 없다
- 객체를 만들 수 없다
- 추상 메서드는 하위 클래스에게 메서드 구현을 강제한다
- 추상 메서드를 포함하는 클래스는 반드시 추상 클래스여야한다
[2] 생성자
- 아무런 생성자도 만들지 않으면 자바는 인자가 없는 기본 생성자를 자동으로 만들어준다
- 인자가 있는 생성자를 하나라도 만든다면 자바는 기본 생성자를 만들어주지않는다
[3] static 블록
public class test{
static {
/// staitc 블록
}
}
클래스 정보는 main메서드 실행 시 바로 메모리에 적재되는것이 아니라 해당 클래스가 처음 사용될 때 static 영역에 로딩된다. 이 때 단 한번 해당 클래스의 static 블록이 실행된다. 클래스가 제일 처음 사용되는 경우는 다음 세가지이다.
- 클래스의 정적 속성을 사용할 때
- 클래스의 정적 메서드를 사용할 때
- 클래스의 인스턴스를 최초로 만들 때
** @JUnit 의 @BeforeClass 어노테이션 을 참고하면 좋다
** static 블록과 유사하게 클래스의 인스턴스를 위한 인스턴스 블록도 존재한다. 아무런 표시 없이 {} 블록을 사용하게되면 인스턴스가 생성될 때마다 {}블록이 실행된다. {}블록은 객체 생성자가 실행되기 전에 먼저 실행된다
[4] final키워드
** final키워드는 클래스,변수,메서드에 붙을 수 있다.
1. final과 클래스
public final class cat{}
클래스에 붙은 final의미 : 상속을 허락하지않겠다. 따라서 하위클래스를 만들 수 없음
2. final과 변수
1234567891011121314151617181920212223242526272829public class cat(){final static int 정적상수1 = 1;final static int 정적상수2;final int 객체상수1 = 1;final int 객체상수2;static{정적상수2 = 2;//상수는 한 번 초기화되면 값을 변경할 수 없다// 정적상수2 = 4;}cat(){객체상수2 = 2;//상수는 한 번 초기화되면 값을 변경할 수 없다// 객체상수2 = 4;final int 지역상수1 = 1;final int 지역상수2;지역상수2 = 2;}}변수에 final이 붙으면 초기화 후 값 변경을 할 수 없다.
(1) 정적상수 : 정적 생성자에 해당하는 static블록엡서 초기화 가능
(2) 객체상수 : 객체 생성자 또는 인스턴스 블록에서 초기화 가능
(3) 지역상수 : 선언시 또는 최초 한 번만 초기화 가능
3. final과 매서드
매서드에 붙은 final의 의미: 재정의 즉 오버라이딩 불가능
[5] instanceof 연산자
특정 클래스의 인스턴스인지 확인하는 연산자. true나 false 반환함.
[6] this키워드
main메서드 실행 후 메모리 상태
위 코드에서 var는 객체변수도 있고 지역변수도 있다.
- 지역 변수와 속성(객체 변수, 정적 변수)의 이름이 같은 경우 지역변수가 우선한다.
- 객체 변수와 이름이 같은 지역 변수가 있는 경우 객체변수를 사용하려면 this를 접두사로 사용한다
- 정적 변수와 이름이 같은 지역변수가 있는경우 정적 변수를 사용하려면 클래스명을 접두사로 사용한다
[7] Super키워드
상위 클래스의 인스턴스를 지칭한다
4. 객체 지향 설계 5원칙 - SOLID
좋은 소프트웨어 설계를 위해서는 결합도(coupling)는 낮추고 응집도(cohesion)는 높이는것이 바람직하다.
- 결합도는 모듈(클래스)간의 상호 의존 정도로서 결합도가 낮으면 모듈 간의 상호 의존성이 줄어들어 객체의 재사용이나 수정,유지보수가 용이하다.
- 응집도는 하나의 모듈 내부에 존재하는 구성요소들의 기능적 관련성으로 응집도가 높은 모듈은 하나의 책임에 집중하고 독립성이 높아져 재사용이나 기능의 수정, 유지보수가 용이하다.
[1] SPR - 단일 책임 원칙 (어떤 클래스를 변경해야하는 이유는 오직 하나뿐이어야한다, 추상화)
[2] OCP - 개방 폐쇄 원칙 (자신의 확장에는 열려있고, 주변의 변화에 대해서는 닫혀있어야한다, JDBC)
[3] LSP - 리스코프 치환 원칙 (하위 클래스의 인스턴스는 상위형 객체 참조 변수에 대입해 상위 클래스의 인스턴스 역할을 하는데 문제가 없어야한다[서브타입은 언제나 자신의 기반 타입으로 교체할 수 있어야한다], 상속)
[4] ISP - 인터페이스 분리 원칙 (클라이언트는 자신이 사용하지 않는 메서드에 의존관계를 맺으면 안 된다)
[5] DIPS - 의존 역전 원칙 (자신보다 변하기 쉬운 것에 의존하지마라)