Java

[인프런] 기본형과 참조형

sejin2 2024. 5. 20. 18:20

변수의 데이터 타입을 가장 크게 보면 기본형과 참조형으로 분류할 수 있다.
사용하는 값을 변수에 직접 넣을 수 있는 기본형과 객체가 저장된 메모리의 위치를 가르키는 참조값을 넣을 수 있는 참조형으로 분류할 수 있다.

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

- 숫자 10, 20과 같이 실제 사용하는 값을 변수에 담을 수 있고, 해당 값을 바로 사용할 수 있다.
- 참조형은 실제 사용하는 값을 변수에 담는 것이 아니라 이름 그대로 실제 객체의 위치를 저장한다. 참조형에는 객체와 배열이 있다. 객체는 .을 통해서 메모리 상에 생성된 객체를 찾아가야 사용할 수 있고, 배열은 [ ] 를 통해서 메모리 상에 생성된 배열을 찾아가야 사용할 수 있다.

- 기본형은 연산이 가능하지만 참조형은 연산이 불가능하다. => 참조형은 변수에 객체의 위치인 참조값이 들어있기 때문에 오류가 발생한다.
.을 통해 객체의 기본형 멤버 변수에 접근한 경우에는 연산이 가능하다.

- 기본형을 제외한 나머지는 모두 참조형이다. 기본형은 소문자로 시작한다. 기본형은 자바가 기본으로 제공하는 데이터 타입이다. 이러한 기본형은 개발자가 새로 정의할 수 없고, 참조형인 클래스만 직접 정의할 수 있다. 
- 클래스는 대문자로 시작하고, 클래스는 모두 참조형이다. 

String

자바에서 String은 클래스이다. 즉 참조형이다. 그런데 기본형처럼 문자 값을 바로 대입할 수 있다. 
문자는 매우 자주 다루기 때문에 자바에서 특별하게 편의 기능을 제공하는 것이다. 

 

대원칙 : 자바는 항상 변수의 값을 복사해서 대입한다. 



기본형과 참조형의 변수 대입

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

기본형은 변수에 값을 대입하더라도 실제 사용하는 값이 변수에 바로 들어있기 때문에 해당 값만 복사해서 대입한다고 생각하면된다. 참조형의 경우 실제 사용하는 객체가 아니라 객체의 위치를 가르키는 참조값만 복사된다. 

package ref;

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.value = 30;
        System.out.println("변경 dataB.value = 30");
        System.out.println("dataA.value = " + dataA.value);
        System.out.println("dataB.value = " + dataB.value);
    }
}

 

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

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

메서드 호출도 마찬가지로 메서드를 호출할 때 사용하는 매개변수(파라미터)도 결국 변수일 뿐이다. 따라서 메서드를 호출할 때 매개변수에 값을 전달하는 것도 값을 복사해서 전달하는 것이다. 

기본형과 메서드 호출

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;
    }
}

참조형과 메서드 호출

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;
    }
}

같은 인스턴스를 참조하고 있기 때문에 값이 바뀐다. 

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

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

 

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

public class Method1 {
    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 = "학생1";
        student2.age = 16;
        student2.grade = 80;

        printStudent(student1);
        printStudent(student2);

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

    }
}

package ref;

public class Method1 {
    public static void main(String[] args) {
        Student student1 = new Student();  // x001
        initStudent(student1, "학생1", 15, 90);

        Student student2 = new Student(); // x002
        initStudent(student2, "학생2", 16, 80);

        printStudent(student1);
        printStudent(student2);

    }
    static void initStudent(Student student, String name, int age, int grade) { //student = x001 -> x002
        student.name = name;
        student.age = age;
        student.grade = grade;
    }

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

    }
}

참조형은 메서드를 호출할 때 참조값을 전달한다. 따라서 메서드 내부에서 전달된 참조값을 통해 객체의 값을 변경하거나, 값을 읽어서 사용할 수 있다.

  • - initStudent : 전달한 학생 객체의 필드에 값을 설정한다.

    • student1이 참조하는 Student 인스턴스에 값을 편리하게 할당하고 싶어서 initStudnet( ) 메서드를 만들었다.
      이 메서드를 호출하면서 student1을 전달한다. 그러면 student1의 참조 값이 매개변수 student에 전달된다. 이 참조값을 통해 initStudnet( ) 메서드 안에서 student1이 참조하는 것과 동일한 x001 Student 인스턴스에 접근하고 값을 변경할 수 있다. 
  • - printStudent : 전달한 학생 객체의 필드 값을 읽어서 출력한다. 

 

public class Method2 {
    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);
    }
}

createStudent( ) 라는 메서드를 만들고 객체를 생성하는 부분도 이 메서드 안에 함께 포함되다. 이제 이 메서드 하나로 객체의 생성과 초기 값 설정을 모두 처리한다. 그런데 메서드 안에서 객체를 생성했기 때문에 만들어진 객체를 메서드 밖에서 사용할 수 있도록 돌려주어야 한다.( return ) 그래야 메서드 밖에서 이 객체를 사용할 수 있다.

메서드 내부에서 인스턴스를 생성한 후에 참조값을 메서드 외부로 반환하였다. 이 참조값만 있으면 해당 인스턴스에 접근할 수 있다. createStudent( )는 생성한 Student 인스턴스의 참조값을 반환한다. 이렇게 참조된 값을 student1 변수에 저장하여 student1을 통해 Student 인스턴스를 사용할 수 있다. 

 

 

공부 내용: [인프런] 김영한의 실전 자바 - 기본편