[Java] 참조 타입과 참조 변수

rara_kim·2022년 11월 11일
0

Java

목록 보기
28/39

참조 타입(Reference type)

자바의 타입은 크게 기본 타입, 참조 타입으로 분류된다.
여기서 참조 타입이란 객체(object)의 번지를 참조하는 타입으로 배열, 열거, 클래스, 인터페이스를 말한다.

기본 타입과 참조 타입

기본 타입으로 선언된 변수와 참조 타입으로 선언된 변수의 차이점은 저장되는 값이다.
기본 타입은 byte, char, short, int, long, float, double, boolean 변수는 실제 값을 변수 안에 저장하지만, 참조 타입인 배열, 열거, 클래스, 인터페이스 변수는 메모리의 번지를 변수 안에 저장한다.
번지를 통해 객체를 참조한다는 뜻에서 참조 타입이라고 부른다.

//기본 타입 변수
int age = 25;
double price = 100.5;


//참조 타입 변수
String name = "홍길동";
String hobby = "코딩";

int타입 변수인 age와 double타입 변수인 price는 직접 값을 저장하고 있지만, String클래스 변수인 namehobby는 힙 영역의 String 객체의 번지 값을 가지고 있다.
이처럼 번지를 통해 객체를 참조하기 때문에 String클래스 변수를 참조 타입 변수라고 한다.

메모리 사용 영역

JVM은 운영체제에서 할당받은 메모리 영역(Runtime Data Area)을 세부 영역으로 구분해서 사용한다.

1️⃣메소드 영역(Method Area = Class Area)

  • JVM이 동작해서 클래스가 로딩될 때 생성되며 모든 Thread가 공유하는 영역이다.
  • 클래스 정보, static 변수, 변수 정보, 메소드 정보 등을 저장한다.
  • 패키지나 클래스 정보가 올라간다.
  • static이 선언된 클래스 멤버도 올라간다.
  • static(전역)변수는 어디든 접근이 가능해지므로 읽기 전용이 아닌 경우는 가능한 사용하지 않는다.
  • JVM이 동작해서 클래스가 로딩될 때 생성되고, JVM이 종료될때까지 유지된다.

2️⃣힙 영역(Heap Area)

  • 힙 영역은 인스턴스를 생성할 때 생성되는 메모리 형식이다.
  • new를 사용하여 객체를 만들 때 저장된다.
  • 참조형(class, interface, enum, Array 등) 자료형도 같이 저장된다.
  • 여기에 생성된 객체와 배열 등은 JVM 스택영역의 변수나 다른 객체의 필드에서 참조할 수 있다.
  • 힙의 참조 주소는 "스택"이 갖고 있고 해당 객체를 통해서만 힙 영역에 있는 인스턴스를 핸들링할 수 있다.
  • 만약, 참조하는 변수나 필드가 없다면 의미없는 객체가 되기 때문에 GC가 자동으로 제거한다.

3️⃣스택 영역(Stack Area)

  • 지역변수, 파라미터, 리턴값, 연산에 사용되는 임시값 등이 생성되는 영역이다.
  • JVM 스택은 메소드를 호출할 때마다 프레임을 추가하고 메소드가 종료되면 해당 프레임을 제거하는 동작을 수행한다.
  • 프레임 내부에는 로컬 변수 스택이 있는데, 기본 타입 변수와 참조 타입 변수가 추가되거나 제거된다.
  • 기본 타입 변수는 스택 영역에 직접 값을 가지고 있지만, 참조 타입 변수는 스택 영역에 힙 영역의 객체 주소를 갖는다.
  • 변수가 초기화되면 스택 영역에 변수가 생성된다.

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

기본 타입 변수의 ==,!= 연산은 변수의 값이 같은지, 아닌지를 조사하지만 참조 타입 변수들 간의 ==,!= 연산은 동일한 객체를 참조하는지, 다른 객체를 참조하는지 알아볼 때 사용된다.
참조 타입 변수의 값은 힙 영역의 객체 주소이므로 ==,!= 연산은 번지 값을 비교하는 것이 된다.

refVar1 = 객체1;
refVar2 = 객체2;
refVar3 = 객체2;

refVar1 == refVar2    //false
refVar1 != refVar2    //true
refVar2 == refVar3    //true
refVar2 != refVar3    //false

null과 NullPointerException

참조 타입 변수는 힙 영역의 객체를 참조하지 않는다는 뜻으로 null(널) 값을 가질 수 있다.
null값도 초기값으로 사용할 수 있기 때문에 null로 초기화된 참조 변수는 스택 영역에 생성된다.

참조 타입 변수가 null값을 가지는지 ==,!= 연산으로 확인할 수 있다.

refVar1 = 객체1;
refVar2 = null;

refVar1 == null    //false
refVar1 != null    //true
refVar2 == null    //true
refVar2 != null    //false

자바는 프로그램 실행 도중에 발생하는 오류를 예외(Exception)라고 부른다.
예외는 사용자의 잘못된 입력으로 발생할 수도 있고, 개발자가 코드를 잘못 작성해서 발생할 수도 있다.

참조 변수가 null을 가지고 있을 경우에는 참조 객체가 없으므로 변수를 통해 객체를 사용할 수 없다.
만약, null 상태에서 있지도 않은 객체의 데이터(필드)나 메소드를 사용하는 코드를 실행하면 NullPointerException이 발생한다.

int[] myArray = null;
myArray[0] == 10;     //NullPointerException

위 코드에서 myArray는 배열 변수이므로 참조 변수로, null로 초기화가 가능하다.
이 상태에서 myArray[0]에 10을 저장하려고 하면 변수가 참조하는 배열 객체가 없기 때문에 NullPointerException이 발생한다.

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

String도 클래스이므로 참조 타입이다. 따라서 위의 str변수도 NullPointerException이 발생한다.

String 타입

  • 문자열은 String 객체로 생성되고 변수는 String 객체를 참조한다.
  • 자바는 문자열 리터럴이 동일하다면 String 객체를 공유하도록 되어 있다.

일반적으로 변수에 문자열을 저장할 경우에는 문자열 리터럴을 사용하지만, new 연산자를 사용해서 직접 String 객체를 생성시킬 수도 있다.
new 연산자는 힙 영역에 새로운 객체를 만들 때 사용하는 연산자로 객체 생성 연산자라고 한다.

String name1 = "홍길동";
String name2 = "홍길동";
String name3 = new String("홍길동");

name1 == name2    //true
name2 == name3    //false
name1 != name3    //true

==연산자는 변수에 저장된 객체의 번지가 동일한지를 검사하기 때문에, new 연산자로 String 객체를 생성했을 경우 연산의 결과는 false가 나온다.
name1과 name2는 동일한 문자열 리터럴로 생성된 객체를 참조하기 때문에 연산의 결과는 true가 된다.

동일한 String 객체이건 다른 String 객체이건 상관없이 내부 문자열을 비교하고 싶을 때에는 String 객체의 equals()메소드를 사용할 수 있다.
equals() 메소드는 원본 문자열과 매개값으로 주어진 비교 문자열이 동일한지 비교한 후 true 또는 false를 리턴한다.

String name1 = "홍길동";
String name2 = new String("홍길동");

booelan result = name1.equals(name2);    //true
profile
느리더라도 꾸준하게

0개의 댓글