[Must Have Java][Chapter 09] 클래스의 기초

허다람·2024년 5월 29일
post-thumbnail

[Must Have] 이재환의 자바 프로그래밍 입문 책을 읽고 정리한 글입니다.

💡 학습 목표
클래스의 기본 개념을 알아보고, 클래스를 통해 객체를 생성하고 사용하는 방법을 알아보자

1. 객체

객체란 우리가 표현할 수 있는 실제 세계의 모든 사물들을 말한다. 눈에 보이고 만져지는 물리적인 객체와, 보이지 않고 만져지지 않는 개념적인 객체로 나뉘어 진다.

개념적인 객체물리적인 객체
동물개, 고양이, 호랑이, 곰
자동차소나타, K5, SM5

2. 클래스

  • 클래스란 프로그래밍에서 객체와 관련된 데이터와 처리 동작을 한곳에 모은 코드 뭉치를 말한다.
  • 추상화란 특징적인 데이터와 처리 동작을 추려내는 과정을 말한다.
  • 객체지향 프로그래밍에서 추상화는 객체어서 특징적인 속성과 행위를 추출하는 과정을 의미한다. 같은 대상으로 추상화를 하더라도 목적이나 원하는 기능에 따라 여러 추상화 모델이 생성될 수 있다.

추상화 모델이 결정되고 객체를 추상화(일반화)할 때 다음과 같은 추상화 작업을 거치게 된다.

  • 명사적인 특징을 뽑아내는 추상화 과정 -> 멤버 변수(필드) 추출
  • 동사적인 특징을 뽑아내는 추상화 과정 -> 멤버 함수(메서드) 추출

아래와 같이 어떤 객체를 자바의 클래스 파일에 데이터는 필드로, 동작은 메서드로 추상화해서 기술하는 것을 클래스를 정의한다 라고 말한다.

추상화를 거친 클래스 예제 코드

// 클래스 정의 : 객체를 추상화해놓은 것
class Npc
{
	// 필드 : 데이터
	String name;
    int hp;
    
    // 메서드 : 동작
    void say()
    {
    	System.out.println("안녕하세요.");
    }
}

자세한 클래스 구조는 다음 그림과 같다.

3. 객체와 클래스

클래스를 프로그래밍에서 사용하려면 설계도를 기초로 실체를 만들 필요가 있다. 실체화된 것을 객체(오브젝트)라고 하며, 실체화하는 작업을 "객체(오브젝트)를 생성한다" 또는 "인스턴스화한다" 등으로 말한다.
소프트웨어 세계에서 객체는 클래스라는 설계도대로 구현한 것을 메모리에 탑재해 메모리 주소를 부여한 것을 의미한다.

설계도객체 생성(인스턴스화)실물
실생활자동차 설계도->공장->(생상된)자동차
프로그래밍클래스->new->(메모리에 적재된) 값

클래스를 객체로 만드는 코드

Book myBook = new Book();

// Book : 클래스 타입
// myBook : 변수
// new : 객체 생성
// Book(); : 생성자

myBook 이라는 변수를 만드는 데 변수의 자료형을 Book이라는 클래스형으로 한다.
그리고 Book 클래스의 Book() 생성자를 이용해서 new 해서(새로 만들어서) 생성된 객체를 메모리에 적재하고 변수 myBook에 대입시킨다.

클래스 객체로 만드는 예제

// 클래스 정의 : 객체를 추상화해놓은 것
class Npc
{
	// 필드 : 데이터
	String name;
    int hp;
    
    // 메서드 : 동작
    void say()
    {
    	System.out.println("안녕하세요.");
    }
}

public class NpcUse
{
	// 클래스를 이용해 객체 생성
    // Npc 라는 클래스를 이용해 Npc 객체 만들기
    // 클래스 타입의 변수는 new를 통해 객체 생성
	public static void main(String[] args) {
    	Npc saram1 = new Npc();
        
        // 필드 접근
        saram1.name = "경비";	// 멤버 변수에 직접 접근
        saram1.hp = 100;
        System.out.println(saram1.name + ":" + saram1.hp);
        
        // 메서드 호출
        saram1.say();
    }
}
// 실행 결과
// 경비:100
// 안녕하세요.

객체의 멤버 변수와 메서드는 객체의 변수명과 .을 입력하고 그 뒤에 멤버 변수를 불러 사용하면 된다.

4. 오버로딩

오버로딩이란 하나의 클래스 내에 매개변수 개수나 자료형은 다르지만 메서드명은 같은 메서드를 여러 개 정의하는 것을 말한다.

오버로딩 사용예제

class Calc
{
	int add(int a, int b)
    {
    	return a + b;
    }
    
    int add(int a)
    {
    	return a + 1;
    }
    
    double add(double a, double b)
    {
    	return a + b;
    }
}

public class OverloadingUse
{
	public static void mian(String[] agrs)
    {
    	Calc calc = new Calc();
        int nRtn1 = calc.add(3, 9);
        int nRtn2 = calc.add(3);
        double nRtn3 = calc.add(3.0, 9.0);
        
        System.out.println("Rtn1 = " + nRtn1);        								System.out.println("Rtn2 = " + nRtn2);
        System.out.println("Rtn3 = " + nRtn3);
    }
}
// 실행 결과
// Rtn1 = 12
// Rtn2 = 4
// Rtn3 = 12.0

