본문 바로가기

프로그래밍 언어 기초/JAVA

Chapter 5. Java의 클래스, 생성자, 메서드

5. 0. Java의 클래스란?

 Chapter 1.에서 우리는 자바의 변수가 무엇인지에 대해 알아보았습니다. 간략하게 변수란 '자료(Data)를 저장하기 위한 공간'이라고 요약할 수 있겠습니다. , 여러분에 마트에 방문했다고 가정을 해봅시다. 오늘 저녁은 맛있는 크림 파스타를 만들려고 결정했는데요. 그래서 마트 입구에서 바구니를 들고 상품을 고르려고 마트의 코너들을 돌아다녀 봅니다. 제일 먼저 눈에 띄는 재료는 파스타 면이었습니다. 다음으로 크림 파스타의 소스를 만들기 위해 우유를 담으려고 하는데, 아뿔싸! 바구니에서 갑자기 경고창이 뜨면서 고객님의 바구니는 파스타 면만 담으실 수 있습니다하고 안내 문구가 보입니다. 기분 좋게 파스타 재료를 사려고 왔던 여러분은 크게 당황하셨을 것 같습니다. 정말 어처구니 없는 상횡이죠?

 

 자바에서도 마찬가지입니다. 만약 개발자도 여러 자료형으로 의미 있는 데이터를 도출해내야 하는데, 이상한 마트의 장바구니처럼 한 가지 데이터만 다룰 수 있다면, 정말 불편하겠죠? 그래서 자바는 여러 가지 자료형을 개발자의 입맛대로, 심지어는 자바의 함수까지도 자유롭게 다룰 수 있는 도구를 제공하는데요. 이것이 바로 클래스입니다.

 

 물론 클래스의 정확한 정의는 아래와 같이 하는 것이 올바르겠습니다.

현실 세계의 객체가 갖는 속성과 기능을 추상화(abstraction)하여 저장된 자료

하지만, 딱딱한 정의를 말씀드리는 것보다, 친숙한 소재를 사용해 비유하는 것이 이해에 조금 도움이 될까 싶어 위와 같이 설명해보았습니다.

 

5.1. 클래스(Class)

 이러한 클래스는 두 가지로 구성되어 있는데, 각각 필드(field)메소드(method)입니다. 클래스에도 1, 2, 3, 과 같은 정수형(Integer) 데이터를 직접 저장하거나 안녕하세요와 같은 문자열(String)을 직접 저장할 수 있는 변수가 있는데요. 우리는 이것을 특별히 필드(field)라고 부르기로 약속했습니다. 물론 필드도 변수랑 같은거 같은데 용어를 통일하지 않았나? 하는 의구심이 들 수도 있겠지만, 변수(Variable)과 구분 지어 부르는 이유는 그것과 구분되는 특징이 존재하기 때문입니다. 자바 클래스의 필드는 자바의 메인 메소드에서처럼 반드시 초기 값을 설정하지 않아도 각각의 자료형의 기본값(default)을 부여 받게 되는데 이것이 바로 변수와 필드의 차이점 중 하나라고 볼 수 있겠습니다. 다음으로 메소드입니다. x+y = 3x+2y와 같은 사용자 정의 수식을 변수로 표현하려면 정말 어렵겠죠? 그래서 이러한 사용자 정의 수식 등을 편하게 값(data)만 넣어주면 원하는 결과를 산출할 수 있도록 한 함수가 바로 메소드입니다. 메소드에 자세한 설명은 Chapter 1.을 참고해주세요.

 

https://1-hee.tistory.com/2

 

 

public class Basket {
	
	String member1; // 다양한 자료형을 담을 수 있다.
	int member2; 	// A = 30 과 같이 값을 설정하지 않아도 된다
	float member3 = 3.0f; // 물론 값을 직접 작성할 수도 있다.
	
	void call() {
		System.out.println("안녕하세요 OO 마트입니다.");
	}
	
	// 클래스 내부에 작성된 '함수'를 메소드 라고 부른다.
	int getPrice(int weight, int count) { // 리턴타입, 매개변수 등을 설정할 수 있다.
		int result = weight * count + 300; // 복잡한 계산식도 가능하다!
		return result;
	}

}

 

