[Java] 자바 실전(1) - 클래스와 기본형, 참조형

wony·2024년 3월 25일

Java

목록 보기
3/30

0. 개요

주제 : 김영한님의 자바 실전 강의 총 정리
내용 : 이를 통해, 자바의 실전 코드를 작성할 수 있다!

클래스, 객체, 인스턴스

클래스 : 클래스는 객체를 생성하기 위한 설계도이다. 클래스는 객체가 가져야 할 속성(변수)과 기능(메서드)를 정의한다. 예를 들어, 클래스는 속성으로 name,age,,grade를 가진다.

객체 : 객체는 클래스에서 정의한 속성과 기능을 가진 실체이다. 객체는 서로 독립적인 상태

인스턴스 : 인스턴스는 특정 클래스로부터 생성된 객체를 의미한다.

객체 vs 인스턴스
둘다 클래스에서 나온 실체라는 의미에서 비슷하게 사용되지만, 용어상 인스턴스는 객체보다 좀 더 관계에 초점을 맞춘 단어이다. 보통 student1Student의 객체이다. 라고 말하는 대신 student1Student의 인스턴스이다. 라고 특정 클래스와의 관계를 명확히 할 때 인스턴스라는 용어를 주로 사용한다.

1. 클래스와 데이터(변수선언과 객체생성!)

1) 클래스 도입

클래스를 사용해서 학생이라는 개념을 만들고, 각각의 학생 별로 본인의 이름, 나이, 성적을 관리하자

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 객체의 참조값을 가지고 있다.

2) 객체 사용

// 객체 값 대입
student1.name = "학생1";
student1.age = 15;
student1.grade = 90;
// 객체 값 사용
System.out.println("이름:" + student1.name + " 나이:" + student1.age + " 성적:" + student1.grade);
  • 객체에 접근하려면 .(dot) 을 사용하면 된다.

3) 배열 도입 - 시작

클래스와 객체 덕분에 학생 데이터를 구조적으로 이해하기 쉽게 변경할 수 있었다. 마치 실제 학생이 있고, 그 안에 각 학생의 정보가 있는 것 같다. 따라서, 사람이 이해하기도 편리하다. 이제 각각의 학생 별로 객체를 생성하고, 해당 객체에 학생의 데이터를 관리하면 된다.

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

3-1) 배열에 참조값 대입

Student[ ] students = new Student[2];

  • Student 변수를 2개 보관할 수 있는 사이즈 2의 배열을 만든다.
  • Student 타입의 변수는 Student 인스턴스의 참조값을 보관한다. Student 배열의 각각의 항목도 Student 타입의 변수일 뿐이다. 따라서, Student 타입의 참조값을 보관한다.
  • 배열에는 아직 참조값을 대입하지 않았기 때문에 참조값이 없다는 의미의 null 값으로 초기화된다.

3-2) 배열 선언 최적화

우리가 직접 정의한 Student 타입도 일반적인 변수와 동일하게 배열을 생성할 때 포함할 수 있다.

Student[] students = new Student[]{student1, student2};

생성과 선언을 동시에 하는 경우 다음과 같이 더 최적화 할 수 있다.

Student[] students = {student1, student2};

4) 배열 도입 - 리팩토링

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

2. 기본형과 참조형

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

1) 기본형 vs 참조형1

  • 기본형: 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
    • 클래스는 모두 참조형이다.

2) 기본형 vs 참조형2 - 변수 대입

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

기본형은 변수에 값을 대입하더라도 실제 사용하는 값이 변수에 바로 들어있기 때문에 해당 값만 복사해서 대입한다고 생각하면 쉽게 이해할 수 있다.

그런데 참조형의 경우 실제 사용하는 객체가 아니라 객체의 위치를 가리키는 참조값만 복사된다. 쉽게 이야기해서 실제 건물이 복사가 되는 것이 아니라 건물의 위치인 주소만 복사되는 것이다. 따라서 같은 건물을 찾아갈 수 있는 방법이 하나 늘어날 뿐이다.

실행코드

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

3) 기본형 vs 참조형3 - 메서드 호출

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

1번과 2번 다르다! 집중

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




정리

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

4-1) 참조형과 메서드 호출 - 활용(중요- 중복 처리!!!!)

  • 이전에 보았던 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);
    }
}

4-2) 메서드에서 객체 반환(4-1 업그레이드)

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

5) 변수와 초기화

변수의 종류

  • 멤버 변수 : 클래스에 선언
  • 지역 변수 : 메서드에 선언, 매개변수도 지역 변수의 한 종류이다.
  • 멤버 변수, 필드 예시
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 는 지역 변수이다.

profile
안녕하세요. wony입니다.

0개의 댓글