기본형 VS 참조형
- 앞서 입문편에서 가볍개 배웠었다.
- 변수의 데이터 타입을 크게 보면 기본형과 참조형으로 분류할 수 있다.
- 기본형을 제외한 나머지는 모두 참조형이다.
- 기본형
- 사용하는 값을 변수에 직접 넣을 수 있는 것 (리터럴 값을 담는다.)
- 기본형 데이터는 변수를 불러 직접 사용 가능하다.
- 들어있는 값 그대로 사용 가능
- 소문자로 시작 한다 → int, long, double, boolean, char
- 기본형은 자바가 기본으로 제공하는 데이터 타입이다.
- 개발자가 기본형타입으로 새로 정의할 수 없다.
- 참조형
- 객체가 저장된 메모리의 위치(주소)를 저장 하고 있는 것
- 참조형 데이터를 사용하려면 참조 값을 통해 해당 위치로 이동해야 한다.
- 객체는 . (dot) 을 통해 객체를 찾아가야 한다.
- 배열은 [ ] index 를 통해 메모리 상의 배열 위치를 찾아간다.
- 참조 값 그대로 사용불가 참조 위치에 다가가야 사용 가능
- 대문자로 시작한다 → class 의 Student
- 개발자가 참조형 타입으로 새로 정의할 수 있다.
- String 도 class 인 참조형 데이터 타입이다. → 그런데 기본형처럼 문자 값을 바로 대입할 수 있다.
기본형, 참조형 - 변수 대입
- 대원칙 - 기본형이던 참조형이던 자바는 항상 변수의 값을 복사해서 대입한다.
- 단 참조형은 실제 값을 복사하는게 아니라 값의 위치를 저장한 주소값만 복사하는것 이다.
기본형, 참조형 - 메서드 호출
- 메서드 호출 역시 대원칙인 값 복사를 따른다.
- 메서드의 매개변수 (파라미터) 도 결국 변수일 뿐, 값 전달 역시 값을 복사해서 전달 한다.
- 기본형 - 메서드 호출 예 ⬇️
public class MethodChange1 {
public static void main(String[] args) {
int a = 10;
System.out.println("호출 전 a = " + a); // 10
changePrimitive(a); // <- a 의 값인 10 이 들어간다
System.out.println("호출 후 a = " + a); // 10
// x 에 20 이 저장 되었을뿐 a 에는 10이 여전히 존재하기 때문
}
public static void changePrimitive(int x) { // <- x 에 10 저장
x = 20; // <- 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); // 10
changeReference(dataA); // <- 주소 위치 정보 전달
System.out.println("호출 후 dataA.value = " + dataA.value); // 20
// 주소정보에 value값을 불러보니 변경이 되어 있어 20 을 호출 하게 된다.
}
public static void changeReference(Data dataX) { // <- 주소 위치정보 받음
dataX.value = 20; // <- 주소위치에 value에 저장된 값을 직접 변경
}
}
참조형과 메서드 호출 - 활용
public class Method1 {
public static void main(String[] args) {
Student student1 = new Student();
initStudent(student1, "학생1", 15, 90);
Student student2 = new Student();
initStudent(student2, "학생2", 16, 80);
printStudent(student1);
printStudent(student2);
}
// 입력 부위
static void initStudent(Student student, String name, int age, int grade) {
// Student 타입 참조데이터를 받고, name,age,grade각각 타입의 기본형 데이터를 받아서
student.name = name; // <- 복제한 참조값 객체(인스턴스) 에 접근 맴버변수의 값을 받아온 값으로 복사한다.
student.age = age;
student.grade = grade;
}
// 사용 부위
static void printStudent (Student student) {
// 각 복제한 student 객체 주소 값을 읽고
System.out.println("이름 : " + student.name + ", 나이 : " + student.age + ", 성적 : " + student.grade);
// 각 참조값의 매개변수에 접근하여 값을 읽는다.
}
}
- 객체의 생성과 객체 내부의 맴버변수도 초기화 하기 ⬇️
public class Method2 {
public static void main(String[] args) {
Student student1 = createStudent("학생1", 15, 90);
// 리턴 받은 객체값(주소)을 studnet1 참조타입 변수에 복제한다.
Student student2 = createStudent("학생2", 16, 80);
// studnet1과 다른 새로 생성된 리턴 받은 객체값(주소)을
// studnet2 참조타입 변수에 복제한다.
printStudent(student1);
printStudent(student2);
}
// 기존에 입력과 새로 만든 객체 생성기능을 합친 기능
// 리턴값으로 Student 타입의 참조 값을 던지는데
// 생성 할때에 매개변수 값 들도 동시에 전달 해준다.
// 해당 메소드를 호출할때마다 새로운 객체(인스턴스)를 생성하며 호출 한다.
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);
}
}
변수와 초기화
- 변수의 종류
- 맴버 변수 (필드) : 클래스에 선언한 것
- 지역 변수 : 메서드에 선언한 것 이나 매개변수
- 특정 지역에서만 사용되는 변수라는 뜻 → 변수가 지정된 코드블럭이 끝나면 사라진다.
- 변수의 초기화
- 맴버변수 : 맴버 변수는 선언과 동시에 자동으로 초기화가 된다
- int = 0; boolean = false, 참조형 = null
- 개발자가 직접 초기화 값을 직접 지정해줄 수 있다.
- 지역변수
null
- 참조 타입 변수에는 위치 주소 값이 들어가는데 아직 가리키는 대상이 없다면 null 이라는 값이 들어가게 된다.
- Java 에서는 참조형 타입에만 null이 허용된다.
- null 인 객체(인스턴스) 는 다른 곳에 참조값 (주소) 를 복사해 두지 않은 이상 찾을 수 없다.
- null 인 (객체)인스턴스 는 → Java 의 JVM 에서 GC (가비지 컬렉션)가 더 이상 사용하지 않는 객체(인스턴스) 라고 판단하여 자동으로 메모리에서 삭제 해준다.
NullPointerException
- Null Pointer Exception 은 말 그대로 Null을 가리키다(Pointer), 그래서 발생하는 예외(Exception) 다, → 이 말 뜻은 찾아갈 참조 값의 주소 값이 없어서 발생했다는 뜻 이다.
- NullPointerException 이 발생하면 그 즉시 코드를 중단하고 나간다.
- 참조형 데이터가 다른 클래스(참조형 데이터)에 맴버변수로 할당 되어 사용할때는 주의 해서 사용 해야 한다. (NullPointerException)발생할 위험이 있다.