[2023-03-13]메모리 구조(heap,stack영역), 기본타입
변수 : 하나의 값을 저장할 수 있는 메모리 공간
[JVM 메모리 구조]
힙(heap)영역
-객체타입(참조타입): stack영역과 heap영역을 같이 씀
-변수와 메모리 주소를 가짐
스택(stack)영역
-기본타입 (정수,실수,논리) stack영역만 사용
-메모리 주소가 없고 그냥 값만 가져다가 쓰는 것임
-객체타입은 heap 영역을 쓰고 stack 영역도 씀
int a = 1;
int b = 1;
System.out.println(a==b); // true 기본타입이라서 단순히 값을 비교 (stack영역에 들어감)
int[] c = {1};
int[] d = {1};
System.out.println(c==d); // false 객체타입이라서 주소값을 비교 (heap영역에 들어감)
int i=1; //기본타입-stack영역
if(i==1) {
System.err.println("i값은 1입니다.");
int k=2; // 로컬번수 , stack영역. 접시의 맨 밑에 있음 . 밖에서 못씀
int[] num = {1,2,3}; // 객체타입이라 heap영역에 들어가지만 , stack영역에도 있어서 밖에서 못씀
}
int number = num[0];//에러남, stack영역의 순서에 어긋남
if(k==2) { //에러남
System.err.println("k값은 1입니다.");
}
[기본타입]
byte타입 : -128~ 0 ~ 127만 대입이 가능 (1바이트:8비트)
byte myByte = 128; //에러
byte myByte = 127; // int 리터럴의 값인데, byte범위의 타입으로 선언해서 byte 리터럴로 자동변환됩니다.
short타입: -32768~0~32767 정수만 대입가능 (2바이트:16비트)
short myShort=100; // int리터럴인데 short 범위의 값이므로 , short 리터럴로 자동 변환됨
short myShort2 = 21768 // type mismatch , cannot convert from int to short
int타입 : 정수만 대입 가능 , (4바이트:32비트) 21 억까지
int number = 100;
int타입은 double보다 작은데 값이 double이 나오면 에러가 난다. 따라서 int로 casting해준다.
int myIntResult = (int)30/4;
long타입 : int범위 이상의 큰 정수 (8바이트:64비트)
long myLong = 1000000000000;//에러 type int is out of range
Long타입을 쓸때는 반드시 L을 써줘야한다.
왜냐하면 값을 저장하기 전에 위의 내용처럼 먼저 int로 임시메모리에 저장되는데 100000000000은 int의 범위를 넘었기 때문이다.
따라서 long 을 쓸 때는 반드시 리터럴 뒤에 L을 써준다.
long a = 10L;
int b ;
// b = a; // 10L은 long 타입이라서 int로 자동변환이 안됌 (큰거->작은거 타입변환 X)
b = (int)a; // 10 a가 long타입이지만 int의 범위에 있기 때문에 강제변환을 해준다.
char 타입 : 0~65,535 정수만 대입이 가능 2바이트(16비트)사용 가능
char myChar1 = 'A';
System.out.println(myChar1); // A
myChar1 = 65;
System.out.println(myChar1); // A
A로 표시되는 것을 int값으로 바꾸기 위해 cating을 활용한다.
char myChar1 = 'A';
int myChar1int = (int)myChar1;
System.out.println(myChar1int);//65
float:실수타입 및 실수 리터럴 ( 4바이트공간 사용 가수x10^지수처리 )
float으로 타입을 한 경우, 기본 메모리 값으로 double로 저장되기때문에 float타입을 쓸때는 항상 flaot으로 바꿔줘야 한다.
float myFloat = 10.0; // 에러 cannot convert from double to float
myFloat = (float)10.0;
myFloat = 10.0F;
double:실수타입 및 실수 리터럴 ( 8바이트공간 사용 가수x10^지수처리 )
실수로 넣을 경우 메모리에는 기본타입으로 double이 저장된다.
변수의 값의 범위비교
byte<short<int<long
큰 범위-> 작은 범위로는 자동 형변화 불가
int w = 10;
byte h = w; // cant convert int to byte
System.out.println(h);
작은 범위-> 큰 범위로는 자동 형변화 가능
byte w = 10;
int h = w;
System.out.println(h);
만약 , 큰 범위->작은 범위로 자동 형변화를 해주고 싶다면 , casting을 쓴다.
int w = 10;
byte h = (byte)w;
논리형 boolean
boolean isTrue = true;
isTrue = false;
[주의!! ]
String은 기본타입이 아니라 객체타입이다.
하지만 값이 동일하면 같은 heap메모리 주소를 공유한다.
stack영역에 값이 기록되기는 하지만 heap영역에 메모리가 저장되기 때문에 stack영역을 비교하는 ==가 아니라 .equals로 비교해야한다.
String str = new String("홍길동"); //heap 영역에 저장되며, stack영역에 변수 이름과 메모리주소를 저장
String str1 = new String("홍길동");
//stack영역에 있는 메모리를 비교
if(str==str1) {
System.out.println("두 변수의 값은 동일합니다.");
}else {
System.out.println("두 변수의 값은 동일하지 않습니다.");
}
두 변수의 값은 동일하지 않습니다.
출력값이 틀렸다. String은 값이 같으면 똑같은 메모리 주소를 공유하기 때문에 두 변수의 값은 동일합니다가 나와야한다.
String은 많이 쓰여서 , new 객체를 쓰지 않고도 약식으로 String 변수이름으로 쓸 수 있음 .
하지만 , 기본타입과 다르게 객체가 만들어지고 heap 메모리 영역에 저장되서 주소가 생성된다.
만약 값이 똑같다면 , JVM이 메모리 낭비를 줄이기 때문에 다른 주소로 저장되지 않고 같은 주소로 들어감
만약 값이 달라지면 주소가 달라짐
String str = "홍길동";
String str2 = "홍길동";
//stack영역에 있는 메모리주소
if(str==str2) {
System.out.println("두 변수의 값은 동일합니다.");
}else {
System.out.println("두 변수의 값은 동일하지 않습니다.");
}
두 변수의 값은 동일합니다. (객체타입이지만 값이 같기 때문에 서로 같은 메모리 주소를 공유하게 해준다)
실제로 heap영역에 있는 문자열이 동일한지 비교하는 것은 String 클래스에 정의된 equals 메소드를 사용해야함
String str = new String("홍길동");
String str1 = new String("홍길동");
if(str.equals(str1)) {
System.out.println("두 변수의 값은 동일합니다.");
}else {
System.out.println("두 변수의 값은 동일하지 않습니다.");
}
두 변수의 값은 동일합니다.
equals 는 메모리 주소를 비교함
String str1 = new String("홍길동");
if(str.equals("홍길동")) {
System.out.println("두 변수의 값은 동일합니다.");
}else {
System.out.println("두 변수의 값은 동일하지 않습니다.");
}
두 변수의 값은 동일합니다.
String str = new String("홍길동"); //heap 영역에 저장되며, stack영역에 변수 이름과 메모리주소를 저장
String str1 = new String("홍길동");
if(str==str1) {
System.out.println("두 변수의 값은 동일합니다.");
}else {
System.out.println("두 변수의 값은 동일하지 않습니다.");
}
두 변수의 값은 동일하지 않습니다. (사실 안에 주소값 동일한데 false로 나옴
null : 객체 타입에 , 객체가 만들어지지 않았다고 표시
String herName =""; // heap 영역에 길이가 0인 문자열을 가진 String객체를 생성
//stack영역에 변수이름과 메모리 주소를 저장함
String itsName =null; //heap 영역에 객체를 생성하지 않았음 . stack영역에 변수 이름과
// null이라는 문자열을 저장
자바스크립트에서는 undefined가 가능했지만 자바에서는 값이 없다 표시할 때 null 이나 "" 로 표현해야한다 .
문자열 변수에 값이 없을 때 조건으로 표현하면 항상 두가지를 고려해야 함
if(문자열 변수 == null && 문자열변수.equals(""))
null은 객체가 생성안된 경우고 , ""은 길이가 0인 객체가 생성된 경우이기 때문에 둘다 체크해줘야한다.
null로 할 때는 stack영역에 있는 부분만 비교한 것이다.
input에 값을 넣고 submit한 경우도 있고 , input에 값을 안넣고 submit한 경우도 있기 때문이다.
int hisInt == null; //에러 남
기본타입은 null로 비교가 안된다!!!
이클립스 구조
이클립스에서 하위패키지 추가할 때 패키지 누른 후, 하위패키지 이름을 추가한다.
패키지 구조를 볼 때 계층 구조로 보고 싶을 때
로컬변수 범위
int myInt = 0;
if(myInt) {
//에러발생
}
javascript에서는 값이 있으면 true가 되서 쓸 수 있었지만 , java에선 boolean 값을 넣어줘야한다.
if문 안에 선언된 변수는 else문에서 쓸 수 없다.
if(true) {
int variable = 22; //로컬변수
}else {
System.out.println(variable); // 에러
}
printf
printf("형식문",값1,값2) ...
System.out.printf("이름 %s","푸딩"); // 이름 푸딩
System.out.printf("나이 %d",1); // 나이 1
%d : 정수
%6d : 6자리 정수를 쓸건데 남은 빈 앞자리는 공백 ___123
%-6d: 6자리 정수를 쓸건데 남은 빈 뒷자리는 공백 123___
값을 두개 넣을 수도 있다.
System.out.printf("이름은 %s이고 나이는 %d이다","푸딩",20);
이름은 푸딩이고 나이는 20이다.
변수 이름
특수기호랑 자바 타입을 쓸 수 없다
주의 ::: 특수 기호 중에 _랑 $는 쓸 수 있다.