강의내용정리/Java

[Java] 기본형과 참조형

송병민 2025. 1. 13. 19:04

기본형과 참조형

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

기본형

  • 기본형을 제외한 나머지는 모두 참조형
  • 소문자로 시작
  • 자바가 기본으로 제공하는 데이터 타입으로 개발자가 새로 정의할 수 없다
  • 숫자와 같이 실제 사용하는 값을 변수에 담을 수 있다. 그래서 해당 값을 바로 사용할 수 있다. 

참조형

  • 클래스는 대문자로 시작 (클래스는 모두 참조형)
  • 참조형은 실제 사용하는 값을 변수에 담는 것이 아니기 때문에 메모리 상에 생성된 실제 객체에 접근해서 사용해야 한다

※ String

String은 클래스, 참조형이다. 그러나 기본형처럼 문자 값을 바로 대입할 수 있다

 

변수대입

자바는 항상 변수의 값을 복사해서 대입한다. 기본형이면 변수에 들어있는 실제 사용하는 값을 복사해서 대입하고, 참조형이면 변수에 들어있는 참조값을 복사해서 대입한다.

 

기본형 변수 대입

public class VarChange1 {
    public static void main(String[] args) {
        int a = 10;
        int b = a;
        System.out.println("a = " + a);
        System.out.println("b = " + b);

        //a 변경
        a = 20;
        System.out.println("변경 a = 20");
        System.out.println("a = " + a);
        System.out.println("b = " + b);

        //b 변경
        b = 30;
        System.out.println("변경 b = 30");
        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}


참조형 변수 대입

public class Data{
	int value;
}

public class VarChange2 {
    public static void main(String[] args) {
        Data dataA = new Data();
        dataA.value = 10;
        Data dataB = dataA;

        System.out.println("dataA = " + dataA);
        System.out.println("dataB = " + dataB);
        System.out.println("dataA.value = " + dataA.value);
        System.out.println("dataB.value = " + dataB.value);

        //dataA 변경
        dataA.value = 20;
        System.out.println("변경 dataA.value = 20");
        System.out.println("dataA.value = " + dataA.value);
        System.out.println("dataB.value = " + dataB.value);

        //dataB 변경
        dataB.value = 30;
        System.out.println("변경 dataB.value = 30");
        System.out.println("dataA.value = " + dataA.value);
        System.out.println("dataB.value = " + dataB.value);
    }
}

dataA의 주소값을 dataB에 저장했기 때문에 같은 객체를 참조하고 있다. 따라서 dataA 값을 변경하나, dataB의 값을 변경하나 똑같은 객체의 값이 변경되고 있다.

 

메서드 호출

public class MethodChange1 {
    public static void main(String[] args) {
        int a = 10;
        System.out.println("메서드 호출 전: a = " + a);
        changePrimitive(a);
        System.out.println("메서드 호출 후: a = " + a);
    }

    static void changePrimitive(int x) {
        x = 20;
    }
}

chagePrimitive(a)가 실행되면 a의 값인 10이 매개변수로 전달된다

10 = 20 이 되어서 똑같은 값 10이 출력된다

package ref;

public class MethodChange2 {
    public static void main(String[] args) {
        Data dataA = new Data();
        dataA.value = 10;
        System.out.println("메서드 호출 전: dataA.value = " + dataA.value);
        System.out.println("dataA=" + dataA);
        changeReference(dataA);
        System.out.println("메서드 호출 후: dataA.value = " + dataA.value);
    }

    static void changeReference(Data dataX) {
        System.out.println("dataX=" + dataX);
        dataX.value = 20;
    }
}

chagePrimitive(dataA)가 실행되면 dataA의 참조값(주소)이 매개변수로 전달된다

dataA의 value 값을 20으로 변경해서 10과 20이 출력된다

 

' 변수의 값을 복사해서 대입한다 ' 라는 개념 확실히 !!


기본형과 참조형의 메서드 호출

자바에서 메서드의 파라미터는 항상 값에 의해 전달된다. 이 값이 실제값이냐, 참조값이냐에 따라 동작이 달라진다

