Java

Chapter 05-1 참조 타입과 참조 변수

yeooniyeoon 2022. 11. 10. 01:27
728x90
SMALL

자바의 데이터 타입

자바의 데이터 타입은 기본 타입과 참조 타입으로 나뉜다.

기본 타입은 정수, 실수, 논리 타입을 말하고

참조 타입은 객체의 번지를 참조하는 타입으로 배열, 열거, 클래스, 인터페이스를 말한다.

 

문자열을 저장하는 String도 참조 타입이다.

자바에서는 문자열을 값이 아닌 객체로 취급하기 때문에

참조 타입 변수에 문자열을 저장 시 힙 영역에 String 객체 생성 후 그 안에 문자열을 저장한다.

그리고 변수에는 String 객체의 번지가 저장되고 변수는 해당 번지를 참조하여 문자열에 접근할 수 있다.

 

기본 타입 변수변수에 값이 그대로 저장되고

참조 타입 변수힙 영역에 생성된 객체의 번지를 갖고 있다

이게 둘의 차이~

 

 

메모리 사용 영역

JVM은 운영체제에서 할당받은 메모리 영역을 크게 메소드 영역, 힙 영역, JVM 스택 영역 3가지로 구분하여 사용한다.

 

메소드 영역은 JVM 시작 시 생성 되고 모든 스레드가 공유하는 영역으로 바이트 코드 파일 실행 시 메소드 영역에 바이트 코드가 로딩된다. 그리고 그 코드를 읽어 힙 영역에 객체를 생성하거나 스택 영역에 변수를 생성하게 된다.

 

힙 영역은 클래스로부터 생성된 객체들이 저장되는 영역이다.

 

JVM 스택 영역은 FILO 구조로 되어 있으며 메소드가 호출될 때마다 프레임이 추가되고 메소드 종료 시 프레임을 제거하는 동작을 수행한다.

프레임이란 메소드 호출 시 사용된 변수들이 저장되는 곳으로 메소드가 실행 중일때만 프레임이 존재하며, 메소드 종료 시 프레임도 제거된다.

 

 

 

참조 변수의 ==, != 연산

참조 타입 변수에 비교 연산자 사용 시 참조 타입 변수가 가리키는 번지를 비교하게 된다.

두 피연산자가 동일한 객체를 참조하는지, 다른 객체를 참조하는지 확인하는 용도로 사용한다.

 

String refArr1 = "hi";
String refArr2 = "hello";

refArr1 == refArr2;		// false
refArr1 != refArr2;		// true

 

위 코드에서 refArr1과 refArr2는 서로 다른 객체를 가리키고 있으므로 4행의 결과는 false, 5행의 결과는 true이다.

이처럼 동일 객체 참조 여부 확인 시 비교 연산자를 사용할 수 있다.

 

 

null과 NullPointerException

참조 타입 변수는 항상 값을 가져야 하는 것은 아니기 때문에

힙 영역의 객체를 참조하지 않는다는 의미로 null 값을 가질 수 있다.

따라서 참조 타입 변수의 값이 null이라면 현재 가리키고 있는 객체가 없음을 뜻한다.

참조 타입 변수가 null 값을 갖는지 확인하려면 위에서 나온 ==, != 비교 연산자를 사용하면 된다.

 

refVar = null;

refVar == null;		// refVar가 가리키고 있는 객체를 없는가?
refVar != null;		// refVar가 가리키고 있는 객체가 있는가?

 

3행은 refVar이 현재 참조하는 객체가 없는가를 의미하고

4행은 refVar이 현재 참조하는 객체가 있는가를 확인하는 것이다.

 

자바는 error와 exception이라는 단어를 구분해서 사용하는데

error는 하드웨어, OS 관련 문제 발생 시 사용하고

exception은 프로그램 실행 도중 문제 발생 시 사용한다.

 

참조 변수를 사용하며 가장 많이 발생하는 오류 중 하나로 NullPointerException이 있다.

