현실 세계 | 가상 세계 |
---|---|
소프트웨어 개발 도구 | JDK - 자바 개발 도구 // JVM용 소프트웨어 개발 도구 |
운영체제 | JRE - 자바 실행 환경 // JVM용 OS |
하드웨어 - 물리적 컴퓨터 | JVM - 자바 가상 머신 // 가상의 컴퓨터 |
(JDK: Java Development Kit / JRE: Java Runtime Environment / JVM: Java Virtual Machine)
배포되는 JDK, JRE, JVM은 편의를 위해 JDK가 JRE를 포함, JRE는 JVM을 포함하는 형태로 배포
JDK는 자바 소스 컴파일러인 javac.exe를 포함, JRE는 자바 프로그램 실행기인 java.exe 포함
➡️ 기존 언어로 작성한 프로그램은 각 플랫폼(하드웨어와 OS의 조합)용으로 배포되는 설치 파일을 따로 준비해야했던 불편함 해결
➡️ 각 플랫폼(윈도우10, 맥 OS, 리눅스 등)에 맞는 JVM이 중재자로서 각 플랫폼에서 프로그램을 구동하는 데 아무 문제가 없게끔 만들어 줌
코드 실행 영역 | 스태틱(Static)영역 ------------------------------------- 스택(Stack)영역 / 힙(Heap) 영역 |
---|
➖ 예제 코드
pubilic class Start() {
public static void main(String[] args {
System.out.println("Hello OOP!!");
}
}
}
➖ 위 코드가 실행될 때의 메모리에서의 변화는 다음과 같다
(스태틱, 스택, 힙 영역의 메모리를 우측 메모리라 칭하겠음)
JRE는 먼저 프로그램 안에 main() 메서드가 있는지 확인
main() 메서드의 존재가 확인되면 JRE는 프로그램 실행을 위한 사전 준비 착수
(가상 머신인 JVM에 전원을 넣어 부팅)
부팅된 JVM은 오브젝트 파일을 받아 그 오브젝트 파일을 실행
JVM이 가장 먼저 하는 일은 전처리
모든 자바 프로그램이 반드시 포함하게 되는 패키지인 java.lang 패키지를 메모리의 스태틱 영역에 가져다 놓음
다음으로 JVM은 개발자가 작성한 모든 클래스와 임포트 패키지 또한 스태틱 영역에 가져다 놓음
main() 메서드가 실행되기 전 JVM에서 수행하는 전처리 작업
- java.lang 패키지를 메모리의 스태틱 영역에 배치
- import된 패키지를 메모리의 스태틱 영역에 배치
- 프로그램 상의 모든 클래스를 메모리의 스태틱 영역에 배치
클래스 정의를 시작하는 중괄호를 제외한 여는 중괄호를 만날 때마다 스택메모리에 스택 프레임 생성
메서드의 인자 args를 저장할 변수 공간을 스택 프레임의 맨 밑에 확보(메서드 인자들의 변수 공간 할당)
(지역변수를 선언했다면 args위로 차곡차곡 쌓임)
main() 메서드 안의 첫 명령문 실행
System.out.println("Heelo OOP!!") 구문 실행 후에 우측메모리에는 변화 없음
-> 메모리에서 코드 실행 공간은 별도로 있기 때문
닫는 중괄호를 만나면 스택 프레임 소멸됨
따라서 main() 메서드의 끝을 나타내는 닫는 중괄호를 만나면 스택 영역에서 스텍 프레임 소멸
main()메서드가 끝나면 JRE는 JVM 종료시키고 JRE 자체도 운영체제 상의 메모리에서 사라짐
코드를 실행중에 if문을 만난다면, if는 조건에 따라 분기를 일으킬 것이다.
if문의 여는 중괄호를 만난다면 메서드의 스택 프레임이 아닌 if문 블록의 스택 프레임이 생성된다.
참 또는 거짓에 해당하는 if(true or false) 스택 프레임이 main() 스택 프레임 안에 중첩하여 생성된다.
블록을 종료하는 닫는 중괄호를 만나면 if 블록 스택 프레임은 스택영역에서 사라진다.
(if 블록 스택 프레임 안에 상주하던 변수의 저장 공간도 함께 사라짐)
➡️ 스택 메모리 내의 스택 프레임 안의 변수를 지역 변수라 하는 이유
(그 지역에서만 사용 가능, 지역이 사라지면 함께 소멸)
지역 변수 : 스택 영역, 스택 프레임 안에서 일생을 보냄. 스택 프레임 소멸시 함께 소멸
클래스 멤버 변수 : 스태틱 영역에서 일생을 보냄. 스태틱 영역에 한번 자리 잡으면 JVM이 종료될 때 까지 static 상태로 그 자리 지킴
객체 멤버 변수 : 힙 영역서 일생을 보냄. 객체 멤버 변수들은 객체와 함께 garbage collector라고 하는 힙 메모리 회수기에 의해 소멸
한 메서드에서 다른 메서드 내의 지역 변수에 접근 불가
메서드를 호출하면서 인자로 전달되는 것은 변수 자체가 아니라 변수가 저장한 값만을 복제해서 전달
메서드 사이에 값을 전달하거나 반환하는 방법은 메서드의 인자와 반환값으로만 가능 (전역변수는 사용 X)
<-> Call by Refernce
인자로 레퍼런스 전달, 메서드 내에서 인자 값이 변하면 변수값도 변함
자바 공식 문서에서 goto는 not used임을 확인 가능
goto를 사용하게 되면 프로그램의 실행 순서가 인간이 이해하기에 너무 복잡해질 가능성 O
goto를 이용한 이동은 프로그램을 논리적으로 잘 구성하면 모두 피할 수 있는 것들
함수 사용 장점
둘은 다르지 않다. 객체 지향에서는 좀 다르게 부르기 위함
굳이 차이점을 찾자면 함수는 클래스나 객체와 아무 관련이 없으나 메서드는 반드시 클래스 정의 안에 존재해야 함
자바의 예약어 중 구조적/절차적 프로그래밍의 유산이라 할 수 있는 것들(✔️표시)
abstract | ✔️continue | ✔️for | New | ✔️switch |
assert | ✔️default | ✔️goto | Package | ✔️synchronized |
✔️boolean | ✔️do | ✔️if | private | this |
✔️break | ✔️double | implement | protected | thorw |
✔️byte | ✔️else | ✔️import | public | thorws |
✔️case | enum | instanceof | ✔️return | transient |
catch | extends | ✔️int | ✔️short | try |
✔️char | final | interface | static | ✔️void |
class | finally | ✔️long | ✔️stricfp | ✔️volatile |
✔️const | ✔️float | ✔️native | super | ✔️while |
------------------ | ------------------ | ------------------- | ------------------ | ------------------ |
예제
: 두 개의 스레드로 구성된 프로그램
스레드 1 : 공유 영역(스태틱, 힙)에 있는 전역 변수 A에 10 할당
CPU 사용권이 스레드 2로 넘어감
스레드 2 : 전역 변수 A에 20을 할당
CPU 사용권이 다시 스레드 1로 넘어감
A의 값 출력
➡️ 스레드 1 입장에서는 갑자기 20이라는 값이 출력되는 문제 발생
🟦 프로그래밍 패러다임
- 선언형 프로그래밍 : '무엇을 풀어내는가에 집중'
- 함수형 프로그래밍 : 선언형 프로그래밍의 일종
순수 함수들을 쌓아 로직 구현 + 고차 함수를 통해 재사용성 높임
(순수 함수 - output이 input에만 의존)
(고차 함수 - 함수가 함수를 값처럼 매개변수로 받아 로직 생성 가능
변수나 매서드에 함수 할당, 함수 안에 함수를 매개변수로, 함수가 함수 반환 OK)
- 명령형 프로그래밍
- 객체지향 프로그래밍
: 객체들의 집합으로 프로그램의 상호작용 표현,
데이터를 객체로 취급 + 객체 내부에 선언된 메서드를 활용하는 방식- 절차형 프로그래밍
: 로직이 수행되어야 할 연속적인 계산 과정으로 이루어짐
코드의 가독성 좋음, 실행 속도 빠름
모듈화 어려움, 유지보수성 나쁨
김종민, '스프링 입문을 위한 자바 객체 지향의 원리와 이해', 위키북스 참고