5.2. 클래스와 인스턴스

 자바에서 클래스를 사용하려면 해당 클래스 타입의 객체(object)를 선언해야 합니다. 개발자가 앞으로 XX라는 자료형인 데이터를 생성할 것이며, 그 설계도는 사용자가 정의한 XX라는 클래스에 정의되어 있다. 라고 컴퓨터에 알려주는 것이죠, 이렇게 선언된 데이터는 컴퓨터의 메모리에 올라가게 되고, 이러한 작업을 통해 개발자는 클래스를 사용할 수 있게 됩니다. 이 과정을 통해 생성된 클래스 타입의 객체를 인스턴스(instance)라고 합니다. 그리고 이렇게 개발자가 클래스를 설계한 것을 토대로 인스턴스를 만들어 내는 중간 과정을 인스턴스화라고 하며, 개발자가 클래스를 사용해서 인스턴스를 만든 과정을 설명할 때, 클래스가 인스턴스화 되어 인스턴스를 생성하였다고 말합니다.

 

public class BasketTest {

	
	// 자바의 클래스는 메인 메소드에서 인스턴스를 생성하고 사용할 수 있다.
	public static void main(String[] args) {
	
		Basket basket = new Basket(); // 클래스의 새로운 인스턴스 생성할 때에는 반드시 new 키워드를 사용한다
		basket.member1 = "hey";
		basket.member2 = 33; // 제한자를 통해 제한을 두지 않았다면 클래스의 필드는 자유롭게 수정과 삭제 가능하다.
		System.out.println(basket.member3); // 클래스의 필드를 바로 출력 가능
		
		int price = basket.getPrice(30, 2); //  클래스의 메서드 사용도 가능
		
	}

}

 

 

5.3. 클래스의 생성자

 자바의 클래스는 단순히 나는 OO이라는 클래스를 만들 거야라고 코드를 작성한다고 해서 클래스가 되는 것이 아닙니다. 물론 내부적으로는 정말 복잡한 과정이 있겠지만, 우리는 그것을 모른다고 해서 사용하는 데 어려움이 없습니다. 마치 우리가 스마트폰 어떻게 만드는지 몰라도 스마트폰 사용하는 데는 문제가 없는 것과 같은 이치이죠. 컴퓨터과학에서는 이렇게 복잡하고 어려운 내부 과정을 모르더라도 개발자가 핵심적인 개념 또는 기능을 간추려 낼 수 있는 것을 추상화(abstraction)라고 합니다. 이 개념은 객체지향 프로그래밍 챕터에서 별도로 다루는 내용이므로 이 정도로 설명하고 넘어가도록 하겠습니다. 자바의 클래스는 클래스를 생성할 때 개발자가 작성한 규칙에 따라서 클래스 인스턴스를 생성할 수 있도록 강제할 수 있고, 이렇게 클래스 인스턴스를 생성할 때 사용되는 메서드를 특별히 생성자라고 부릅니다. 생성자는 아주 특별한 메서드이기 때문에 다음의 특징을 가집니다.

 

1. 클래스명과 메서드의 명이 일치한다.

2. 리턴 타입을 정의하지 않는다.

 

 또한, 자바 클래스의 생성자는 여러 개를 작성할 수도 있습니다. 개발자가 해당 클래스의 인스턴스를 만드는 경우의 수를 다양하게 할 수 있게 하는 역할을 합니다. 클래스 인스턴스를 생성할 때 아무런 데이터도 주지 않고 생성해서 사용할 수도 있고, 초기값으로 어떤 값을 미리 계산하거나 할당해서 사용할 수도 있게하는 등 다른 개발자에게 여러 선택지를 제공할 수 있게 해주는 역할을 합니다. 즉, 생성자도 오버로딩(Overloading)이 가능하다는 말입니다.

 

public class Basket {
	
	String member1; // 다양한 자료형을 담을 수 있다.
	int member2; 	// A = 30 과 같이 값을 설정하지 않아도 된다
	float member3 = 3.0f; // 물론 값을 직접 작성할 수도 있다.
	
