본문 바로가기

Study/Java

[Java]OOP - 클래스와 메서드

객체 지향 프로그래밍(OOP)

java의 가장 큰 특징은 객체 지향 프로그래밍(Object-Oriented-Programming) 언어라는 점이다. 절차 지향 프로그래밍(Procedure-Oriented-Programming)과 다르게 OOP는 여러 객체를 조합해서 프로그램을 만드는 기법으로, 객체가 중심이 된다. 처리를 객체 단위로 하게 되면 코드 재사용성이 높고 유지보수가 쉬워, 대규모 프로젝트에 적합하다. 대신 상대적으로 처리가 느리고, 객체가 늘어날수록 용량도 늘어나며 설계부터 시간이 걸린다는 단점이 있다. OOP의 특징으로는 A(Abstraction;추상화), P(Polymorphism;다형성), I(Inheritance;상속성), E(Encapsulation;캡슐화)가 있는데, 이에 대해서는 천천히 설명할 것이다.

먼저 OOP의 단계에는 3가지가 존재한다. 첫 번째인 분석은 객체를 모델링하는 단계, 설계는 클래스를 정의하는 단계, 세 번째는 구현으로 객체를 생성하고 사용하는 단계다. 객체는 JS에서와 같이 속성과 기능으로 구성되는데, java에 있어 속성은 필드(멤버변수), 기능은 메서드로 나타낸다. 여기서 클래스가 설계도 역할을 하며 클래스 내에 존재하는 객체를 인스턴스라고 부른다.

 

클래스(Class)

java에서 객체가 없다면 코딩이 불가능하고, 객체는 클래스에서 선언되어야 한다. 클래스 선언은 [접근제한자] class 클래스명 { } 형식으로 작성된다. 접근제한자는 public이나 private 등을 말하는데, 파일명과 이름이 같은 클래스에만 붙일 수 있어서, 그 외에는 접근제한자 없이 선언한다. 그리고 클래스 생성 후 인스턴스 생성까지 되어야만 클래스가 실체화되고 작업이 가능해진다.

인스턴스 사용에도 순서가 있다. 먼저 클래스타입의 변수를 선언하고 new 연산자를 이용해 생성한다. 선언과 생성을 한꺼번에 클래스명 변수명 = new 클래스명(); 으로 할 수 있으며, 이것은 인스턴스의 주소값을 변수에 저장하는 과정이다. 이 인스턴스를 사용할 때는 변수명. 뒤에 필드명 또는 메서드명( )을 적어 해당 필드(메서드) 데이터를 인스턴스 메모리에 저장한다.

 

메서드(Method)

메서드는 객체의 동작을 정의하는 명령문의 집합으로, 호출되어야만 사용 가능하며 클래스 내에서는 주로 인스턴스의 데이터를 저장, 사용하는 역할을 한다. 메서드는 리턴 타입이 존재하는데, 메서드 수행 결과를 어떤 데이터타입으로 리턴할지 묻는 것이다. 정해진 타입이 없으면 특수 데이터타입(void)을 붙이고 return문을 생략한다. 그게 아닐 경우 return 뒤에 리턴할 변수 또는 리터럴을 명시해야 한다. 또한 메서드는 JS의 함수와 같기 때문에 매개변수를 전달할 수 있다. 매개변수는 없을 수도 있고 여러 개일 수도 있지만, return 값은 하나만 가능하다.

메서드 작성법은, 접근제한자 return타입 메서드명(매개변수1, 매개변수2, ...) { 코드; return 리턴값; } 이다. 여기서 매개변수와 리턴 값이 둘 다 없거나, 둘 다 있거나, 하나만 없는 것 모두 된다. 메서드명은 변수명 작성 규칙을 따르며, 매개변수(Parameter)는 메서드에 전달된 데이터를 저장할 변수, 전달할 데이터는 전달인자(Argument)라고 부른다. 이 요소들이 포함되는 부분을 메서드 선언부(헤더), { } 안의 부분을 메서드 구현부(바디)라고 한다.

 

class Person {    //Person 클래스

	String name;    //Person 클래스의 필드(멤버변수) 선언
	String type = "사람";    //선언 및 초기와

	public void talk() {
		System.out.println("말하기");    //Person 클래스의 talk() 메서드
	}
}



public class Main {    //Main 클래스

	public int age(int num) {    //Main 클래스의 age() 메서드

		int age = num;    //매개변수 num값을 변수에 초기화
		return age;    //int형인 age값을 return
	}


	public static void main(String[] args) {    //Main 클래스의 main() 메서드

		Person p = new Person();    //Person 클래스의 인스턴스 변수 p 생성
		p.name = "홍길동";    //p에 필드 name 사용 및 초기화

		System.out.println(p.name);    //홍길동 출력
		System.out.println(p.type);    //사람 출력

		int age = age(40);    //전달인자가 40인 age() 메서드의 리턴값을 변수에 초기화
		System.out.println(age);    //40 출력

		p.talk();    //말하기 출력
	}
}

 

만약 메서드 내에서 조건문을 쓰게 되면, 모든 조건에 return문을 작성하거나 아예 조건문 밖에 return문을 작성해야 한다. 특히 if문과 else if문 뒤에 else문이 없을 경우 그에 해당하는 return문이 없어서 오류가 날 수 있다.

 

메서드 - 오버로딩(Overloading)