모든 메서드명이 add()로 똑같아도 매개변수 개수가 다르거나, 매개변수 자료형이 다르다.
C언어의 경우엔 add() 기능을 하는 함수들을 add_int(), add_double()처럼 구분해서 지어야 한다.

5. 생성자

생성자란 객체 생성을 할 때만 호출하는 특수한 메서드이다.
new 연산자가 객체의 생성자를 이용하여 객체를 생성해준다.

Book myBook = new Book();
// Book : 클래스 타입
// myBook : 변수
// new : 객체 생성
// Book(); : 생성자

생성자의 특징

  • 생성자명은 클래스명하고 똑같다.
  • 메서드이지만 반환형이 없는 형태이다.

디폴트 생성자란 클래스를 정의할 때 생성자를 기술하지 않으면 매개변수가 없는 생성자가 자동으로 만들어지는 것을 말한다.

디폴트 생성자 특징

  • 생성자명과 클래스명이 같다.
  • 메서드이지만 반환형이 없다.
  • 매개변수가 없다.
  • 특별히 수행하는 기능도 없다.
class Book
{
	// 디폴트 생성자
	Book()
    {
    	// <- 자동으로 만들어짐
    }
}

이와 같이 디폴트 생성자는 프로그래머가 굳이 정의하지 않아도 컴파일러가 클래스명만 보고 자동으로 만들어주는 특성이 있다. 그래서 디폴트 생성자는 보통 생략하고 만드는 경우가 많이 있다.

6. 접근 제한자

변수나 메서드에 접근 제한자를 지정하면 접근을 제한할 수 있다.

자바에서 사용하는 접근 제한자

접근 제한다설명
public퍼블릭, 외부 클래스 어디에서나 접근 가능하다.
protected프로텍티드, 같은 패키지 내부와 상속 관계의 클래스에서만 접근 가능하다.
(아무것보 표시 안 함)디폴트, 같은 패키지 내부에서만 접근 가능하다.
private프라이빗, 같은 클래스 내부에서만 접근 가능하다.

private를 적용하면 클래스 외부에서 클래스 내부로의 변수와 메서드에 대한 접근을 제한 할 수 있다. 이것을 객체지향 프로그래밍에서 정보 은닉화 라고 부른다.

private로 멤버 변수 접근 제한을 했더라도 해당 멤버 변수를 사용할 수 있는 메서드를 제공해서 프로그램 의도에 맞게 멤버 변수의 값을 사용하도록 유도할 수 있다.
private 멤버 변수에 값을 대입하는 메서드를 세터(Setter), 값을 가져오는 메서드를 게터(Getter)라 부른다.

접근 제한자를 이용한 정보 은닉, 게터, 세터를 이용한 코드 예제

class Student1	// 접근 제한 default 상태(언제든지 변수에 접근 가능)
{
	String name;
    int age;
}

class Student2
{
	public String name;
    private int age;	// private는 접근이 제한된다. 즉 age 변수는 다른 클래스에서 접근할 수 없다.
    
    public Student2(String name, int age)
    {
    	this.name = name;
        this.age = age;
    }
    
    public int getAge()	// 게터 메서드 : 변수의 값을 다른 클래스에 가져갈 수 있게 해줌
    {
    	return age;
    }
    
    public void setAge(int age)	// 세터 메서드 : 값을 대입
    {
    	if(age < || age > 150) // 부적절한 나이를 대입하지 못하게 체크
        {
        	System.out.println("나이가 부적절합니다.");
            this.age = 0;
            return;
        }
        this.age = age;
    }
}

public class PrivateUse
{
	public static void main(String[] args)
    {
    	Student1 student1 = new Student1(); // Student1이 defaul 상태라 접근이 가능
        student1.name = "홍길동";		// 멤버 변수에 직접 접근
        student1.age = -20;				// 멤버 변수에 직접 접근
        // 직접 접근할 경우 부적절한 값이 대입될 수 있다.
        System.out.print("%s의 나이는 %d살입니다. \n",
        				student1.name, student1.age);
                        
		Student2 student2 = new Student2("전우치", 20);
        student2.name = "손오공";		// 멤버 변수에 직접 접근 // public으로 지정되어있기 때문에 가능
        student2.setAge(-10);			// 세터를 사용한 접근 // private로 지정
        // setAge()가 호출되고 부적절한 값이 걸러진다.
        int age = student2.getAge();
        System.out.print("%s의 나이는 %d살입니다. \n", 
        				student2.name, age);
    }
}

게터, 세터를 지정하는 이유 : 변수에 접근할 때 값 대입 시 부적절한 값의 대입을 막기 위함이다.
모든 변수를 private로 선언해야 하는 것은 아니지만, 필요한 경우에 private로 선언하고 게터, 세터를 활용해 오류를 막을 수 있다. 이러한 클래스 설계를 정보 은닉이라 한다.

profile
나 java봐라

0개의 댓글