	void call() {
		System.out.println("안녕하세요 OO 마트입니다.");
	}
	
	// 클래스 내부에 작성된 '함수'를 메소드 라고 부른다.
	int getPrice(int weight, int count) { // 리턴타입, 매개변수 등을 설정할 수 있다.
		int result = weight * count + 300; // 복잡한 계산식도 가능하다!
		return result;
	}
	
	
	public Basket() {} // 클래스에서 매개변수가 아무것도 없는 생성자를 '기본생성자'라고 부름
	public Basket(int member2) {}
	public Basket(float member2) {} // 매개변수의 개수가 같아도 자료형이 다르면 선언 가능
	public Basket(String member1, int member2, float memberThree) {
		this.member1 = member1; // 필드명과 매개변수 명이 같을 경우에는 this 키워드를 통해 구분 지어야함.
		this.member2 = member2; // 따라서, 필드명과 매개변수 명이 같아도 컴파일 오류 X
		member3 = memberThree; // 매개변수의 이름과 필드의 이름이 다르면 this를 붙이지 않아도 사용 가능하나, 권장 X
	}

}
 

5.3. 오버로딩(Overloading)과 오버라이딩(Overriding)

 자바에서는 함수명이 같은 함수를 여러 개 작성하거나, 기존에 작성했던 함수를 새롭게 작성하여 사용하는 것이 가능합니다. 전자를 오버로딩(Overloading)이라 하고 후자를 오버라이딩(Overriding)이라고 합니다. 자바에서 오버로딩이 가능한 이유는 함수명이 같더라도 구분할 기준이 있기 때문인데, 그 기준은 바로 함수의 매개변수입니다. 매개변수의 개수, 매개변수의 자료형이 구분하는 기준이 되는데요. 매개변수의 개수와 매개변수의 자료형으로 구분하기 때문에 매개변수의 이름이 다른 것으로는 구분되지 못합니다. 즉 컴파일 오류를 발생시킨다는 것이죠.

 

public class OverloadingOverriding {
	
	void call(int value1) {
		
	}
	// void call(int value2) {}// 매개 변수명으로 구분하지 않는다. 컴파일 오류
	void call(float value1) {} // 자료형이 달라서 컴파일 오류 발생 x
	void call(int value1, int value2) {} // 매개변수의 갯수가 달라서 컴파일 오류 X
	
}

 

 오버라이딩 이미 작성된 함수를 개발자가 새롭게 바꿔서 쓰는 것을 말합니다. 새롭게 바꿔서 쓰는 것이기 때문에 개발자는 새로 작성하는 함수는 기존의 함수 그대로 따라 작성해 사용해야 합니다. 이를 개발자가 확인해서 일일이 작성하는 것은 너무 번거롭겠죠? 그래서 자바 IDE 에서는 (대표적으로 이클립스) @Overriding 이라는 어노테이션을 통해서 개발자가 잘못 작성한 부분은 컴파일 오류를 발생시켜서 실수하지 않도록 도와줄 수 있습니다. 혹은 몇가지 단축키를 통해 오버라이딩할 함수를 대신 작성해주기도 합니다.

 

public class OverloadingOverriding {
	
	void call(int value1) {}
	// void call(int value2) {}// 매개 변수명으로 구분하지 않는다. 컴파일 오류
	void call(float value1) {} // 자료형이 달라서 컴파일 오류 발생 x
	void call(int value1, int value2) {} // 매개변수의 갯수가 달라서 컴파일 오류 X
		
    // 이번 예제에서 오버라이딩에 쓸 함수!
	public int method1(int value1) {
		return value1;
	}
	
}

 

public class OverloadingOverridingChild extends OverloadingOverriding{
	
	// 오버라이딩을 하기 위해서는 클래스를 상속받아야 합니다.
	// 클래스간 부모-자식 간의 관계여야 가능
	@Override // 어노테이션을 통해 실수를 잡아줌.
	public int method1(int value1) { 
		return value1*2; // 새롭게 작성된 로직
	}
}