자바에서 참조형을 이해하는것은 중요하다.
변수의 데이터 타입을 가장 크게보면, 기본형과 참조형 두가지로 구분할 수 있다.
핵심은 기본형에는 값이 들어있지만 참조형에는 주소가 들어가 있다는 것이다.
기본형을 제외한 나머지 모두는 참조형이다.
기본형은 소문자로 시작한다. int,long,double,boolean 모두 소문자로 시작한다.
클래스는 대문자로 시작한다 클래스는 모두 참조형이다.
참고-String
String은 값을 대입할수 있지만 일단 참조형이다. 문자는 매우 자주 다루기 때문에 JAVA에서 특별하게 편의 기능을 제공하는것이다. 그래서 String a = "동현"을 하면 동현이라는 문자열은 메모리에 만들어지고 이 메모리의 주소를 변수 a에다가 저장하는것이다.
제일 중요!!!
자바는 항상 변수의 값을 복사해서 대입한다.
int a=10;
int b=a;
이면 a라는 변수의 값인 10을 복사해서 대입한다.
마찬가지로
Student student1 = new Student();
Student student2 = student1
이면 student1의 값은 0x01이라는 참조값이므로 student2에는
student1이라는 인스턴스가 복사되는것이아닌 참조값이 복사되어 student2에는 0x01이라는 참조값이 들어가게된다.
예시
참조형과 메서드 호출
public class MethodChange1 {
public static void main(String[] args) {
int a = 10;
System.out.println("메서드 호출전: "+ a);
changePrimitive(a);
System.out.println("메서드 호출후: "+ a);
}
private static void changePrimitive(int a) {
a = 20;
}
}
이 코드의 결과는 a는 동일하게 10이 나온다. 왜냐하면 자바에서 대원칙은 대입은 값을 복사하는거니까, changePrimitive의 파라미터인 a에는 값인 10이 복사가된다. a를 20으로 바꾼다 한들 main에있는 a가 바뀌지 않는다.
public class MethodChange2 {
public static void main(String[] args) {
Data dataA = new Data();
dataA.value = 10;
System.out.println("메서드 호출 전: dataA.value = " + dataA.value);
changeReference(dataA);
System.out.println("메서드 호출 후: dataA.value = " + dataA.value);
}
static void changeReference(Data dataX) {
dataX.value = 20;
}
}
여기서는 그림이
이런식이다.
그러므로, dataA에는 x001이라는 참조값이 있으므로 changeReference메서드의 dataX에는 참조값이 x001이 복사되므로 이걸 20으로 바꾸면 dataA의 값이 바뀐다.
참조형과 메서드 호출 - 활용
public class Method1 {
public static void main(String[] args) {
Student student1 = createStudent("학생1",15,90);
Student student2 = createStudent("학생2",70,100);
printStudent(student1);
printStudent(student2);
}
static Student createStudent(String i2, int i, int i1){
Student student1 = new Student();
student1.name=i2;
student1.age = i;
student1.grade=i1;
return student1;
}
public static void printStudent(Student student){
System.out.println("이름:" + student.name + "나이: " + student.age + "성적: " + student.grade);
}
}
createStudent메서드에서는 메서드 내부에서 Student객체를 생성하여 반환한다. 그렇게 하더라도 student1에는 이 인스턴스의 참조값이 들어있으므로 main에있는 student1에서 참조값으로 인스턴스 접근이 가능하다.
printStudent메서드에서는 참조값을 파라미터로 받으므로 sout을 통해 인스턴스의 필드에 접근이 가능하다.
변수의 초기화
변수의 종류
멤버변수: 자동 초기화
인스턴스의 멤버 변수는 인스턴스를 생성할 때 자동으로 초기화
숫자는 0 boolean은 false 참조형은 null -> 개발자가 초기값 지정 가능
지역변수: 수동 초기화
지역변수는 항상 직접 초기화 해야한다.
public class InitData {
int value1;
int value2 = 10;
}
public class InitMain {
public static void main(String[] args) {
InitData data = new InitData();
System.out.println("value1 = " + data.value1);
System.out.println("value2 = " + data.value2);
}
}
value1은 초기화를 하지 않아도 자동적으로 초기화 되서 0이고 value2는 10
Null
참조형 변수에서 아직 가르키는 대상이 없다면 null을 넣어 둘 수 있다. 그리고 나중에 참조값을 할당 할수 도 있다.
public class Data {
int value;
}
public class NullMain1 {
public static void main(String[] args) {
Data data = null;
System.out.println(data);
data = new Data();
System.out.println(data);
data = null;
System.out.println(data);
}
}
첫번째 처럼 null을 대입할수 있다. 그러면 data에는 참조값이 들어가는게 아니라 null이 들어가게 된다. 그다음에 new Data()로 객체를 만들고 대입한다.
그다음에 다시 null을 대입 할수 도 있다.
만약에 이렇게 null을 할당하면 앞서 생성한 x001 Data 인스턴스는 더는 아무도 참조하지 않는다.
이렇게 아무도 x001을 참조하지 않으면, x001이라는 참조값을 다시 알수 있는 방법이 없다. 그러므로 이 해당 인스턴스에 접근할 수 있는 방법이 없다.
따라서 JVM의 GC(가비지 컬렉션)가 더이상 사용하지 않는 인스턴스라 판단하고 해당 인스턴스를 자동으로 메모리에서 제거해준다.
이것은, 지역변수도 마찬가지이다.
public void hello(string s){
sout(s);
}
만약 이 hello메서드에서 s는 지역변수이다. hello메서드를 나가게 되면, 이 s라는 인스턴스의 참조값을 아무도 쓰지 않으므로 GC가 이것도 메모리에서 제거해준다.
NullPointerException
null을 가르킨다는 뜻, 즉 객체를 참조할때는 .을 사용한다. 이렇게하면 참조값을 바탕으로 인스턴스를 찾아갈 수 있는데, 참조값 자체가 NULL인 상태에서 .을 찍었다는것을 말한다.
public class BigData {
Data data;
int value;
}
public class NullMain3 {
public static void main(String[] args) {
BigData bigData = new BigData();
System.out.println("BigData.count=" + bigData.value);
System.out.println("BigData.data=" + bigData.data);
System.out.println("BigData.data.value = " + bigData.data.value);
}
}
마지막 sout에서 nullpointerException이 발생한다 그 이유는 자동 초기화에서는 기본형은 0 그리고 인스턴스의 참조값은 null로 초기화가 되는데, DigDta.data에는 null이 들어가 있고 거기다가 null.value이므로 NullPointerException이 발생한다.
해결방안,
그냥 bigData.data = new Data();로
참조값을 할당해주면된다.