기본형과 참조형

고동현·2024년 5월 13일
0

JAVA

목록 보기
3/22

자바에서 참조형을 이해하는것은 중요하다.
변수의 데이터 타입을 가장 크게보면, 기본형과 참조형 두가지로 구분할 수 있다.

  • 기본형: int,long,double,boolean처럼 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입
  • 참조형: Student student1,int[] students와 같이 데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입. 객체 또는 배열에 사용

핵심은 기본형에는 값이 들어있지만 참조형에는 주소가 들어가 있다는 것이다.

기본형을 제외한 나머지 모두는 참조형이다.
기본형은 소문자로 시작한다. 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();로
참조값을 할당해주면된다.

profile
항상 Why?[왜썻는지] What?[이를 통해 무엇을 얻었는지 생각하겠습니다.]

0개의 댓글