  • 기본형 : 메서드로 기본형 데이터를 전달하면 해당 값이 복사되어 전달된다. 메서드 내부에서 파라미터의 값을 변경해도 호출자의 변수 값에는 영향이 없다
  • 참조형 : 메서드로 참조형 데이터를 전달하면 참조값이 복사되어 전달된다. 메서드 내부에서 파라미터로 전달된 객체의 멤버변수를 변경하면 호출자의 객체도 변경된다

 

참조형 메서드 호출 활용

package class1;

public class ClassStart3 {
    public static void main(String[] args) {
        Student student1 = new Student();
        student1.name="학생1";
        student1.age=15;
        student1.grade=90;

        Student student2 = new Student();
        student2.name="학생2";
        student2.age=16;
        student2.grade=80;

        System.out.println(student1);

        System.out.println("이름:" + student1.name + " 나이:" + student1.age + " 성적:" + student1.grade);
        System.out.println("이름:" + student2.name + " 나이:" + student2.age + " 성적:" + student2.grade);
    }
}

 

메서드 호출을 활용해서 이전에 코드를 리팩토링 해보면

 

package ref;

public class Student {
    String name;
    int age;
    int grade;
}

public class Method1 {
    public static void main(String[] args) {
        Student student1 = createStudent("학생1", 15, 90);
        Student student2 = createStudent("학생2", 16, 80);

        printStudent(student1);
        printStudent(student2);
    }
    static Student createStudent(String name, int age, int grade) {
        Student student = new Student();
        student.name = name;
        student.age = age;
        student.grade = grade;
        return student;
    }

    static void printStudent(Student student) {
        System.out.println("이름:" + student.name + " 나이:" + student.age + " 성적:" + student.grade);
    }
}

 

객체 생성할 때 중복되는 코드들을 메서드에서 생성하고 객체를 반환하도록 하고, 출력에서 중복되는 코드들을 메서드에서 객체를 받아 객체별로 출력할 수 있게 리팩토링 했다

 

Null

참조형 변수에는 항상 객체가 있는 위치를 가리키는 참조값이 들어간다. 그런데 아직 가리키는 대상이 없거나, 대상을 나중에 입력하고 싶다면 null 이라는 특별한 값을 넣어둘 수 있다. null 은 값이 존재하지 않는, 없다는 뜻이다

 

public class Data {
    int value;
}

public class NullMain1 {
    public static void main(String[] args) {
        Data data = null;
        System.out.println("1. data = " + data);
        data = new Data();
        System.out.println("2. data = " + data);
        data = null;
        System.out.println("3. data = " + data);
    }
}

  • Data 타입을 받을 수 있는 data에 null값을 할당했다 → 가리키는 객체가 없다
  • data에 생성한 객체의 참조값을 할당했다 → 참조할 객체가 있다
  • 다시 null 값을 할당했다 → data 변수는 Data 인스턴스를 더는 참조하지 않는다

Garbage Collection

 C언어와 같은 과거 프로그래밍 언어는 개발자가 직접 명령어(free()라는 함수)를 사용해서 인스턴스를 메모리에서 제거해야 했다. 만약 실수로 인스턴스 삭제를 누락하면 메모리에 사용하지 않는 객체가 가득해져서 메모리 부족 오류가 발생하게 된다.

 아무도 참조하지 않는 인스턴스가 있으면 JVM의 GC(Garbage Collection)가 더이상 사용하지 않는 인스턴스라 판단하고 해당 인스턴스를 자동으로 메모리에서 제거해준다

 객체는 해당 객체를 참조하는 곳이 있으면, JVM이 종료할 때 까지 계속 생존한다. 그런데 중간에 해당 객체를 참조하는 곳이 모두 사라지면 그때 JVM은 필요 없는 객체로 판단하고 GC를 사용해서 제거한다


NullPointException

 참조값 없이 객체를 찾아가면 NullPointException이라는 예외가 발생한다. 주소가 없는 곳을 찾아갈 때 발생하는 예외이다.

 객체를 참조할 때 .(dot)을 사용하는데 참조값이 null이라면 값이 없다는 뜻이므로 찾아갈 수 있는 객체가 없다. NullPointException은 null에 .을 찍었을 때 발생한다.

바로 프로세스 종료됨

 

다음 코드에서는 어디에 nullPointException이 발생할까

public class BigData {
    Data data;
    int count;
}

public class NullMain3 {
    public static void main(String[] args) {
        BigData bigData = new BigData();
        System.out.println("bigData.count = " + bigData.count);
        System.out.println("bigData.data = " + bigData.data);
        System.out.println("bigData.data.value = " + bigData.data.value);
    }
}
  • bigData.count → int는 초기화 안하면 0, 0 출력
  • bigData.data → 객체는 초기화 안하면 null, null 출력
  • bigData.data.value → data가 지금 null 이기 때문에 null 에 .으로 접근해서 nullPointException이 발생

 

 

'강의내용정리 > Java' 카테고리의 다른 글

[Java] 생성자  (0) 2025.01.20
[Java] 객체 지향 프로그래밍  (0) 2025.01.20
[Java] 클래스와 객체  (0) 2025.01.13