메서드 오버로딩이란 동일한 메서드에 매개변수만 다르게 하여 다중 정의하는 것을 말한다. 이 매개변수는 타입이나 개수로 구별하며, 이 메서드 오버로딩의 대표적인 예로 System.out.println() 이 있다. 오버로딩 때문에 괄호 안에 int 타입을 넣어도 작동하고, String 타입을 넣어도 작동하고, 섞어서 넣었을 때도 작동하는 것이다.

아래는 간단한 계산 코드를 오버로딩 메서드로 작성한 것이다. 매개변수로 연산자(opr) 하나와 피연산자(num)를 2개 또는 3개 전달받고, 연산자에 따라 연산 후 결과를 출력한다.

class Calculator {    //Calculator 클래스
	int total;    //total 필드
    
	public void cal(char opr, int num1, int num2) {    //피연산자가 2개인 메서드
		if(opr == '+')
			total = num1 + num2;
		else if(opr == '-')
			total = num1 - num2;
		else if(opr == '*')
			total = num1 * num2;
		else if(opr == '/')
			total = num1 / num2;
		else
			total = num1 % num2;
		System.out.println(total);
	}

	public void cal(char opr, int num1, int num2, int num3) {    //피연산자가 3개인 메서드
		if(opr == '+')
			total = num1 + num2 + num3;
		else if(opr == '-')
			total = num1 - num2 - num3;
		else if(opr == '*')
			total = num1 * num2 * num3;
		else if(opr == '/')
			total = num1 / num2 / num3;
		else
			total = num1 % num2 % num3;
		System.out.println(total);
	}
}



public class Main {    //Main 클래스
	public static void main(String[] args) {    //main 메서드

		Calculator c = new Calculator();    //Calculator 클래스의 인스턴스 c 생성

		c.cal('+', 20, 10);    //결과 30 출력
		c.cal('-', 30, 10, 10);    //결과 10 출력
	}
}

 

또한 매개변수의 개수를 정확히 지정하지 못하는 경우가 생기는데, 가변 인자(비정형 인자;Variable Arguments)를 사용하면 해결된다. 가변 인자는 동일한 타입의 매개변수를 개수 제한 없이 배열 형태로 전달받는다. 앞 매개변수는 관계없이 매개변수의 마지막에 딱 한번 쓸 수 있으며, (데이터타입... 변수명) 형태로 적는다.

아래는 위의 계산 코드를 가변 인자로 살짝 변경한 것인데, 피연산자(num)가 4개 이상이어도 사용 가능하다. 여기서 주의할 것은 처음 total에 num1 값(배열 첫 번째 값)을 초기화한 후 num2 값(배열 두 번째 값)부터 for문이 시작되어야 한다는 점이다. 그냥 for문을 바로 시작할 경우, total에 이미 연산된 num1 값부터 들어가 결과가 달라진다.

class Calculator {    //Calculator 클래스
	int total;    //total 필드
    
	public void cal(char opr, int... num) {    //가변 인자 사용 메서드
		total = num[0];    //첫 번째 값 초기화

		if(opr == '+') {
			for(int i=1; i<num.length; i++) {
				total += num[i];
			}
		}
		else if(opr == '-') {
			for(int i=1; i<num.length; i++) {
				total -= num[i];
			}
		}
		else if(opr == '*') {
			for(int i=1; i<num.length; i++) {
				total *= num[i];
			}
		}
		else if(opr == '/') {
			for(int i=1; i<num.length; i++) {
				total /= num[i];
			}
		}
		else {
			for(int i=1; i<num.length; i++) {
				total %= num[i];
			}
		}
		System.out.println(total);
	}
}



public class Main {    //Main 클래스
	public static void main(String[] args) {    //main 메서드

		Calculator c = new Calculator();    //Calculator 클래스의 인스턴스 c 생성

		c.cal('+', 20, 10);    //결과 30 출력
		c.cal('-', 30, 10, 10);    //결과 10 출력
		c.cal('*', 5, 10, 20, 5);    //결과 5000 출력
	}
}

 

마지막으로 오버로딩을 하면 메서드에 중복 코드를 적는 일이 생긴다. 예를 들어 연산이 똑같은 메서드에 매개변수만 다르게 할 경우, 코드가 거의 같은 메서드를 여러 개 적게 돼서 불편함이 생긴다. 그럴 때 메서드 안에 코드 대신 오버로딩된 메서드를 호출하면 코드 재사용이 되기 때문에 중복 코드를 제거할 수 있다.

아래 코드는 직사각형과 정사각형의 넓이를 계산하는 오버로딩 메서드다. 정사각형은 가로 세로 길이가 같기 때문에 직사각형과 연산 방식은 같지만 매개변수 개수는 다르다. 이럴 때 코드를 재사용하면 중복 코드를 없애서 코드 길이를 줄일 수 있다. 지금은 짧은 예시를 들었기 때문에 별 차이가 없지만, 코드가 길어질수록 큰 도움이 될 것이다.

public double cal(double a, double b) {    //직사각형 계산 메서드
	return a*b;
}

public double cal(double a) {    //정사각형 계산 메서드
	return cal(a*a);    //코드 재사용
}

'Study > Java' 카테고리의 다른 글

[Java]상속과 참조 형 변환, 다형성  (0) 2022.02.07
[Java]생성자와 패키지, 접근제한자  (0) 2022.01.26
[Java]배열  (0) 2022.01.14
[Java]연산자와 제어문  (0) 2022.01.11
[Java]자료형과 변수, 형 변환  (0) 2022.01.04