1) java -classpath bin com.basic.ex07.Exam0410
=> JVM은 클래스 정보를 Method Area 영역에 로드한다.
2) main() 호출
=> JVM Stack 영역에 main() 메서드가 사용할 로컬 변수를 준비한다.
3) swap() 호출
=> JVM Stack 영역에 swap() 메서드가 사용할 로컬 변수를 준비한다.
4) swap() 실행 완료
=> JVM Stack 영역에 있던 swap()이 사용한 메모리를 제거한다.
5) main() 실행 완료
=> JVM Stack 영역에 있던 main()이 사용한 메모리를 제거한다.
6) JVM 실행 종료
=> JVM이 사용한 모든 메모리를 OS에 반납한다.
JVM 종료하면 사용한 모든 메모리를 OS에 반납
실제 Method Area에는 소스가 아니라 byte code (class 파일) 올라감
.class 파일 명령코드
static 변수
new 명령으로 생성된 인스턴스
Garbage collector가 관리하는 영역
스레드 별로 JVM stack 메모리를 따로 관리
메서드 호출때마다 생성하는 로컬변수
파라미터도 로컬변수
각 메서드마다 프레임 단위로 관리
메서드 호출 끝나면 그 메서드가 사용한 프레임 메모리 제거
스택방식 = LIFO Last In Fist Out 후입선출
.class -> 메서드
method area에 올릴 때
통째로 올리는 것이 아님
꺼내서 관리하고 사용하기 쉽도록 적절하게 배치
Exam.java
class A {}
class B {}
class C {}
public class Exam{}
컴파일 하면?
A.class
B.class
C.class
Exam.class
각각의 블록에 대해 클래스파일 생성됨
Exam.java
class Exam {
class A {} // nested class
class B {}
m1() {
class C {}
}
}
Nested class 중첩클래스
컴파일하면
Exam.class
Exam$A.class
Exam$B.class
Exam$C.class
각 클래스 블록별로 .class 파일이 생성됨
참고 ex07.Exam0430.java
Method area
Exam0430$MyObject.class – int a, int b
Exam 0430.class - getMyObject
JVM stack ( thread 별로 존재 )
main() – 변수 args, ref
변수 arg에서 call한 getMyObject() – 변수 ref
변수 ref 에 주소값 입력 -> ref.a -> a 주소로 가서 값 할당
return 시 main 의 ref로 가서 주소값 호출 – 호출된 변수값 출력
getMyObject 호출이 끝나면 메모리에서 삭제됨
Heap
new MyObject() – int a, int b 주소자리 할당
MyObject 설계도 따라 만든 변수 a, b = MyObject의 인스턴스
ex07.Exam0450
static int sum(int value) {
if (value == 1)
return 1;
return value + sum(value - 1);
}
public static void main(String[] args) {
System.out.println(sum(5));
}
0) 시작
1) main()
2) main() => sum(5)
=> 5 + sum(4)
=> 4 + sum(3)
=> 3 + sum(2)
=> 2 + sum(1)
=> 1
3) main()
4) 종료
같은 이름이지만 같은 local 변수를 공유하지는 않음
다른 메소드를 호출한 것이라고 생각
새로운 method 스택 생성
수학식을 코드로 표현하기 용이함, 코드 간결
반복문보다 코드 구현 편함
메서드 호출이 너무 깊게 들어가지 않는 작은 수 계산에서 활용
스택오버플로우 발생할 수 있음
멈춰야 할 조건 필수 – 없으면 메모리 극한으로 증가하여 스택오버플로우 발생
JVM 스택 메모리가 꽉 차서 더 이상 메서드 실행을 위해 로컬변수를 만들 수 없는 상태
호출하는 메서드의 로컬 변수가 클 때는 스택 메모리가 빨리 참
=> 메서드 호출 회수에 영향 받는게 아니라, 메서드에서 생성하는 로컬 변수의 크기에 영향
메서드명, 파라미터 타입과 개수, 순서, 리턴타입을 가리킴
int plus(int a, int b) // -> 메서드 시그니처 = function prototype (in C언어)
{
-------------- // -> 메서드 바디 body
}
JVM이 클래스를 실행할 때 main() 메서드 호출
메인 메서드는 반드시 다음과 같은 메서드 시그너처(함수 프로토타입)를 가져야함
public static void main(String[] 변수명)
JVM 실행할 때 프로그램에 전달하는 값
ex. java -cp bin Exam0520 aaa bbb cccc
[aaa]
[bbb]
[cccc]
aaa bbb cccc - 프로그램 아규먼트
스트링 배열에 담겨서 main()를 호출할 때 넘어옴
공백을 기준으로 문자열 잘라서 배열 만듦
아규먼트 없으면 빈 배열이 넘어옴
아규먼트 넘기기
$ java 클래스명 값1 값2 값3
아규먼트는 공백으로 구분
main() 호출시 배열 주소 넘김
ex07.Exam0610
$java -cp ./bin/main -D이름=값 -D이름=값 -D이름=값
System.getProperty("이름");
String value1 = System.getProperty("a");
String value2 = System.getProperty("b");
String value3 = System.getProperty("c");
directory> java -Da=okok -cp app\bin\main -Db=haha
Run configurations > Arguments > VM arguments 수정
java.lang. System. getProperty (“aa”)
패키지명 클래스 메서드function 인자argument
println() = 출력 + 줄바꿈
값을 주지 않고 System.out.println(); 만 입력시 단순 줄바꿈 수행
print() 는 출력만 줄바꿈X
이스케이프 문자 \n 으로 줄바꿈 수행
System.out.print(“OK!\n”); = System.out.println(“OK!”)
printf() – 출력값 형식 지정
형식 지정하지 않으면 print()와 같음
%s : 지정한 자리에 문자열 삽입, 삽입할 값은 오른쪽에 설정
%d : 정수 값을 10진수 문자열로 만들어 삽입
%x : 정수 값을 16진수 문자열로 만들어 삽입
%c : 정수 값을 문자로 만들어 삽입
%b : true/false 값을 문자열로 만들어 삽입
한 개의 값을 여러 곳에 삽입할 수 있음
%[n$]s : n은 문자열에 삽입될 값의 순서, 1부터 증가
1$ => 65, 2$ => 66, 3$ => 67
System.out.printf("%2$d %2$x %2$c\n", 65, 66, 67);
2$에 해당되는 66 만 입력됨
값을 삽입할 때 사용할 공간 지정 가능
문자열 삽입할 때
%[-][사용할공간너비]s : -는 왼쪽 정렬, 안 붙이면 기본 오른쪽 정렬
정수를 삽입할 때:
%[0][사용할공간너비]d : 앞의 빈자리는 0으로 채우기
%[+][0][사용할공간너비]d : +는 숫자 앞에 부호를 붙임
java.util.Date today = new java.util.Data();
레퍼런스 클래스
-> Date 설계도따라 현재 일시정보 담은 변수 생성
“인스턴스” = “객체”
레퍼런스 – 인스턴스의 주소를 저장하는 변수, 객체를 가리키는 변수
Date 클래스의 인스턴스를 생성하고 today 레퍼런스로 그 객체(인스턴스)를 가리키는 것
%[n$]_ : n은 문자열에 삽입될 값의 순서 - 1부터 증가
%t[날짜 및 시각 옵션] - %1$t_
Y : 날짜 및 시각 데이터에서 년도를 추출하여 4자리로 표현. 2021
y : 날짜 및 시각 데이터에서 년도를 추출하여 뒤의 2자리로 표현. 21
B : 날짜 및 시각 데이터에서 월을 추출하여 전체 이름으로 표현. January
b : 날짜 및 시각 데이터에서 월을 추출하여 단축 이름으로 표현. Jan
m : 날짜 및 시각 데이터에서 월을 추출하여 2자리 숫자로 표현. 06
d : 날짜 및 시각 데이터에서 일을 추출하여 2자리 숫자로 표현. 01, 21
e : 날짜 및 시각 데이터에서 일을 추출하여 1자리 숫자로 표현. 1, 21
A : 날짜 및 시각 데이터에서 요일을 추출하여 긴 이름으로 표현. 월요일, Monday
a : 날짜 및 시각 데이터에서 요일을 추출하여 짧은 이름으로 표현. 월, Mon
H : 날짜 및 시각 데이터에서 시각을 추출하여 24시로 표현. 16
I : 날짜 및 시각 데이터에서 시각을 추출하여 12시로 표현. 04
M : 날짜 및 시각 데이터에서 시각을 추출하여 분을 표현. 45
S : 날짜 및 시각 데이터에서 시각을 추출하여 초를 표현.
L : 날짜 및 시각 데이터에서 시각을 추출하여 밀리초를 표현.
N : 날짜 및 시각 데이터에서 시각을 추출하여 나노초를 표현.
p : 오전 오후 출력하기.
소문자 t를 사용하면 am 또는 pm으로 출력
대문자 T를 사용하면 AM 또는 PM으로 출력
한글은 대소문자가 없기 때문에 의미XX
년-월-일 시:분:초 출력하기
System.out.printf("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS\n", today);
2021-06-21 16:45:51
InputStream은 바이트 단위로 읽는 기능
바이트 단위로 읽어서 int나 문자열로 바꾸려면 재코딩 해야함
이런 불편함을 줄이기 위해 자바에서는 바이트를 개발자가 원하는 값으로 바꿔주는 기능 제공
-> java.util.Scanner 키보드를 스캐너에 연결한다.
new Scanner(keyboard) -> 키보드에서 읽음
그 외 new Scanner(file ,memory, lancard . . .)
Scanner 도구를 사용하여 키보드로부터 한 줄의 문자열을 가져올 때 사용하는 명령
사용자가 한 줄 입력할 때까지, 입력 데이터에 줄바꿈 0d0a 2바이트가 들어올 때까지 대기
엔터키 입력 -> 입력값으로 0d0a 2바이트 -> 그 전까지 들어온 데이터를 문자열로 만들어 리턴
표준 출력 장치. 콘솔(모니터, 명령창)
표준 입력 장치. 키보드
nextInt()는 한 개의 토큰(token)이 입력될 때까지 대기
한 개의 token을 읽으면 4바이트 정수 값으로 바꾼 다음에 리턴
중간에 여러 개의 공백이 들어가더라도 한 개의 공백으로 간주
설정한 데이터타입과 다른 데이터 입력시? -> 실행 오류 발생
Exception in thread "main" java.util.InputMismatchException
System.out.print("int: ");
int i = keyboard.nextInt();
System.out.print("float: ");
float f = keyboard.nextFloat();
System.out.print("boolean: ");
boolean b = keyboard.nextBoolean();
사용자가 키보드 통해 값 입력 – 내부 메모리(버퍼)에 보관
이번에 출력되지 않은 값은 버퍼에 보관됨
버퍼에 보관된 입력값을 꺼낸다
ex.
100 3.14 입력시? -> 아직 boolean 값을 입력받지 못해서 또다시 공백 입력될 때 까지 커서 대기
100 3.14 true 입력시? -> 공백과 함께 입력받아야 할 값들을 다 입력받아서 바로 결과 출력
nextInt는 키보드 버퍼에 값 들어올때까지 대기
nextInt()는 한 개의 토큰을 읽은 후에 줄 바꿈 코드는 읽기 전 상태로 둠
-> 줄바꿈 코드는 읽지않고 두는 것
다음에 nextLine()을 호출하면 의도치 않게 빈 문자열을 가진 한 줄을 읽음
nextLine() 을 호출할 때 값을 입력받는 것이 아니라 공백을 반영해버림
=> nextInt() 다음에 nextLine()을 호출할 때 발생
nextInt()를 호출한 후 남아있는 엔터 코드를 읽어서 제거
keyboard.nextLine(); // 남아 있는 빈 문자열의 한 줄(LF 코드)을 읽어서 버림
입력 : 100 aaa true
nextInt() 에 100 전달
next() 가 뒤 공백부터 그 다음 공백 앞까지 읽음 ‘ aaa’
앞의 공백은 자동 제거되어 aaa 만 남음
nextBoolean() 앞의 줄바꿈 코드 제거하고 뒤의 입력값만 읽는다 true