Development (국비 복습 )/자바

[2023-03-13]메모리 구조(heap,stack영역), 기본타입

Puddingforever 2023. 3. 13. 10:44

변수 : 하나의 값을 저장할 수 있는 메모리 공간 

 

 

[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로 비교가 안된다!!! 

 

 


이클립스 구조 

 

 

이클립스에서 하위패키지 추가할 때 패키지 누른 후, 하위패키지 이름을 추가한다.

 

패키지 구조를 볼 때 계층 구조로 보고 싶을 때 

package presentation -> heirarchical

 

 

 


로컬변수 범위

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이다. 

 

변수 이름 

특수기호랑 자바 타입을 쓸 수 없다

주의 ::: 특수 기호 중에  _랑 $는 쓸 수 있다.