[java] 참조타입과 참조변수
자바타입은 그게 기본타입과 참조타입으로 구분이된다. 기본타입은 정수, 실수, 문자, 논리리터럴을 저장하는 타입을 말한다. 참조타입은 객체의 번지를 참조하는 타입으로 배열, 열거, 클래스, 인테페이스를 말한다.
1. 기본 타입과 참조타입의 차이점
기본타입과 참조타입의 차이점은 저장되는 값에서 차이가 난다.
기본타입은 실제 값을 변수 안에 저장하지만 참조타입은 메모리의 번지를 변수 안에 저장한다. 번지를 통해 객체를 참조한다는 뜻이다.
2. 메모리 사용 영역
JVM은 운영체제에서 할당받은 메모리 영역을 다음과 같이 세부 영역으로 구분 한 것이다.
2-1. 메소드영역
JVM이 시작할때 생성이 되고 모든 스레드가 공유하는 영역. 메소드 영역에는 코드에서 사용되는 클래스들을 클래스 로더로 읽어 클래스별로 정적필드와 상수, 메소드 코드, 생성자 코드등을 분류해서 저장
2-2. 힙영역
객체와 배열이 생성되는 영역. 여기에 생성된 객체와 배열은 JVM 스택영역의 변수나 다른 객체의 필드에서 참조. 만일 참조하는 변수나 필드가 없다면 의미 없는 객체가 되기 때문에 JVM이 이것을 쓰레기 수집기를 실행시켜 자동으로 제거.
2-3. JVM영역
메소드를 호출할 때마다 프레임을 추가하고 메소드가 종료되면 해당 프레임을 제거 하는 동작을 수행.
프레임 내부에는 로컬변수, 스택이 있는데, 기본타입변수와 참조 타입 변수가 추가 되거나 제거가 된다. 스택 영역에 변수가 생성되는 시점은 초기화 될 때, 즉 최초로 변수가 값이 저장될 때이다. 변수는 선언된 블록 안에서만 스택에 존재하고 블록을 벗어나면 스택에서 제거가 된다.
예시)
char v1 = "A"; //1
if(v1=="A"){
int v2 = 100; //2
double v3 = 2.14;
}
boolean v4 = true; //3
선언된 변수는 실행 순서에 따라서 스택이 생성이 되고 제거가 된다 . v2,v3은 if 블록 내부가 실행되고 있을때만 스택영역에 존재하고 if가 나왔을때 스택이 소멸된다.
기본 타입 변수는 스택 영역에 직접 값을 가지고 있지만 , 참조타입 변수는 스택 영역에 힙 영역의 객체 주소를 가진다.
예시 2)
int [] scores = {10,20,30};
스택영역 (5번지) == 힙 영역
scores = 5번지 >>> 10 ,20 30
다음과 같이 배열 변수인 scores는 스택 영역에 생성되지만 실제 10,20,30을 갖는 배열은 힙 영역에 생성이된다.
3. 참조 변수의 == , != 연산
기본 타입 변수의 ==, != 연산은 변수의 값이 같은지 아닌지를 조사하지만 참조타입 간의 ==, != 은 동일한 객체를 참조하는지 다른 객체를 참조하는지 알아볼 때 사용이 된다. 참조 타입변수의 값은 주소 값이므로 결국 번지 값을 비교하는것이다.
동일한 번지 값을 갖고 있다는 것은 동일한 객체를 참조한다는 의미이다. 따라서 동일한 객체를 참조하고 있는 경우 ==는 true이고 != false이다.
4. null과 nullpointerException
참조 타입 변수는 힙 영역의 객체를 참조하지 않는다는 뜻으로 null 값을 가질 수 있습니다. null 값도 초기값으로 사용할 수 있기 때문에 null로 초기화된 참조 변수는 스택 영역에 생성된다.
자바는 프로그램 실행 도중 발생하는 오류를 예외(exception)이라고 부른다. 참조 변수를 사용하면서 많이 예외중 발생하는 것 중에 하나가 nullpoiner이다. 이 예외는 참조 타입변수를 잘못 사용하면 발생한다.
참조 변수가 null을 가지고 있을 경우 참조 객체가 없으므로 변수를 통해 객체를 사용할 수가 없다. 만약 null 상태에서 있지도 않은 객체의 데이터나 메소드를 사용하는 코드를 실행하면 예외가 발생한다.
예시)
int[] inarray = null;
intArray[0] = 10 ; >> nullpointerExecption
4. String 타입
자바는 문자열을 string변수에 저장하기 때문에 다음과 같이 string 변수를 우선 선언한다.
String name;
name = "한정훈";
String hobby = "사진";
문자열이 직접 변수에 저장되는 것이 아니라 문자열은 string 객체로 생성이 되고 변수는 string객체를 참조하기 때문입니다. 위에 있는 코드를 보면 name과 hobby 변수는 스택 영역에 생성되고, 문자열 리터릴인 "신용권"과 "자바"눈 합 영역에 String객체로 생성이된다. 그리고 name 변수와 hobby 변수에는 string객체의 번지 값이 저장이된다.
예시1)
String name1 = "한정훈";
String name2 = "한정훈";
위에 있는 예시는 문자열 리터럴이 동일하기 때문에 번지 값 공유를 하고 있다.
String name1 = new String("한정훈");
String name2 = new String("한정훈");
이 경우에는 같은 한정훈이 서로 다른 주소값이기 때문에 만약에 동일한지 조건문을 적으면 값은 false로 나올 것이다.
그래서 두 변수가 동일한지 확인시켜주는 메소드가 equals()이다. 이 메소드는 원본 문자열과 매개값으로 주어진 비교 문자열이 동일한지 비교한 후 true나 fasle를 반환한다.
str1.equals(str2);
// str1가 원본 문자열
// str2가 비교 문자열
public static void main(String[] args) {
String strvar1 = "한정훈";
String strvar2= "한정훈";
if(strvar1==strvar2) {
System.out.println("참조값이 같아요 !");
} else {
System.out.println("참조값이 달라요!");
}
if(strvar1.equals(strvar2)) {
System.out.println("strvar1와 strvar2는 문자열이 같다");
}
String strvar3 = new String("한정훈개발자");
String strvar4 = new String("한정훈개발자");
if(strvar3 ==strvar4) {
System.out.println("참조값이 같아요 !");
}else {
System.out.println("참조값이 달라요!!");
}
if(strvar3.equals(strvar4)) {
System.out.println("strvar3과 strvar4는 문자열이 다르다");
}
public static void main(String[] args) {
String var1 = "AB";
String var2 = new String("AB");
String var3 = "AB";
String var4 = new String("AB");
String var5 = "BB";
System.out.println(var1.equals(var2));
System.out.println(var1.equals(var3));
System.out.println(var1.equals(var4));
System.out.println(var2.equals(var4));
System.out.println(var1.equals(var5));
System.out.println(var2.equals(var5));
System.out.println(var4.equals(var5));