이는 참조 타입 변수가 null인 상태에서 존재하지 않는 객체의 데이터나 메소드를 사용할 경우 발생하는 예외이다.

 

int[] arr = null;
arr[0] = 10;

String str = null;
System.out.println(str.length());

 

위 코드처럼 null을 가리키는 배열에 값을 저장하거나

null을 가리키는 String 변수에 length 메소드를 사용할 경우 NullPointerException 예외가 발생한다.

 

이는 해당 참조 변수가 객체를 참조하도록 수정하여 문제를 해결할 수 있다! ! !

 

 

String 타입

String 변수에 문자열 리터럴을 대입하면 String 객체를 생성한 뒤 변수가 String 객체를 참조하게 된다.

 

문자열 리터럴이 동일한 경우에는 같은 Strnig 객체를 공유하게 된다.

 

String var1 = "hello";
String var2 = "hello";

var1 == var2;	// 결과 : true. var1과 var2는 동일한 객체를 참조하고 있음

 

위 코드는 var1과 var2에 동일한 문자열을 값으로 저장했는데, 이럴 경우 힙 영역에 hello라는 값을 가진 객체는 하나만 생성되고 두 변수는 동일한 객체를 참조하게 된다.

 

 

new 연산자

new는 객체를 생성하는 연산자이다.

문자열 변수에 값 할당 시 new 연산자를 사용하면 동일한 문자열 리터럴을 저장해도 각각 다른 객체가 생성된다.

 

Stirng var1 = new String("hello");
String var2 = new String("hello");

var1 == var2;	// 결과 : false. var1과 var2는 각각 다른 객체를 참조함.

 

위와 같은 경우 new 연산자를 사용하여 힙 영역에 hello라는 값을 가진 객체가 2개 생성된다.

두 객체가 가진 값은 같지만 서로 다른 객체이기 때문에 다른 번지값을 갖는다.

그렇기 때문에 var1과 var2 비교 연산 실행 시 결과는 false가 나온다.

 

 

문자열 비교

자바에서는 문자열을 비교할 때 == 연산자는 잘 사용하지 않는다. == 비교 연산자는 참조하는 객체의 번지를 비교하는 것이기 때문에 문자열 비교 시에는 equals() 메소드를 사용한다.

equals() 메소드는 참조하는 객체의 번지가 아닌 그 안에 저장된 문자열을 비교하기 때문에 문자열 비교 시에는 이 메소드를 사용하는 것이 더 적합하다.

 

String var1 = "hello";
String var2 = "hello";

var1 == var2;				// 결과 : true
boolean result = var1.equals(var2);	// 결과 : true

String var3 = new String("hi");
String var4 = new String("hi");

var3 == var4;				// 결과 : false
result = var3.equals(var4);		// 결과 : true

 

위 코드에서 var1과 var2는 동일 객체를 참조하기 때문에 == 연산자와 equals 메소드를 사용한 비교 결과가 모두 true이다.

반면 var3과 var4는 값은 같지만 서로 다른 객체를 참조하기 때문에

== 연산자를 사용한 비교 연산 결과는 false이지만 문자열만을 비교하는 equals() 메소드를 사용한 결과는 true이다.

 

String 변수에 객체의 번지를 할당한 뒤 null 값을 대입하면 변수가 원래 참조하던 객체는 참조를 잃게 된다.

이런 객체를 쓰레기 객체라고 하는데, 자바에서는 쓰레기 객체를 쓰레기 수집기를 통하여 메모리에서 자동으로 제거한다.

이렇게 자바에서는 가비지 콜렉터라 알아서 메모리를 관리해주기 때문에 따로 메모리를 소멸시키는 코드가 없다 ! !

728x90
반응형
SMALL

'Java' 카테고리의 다른 글

&&와 &, ||와 |의 차이  (0) 2023.11.01
Chapter 05-3 열거 타입  (0) 2022.11.16
Chapter 05-2 배열  (0) 2022.11.14
Chapter 01 자바 시작하기  (0) 2022.11.02
환경변수를 설정하는 이유  (0) 2022.08.18