주제 : 김영한님의 자바 실전 강의 총 정리
내용 : 이를 통해, 자바의 실전 코드를 작성할 수 있다!
클래스 : 클래스는 객체를 생성하기 위한 설계도이다. 클래스는 객체가 가져야 할 속성(변수)과 기능(메서드)를 정의한다. 예를 들어, 클래스는 속성으로 name,age,,grade를 가진다.
객체 : 객체는 클래스에서 정의한 속성과 기능을 가진 실체이다. 객체는 서로 독립적인 상태
인스턴스 : 인스턴스는 특정 클래스로부터 생성된 객체를 의미한다.
객체 vs 인스턴스
둘다 클래스에서 나온 실체라는 의미에서 비슷하게 사용되지만, 용어상 인스턴스는 객체보다 좀 더 관계에 초점을 맞춘 단어이다. 보통 student1은 Student의 객체이다. 라고 말하는 대신 student1은 Student의 인스턴스이다. 라고 특정 클래스와의 관계를 명확히 할 때 인스턴스라는 용어를 주로 사용한다.
클래스를 사용해서 학생이라는 개념을 만들고, 각각의 학생 별로 본인의 이름, 나이, 성적을 관리하자
pulic class Student { String name; int age; int grade; }
class 키워드를 사용해서 학생클래스를 정의한다. 학생 클래스는 내부에 이름, 나이, 성적 변수를 가진다.
이렇게 클래스에 정의한 변수들을 멤버 변수, 또는 필드라 한다.
- 멤버 변수 : 특정 클래스에 소속된 멤버이기 때문에 이렇게 부른다.
- 필드 : 데이터 항목을 가리키는 전통적인 용어이다.
- 자바에서 멤버 변수, 필드는 같은 뜻이다.
public class ClassStart3{ public static void main(String[] args){ Student student1; 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.name + " 나이:" + student1.age + " 성 적:" + student1.grade); System.out.println("이름:" + student2.name + " 나이:" + student2.age + " 성 적:" + student2.grade); } }
- 이제 코드를 하나씩 분석해보자
1. 변수 선언
Student student1 //Student 변수 선언
- int는 정수를 String은 문자를 담을 수 있듯이 Student는 Student 타입의 객체를 받을 수 있다.
2. 객체 생성
student1 = new Student() //Student 인스턴스 생성
- 객체를 사용하려면 먼저 설계도인 클래스를 기반으로 객체를 생성해야 한다.
- Student 클래스는 String name, int age, int grade 멤버 변수를 가지고 있다. 이 변수를 사용하는데 필요한 메모리 공간도 함께 확보한다.
3. 참조값 보관
- 객체를 생성하면 자바는 메모리 어딘가에 있는 이 객체에 접근할 수 있는 참조값(주소)(x001)을 반환한다.
- new 키워드를 통해 객체가 생성되고 나면 참조값을 반환한다. 앞서 선언한 변수인 Student student1에 생성된 객체의 참조값(x001)을 보관한다.
- Student student1 변수는 이제 메모리에 존재하는 실제 Student 객체의 참조값을 가지고 있다.
// 객체 값 대입 student1.name = "학생1"; student1.age = 15; student1.grade = 90; // 객체 값 사용 System.out.println("이름:" + student1.name + " 나이:" + student1.age + " 성적:" + student1.grade);
- 객체에 접근하려면
.(dot)을 사용하면 된다.
클래스와 객체 덕분에 학생 데이터를 구조적으로 이해하기 쉽게 변경할 수 있었다. 마치 실제 학생이 있고, 그 안에 각 학생의 정보가 있는 것 같다. 따라서, 사람이 이해하기도 편리하다. 이제 각각의 학생 별로 객체를 생성하고, 해당 객체에 학생의 데이터를 관리하면 된다.
public class ClassStart4{ public static void main(String[] args){ Student student1; 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; # 배열 추가 Student[] students = new Student[2]; students[0] = student1; students[1] = student2; System.out.println("이름:" + student1.name + " 나이:" + student1.age + " 성 적:" + student1.grade); System.out.println("이름:" + student2.name + " 나이:" + student2.age + " 성 적:" + student2.grade); } }
Student[ ] students = new Student[2];
Student변수를 2개 보관할 수 있는 사이즈 2의 배열을 만든다.Student타입의 변수는Student인스턴스의 참조값을 보관한다.Student배열의 각각의 항목도Student타입의 변수일 뿐이다. 따라서,Student타입의 참조값을 보관한다.- 배열에는 아직 참조값을 대입하지 않았기 때문에 참조값이 없다는 의미의
null값으로 초기화된다.
우리가 직접 정의한 Student 타입도 일반적인 변수와 동일하게 배열을 생성할 때 포함할 수 있다.
Student[] students = new Student[]{student1, student2};생성과 선언을 동시에 하는 경우 다음과 같이 더 최적화 할 수 있다.
Student[] students = {student1, student2};
public class ClassStart5 { 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; //배열 선언 Student[] students = new Student[]{student1, student2}; //for문 적용 for (int i = 0; i < students.length; i++) { System.out.println("이름:" + students[i].name + " 나이:" + students[i].age + " 성적:" + students[i].grade); } } }
자바는 항상 변수의 값을 복사해서 대입한다.
- 기본형:
int,long,double,boolean처럼 변수에 사용할 값을 직접 넣을 수 있는 데이터- 참조형 :
Student student1,int[] students와 같이 데이터에 접근하기 위한 참조를 저장하는 데이터 타입. 참조형은 객체 또는 배열에 사용
기본형 vs 참조형 - 기본
- 기본형은 숫자
10,20과 같이 실제 사용하는 값을 변수에 담을 수 있다. 그래서 해당 값을 바로 사용할 수 있다.- 참조형은 실제 사용하는 값을 변수에 담는 것이 아니다. 이름 그대로 실제 객체의 위치를 저장한다. 참조형에는 개체와 배열이 있다.
- 객체는
.(dot)을 통해서 메모리 상에 생성된 객체를 찾아가야 사용할 수 있다.- 배열은
[]를 통해서 메모리 상에 생성된 배열을 찾아가야 사용할 수 있다.
기본형은 연산이 가능하지만 참조형은 연산이 불가능하다.
(.) 을 통해 객체의 기본형 변수에 접근한 경우에는 연산을 할 수 있다)
int a = 10, b = 20; int sum = a+b;
참조형
Student s1 = new Student(); Student s2 = new Student(); s1 + s2 // 오류 발생;Student s1 = new Student(); Student s2 = new Student(); s1.grade = 100; s2.grade = 90; int sum = s1.grade + s2.grade; //연산 가능
쉽게 이해하는 팁
- 기본형을 제외한 나머지는 모두 참조형이다.
- 기본형은 소문자로 시작한다.
int,long,double,boolean모두 소문자로 시작한다.- 클래스는 대문자로 시작한다.
Student
- 클래스는 모두 참조형이다.
대원칙 : 자바는 항상 변수의 값을 복사해서 대입한다.
기본형은 변수에 값을 대입하더라도 실제 사용하는 값이 변수에 바로 들어있기 때문에 해당 값만 복사해서 대입한다고 생각하면 쉽게 이해할 수 있다.
그런데 참조형의 경우 실제 사용하는 객체가 아니라 객체의 위치를 가리키는 참조값만 복사된다. 쉽게 이야기해서 실제 건물이 복사가 되는 것이 아니라 건물의 위치인 주소만 복사되는 것이다. 따라서 같은 건물을 찾아갈 수 있는 방법이 하나 늘어날 뿐이다.
실행코드
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 = ref.Data@x001 dataB = ref.Data@x001 dataA.value = 10 dataB.value = 10
메서드 호출도 마찬가지이다. 메서드를 호출할 때 사용하는 매개변수(파라미터)도 결국 변수일 뿐이다. 따라서 메서드를 호출할 때 매개변수에 값을 전달하는 것도 앞서 설명한 내용과 같이 값을 복사해서 전달한다.
1번 기본형과 메서드 호출
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; } }실행 결과
메서드 호출 전: a = 10
메서드 호출 후: a = 10
2번 참조형과 메서드 호출
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.value = 10
메서드 호출 후: dataA.value = 20
정리
- 기본형: 메서드로 기본형 데이터를 전달하면, 해당 값이 복사되어 전달된다. 이 경우, 메서드 내부에서 매개변수(파라미터)의 값을 변경해도, 호출자의 변수 값에는 영향이 없다.
- 참조형: 메서드로 참조형 데이터를 전달하면, 참조값이 복사되어 전달된다. 이 경우, 메서드 내부에서 매개변수(파라미터)로 전달된 객체의 멤버 변수를 변경하면, 호출자의 객체도 변경된다.
- 이전에 보았던
class1.ClassStart3코드에는 중복되는 부분이 2가지 있다.
name,age,grade에 값을 할당- 학생 정보를 출력
initStudent(Student student, ...): 전달한 학생 객체의 필드에 값을 설정한다.printStudent(Student student, ...): 전달한 학생 객체의 필드 값을 읽어서 출력한다.
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 = name; student.age = age; student.grade = grade; } static void printStudent(Student student1) { System.out.println("이름:" + student1.name + " 나이:" + student1.age + " 성적:" + student1.grade); } }
Student student1 = new Student(); initStudent(student1, "학생1", 15, 90); Student student2 = new Student(); initStudent(student2, "학생2", 16, 80);
- 바로 객체를 생성하고, 초기값을 설정하는 부분. 2번 반복되는 부분을 하나로 합쳐보자.
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 student1) { System.out.println("이름:" + student1.name + " 나이:" + student1.age + " 성적:" + student1.grade); } }
변수의 종류
- 멤버 변수 : 클래스에 선언
- 지역 변수 : 메서드에 선언, 매개변수도 지역 변수의 한 종류이다.
public class Student{ String name; int age; int grade; }
name,age,grade는 멤버 변수이다.
public class ClassStart3 { public static void main(String[] args) { Student student1; student1 = new Student(); Student student2 = new Student(); } }
student1,student2는 지역 변수이다.