2월 25일
method
: 매개변수, 시스템method
, 오버로딩- 객체지향 프로그래밍 (OOP) 개요
- 객체지향 기초문법
Method
먼저 지난 시간 배웠던 method
를 정리하자.
우리가 따로 클래스 파일을 작성하여 method
를 호출하는 것이 아닌, main()
자체에서 원하는 method
를 사용하기 위해선 main
밖에 method
를 선언하여 사용해야 한다.
가장 기본적인 method
작성법은 다음과 같고, 생략이 불가능하다.
method
기능에 맞춰method
명을 정해준다.- 기능에 맞춰서 매개변수를 입력해준다,
- 기능을 구현한다.
- 반환할 결과값을 정해주고, 그 유형에 맞춰 반환타입을 입력한다.
이에 맞춰 작성하면 다음과 같다.
Method Declaration (메서드 선언부)
`접근제어자` `static` `반환타입` ``method` 명` (매개변수) {
실행문
return 반환값;
}
여기서 추가적인 선택과 고려사항은 다음과 같다.
기능 실행을 위해 외부로부터 받는 인자값은 생략이 가능하다.
그 예로 흔히 사용하는 println()
이 있고, 생략할 경우 내부의 기능을 실행하고 알아서 반환한다.
기능 구현시, 복합적인 기능을 만드는 것보단 하나의 기능을 제대로 수행하도록 해야한다.
복합적인 기능은 안정성과 가독성이 낮아진다.
반환 값이 없다면, 반환 자료형은 void
로 정해주면 된다.
static
키워드가 있어야 main()
실행 시 메모리 위에 올라가 있기 때문에 내부에서 언제든지 사용할 수 있다.
조건문으로 기능을 구현할 시, 조건문 내부에 return
을 입력한다면 컴파일러가 에러를 일으킨다.
if
else-if
만 존재한다면 컴파일러의 입장에선 조건을 실행이 안되고 반환값이 void
가 된다. 따라서 else
를 사용해서 무조건 반환되는 값을 설정해야 한다.
`public` `static` `int` ``method` 명` (int num) {
if (조건) { return 0;
} else if (조건) {
return 1;
} else {
return 2;
}
}
반환 자료형을 설정 시, 반환 값이 있거나 없는 method
는 존재하지 않는다.
만약에 인자값의 개수를 정확히 못 정할 경우 매개변수를 ‘가변인자 매개변수’로 해준다.
작성은 다음과 같이 한다.
`접근제어자` `static` `반환타입` ``method` 명` (int ... num) {
실행문
return 반환값;
}
method
는 자기 내부에서 자신을 호출할 수 있다. 이를 ‘재귀 함수’라고 부른다.
주로 알고리즘을 풀 때 또는 그래픽 쪽에서 사용하는 기법이다.
사용할 순 있지만 자신을 부르기에 ‘탈출 조건’을 설정하지 않으면 무한 반복이 되어 Stack Overflow
가 일어난다.
이처럼 우리가 method
를 사용한다는 것은 해당 method
를 그 자리에서 호출하는 것이다. 그래서 호출의 관점에서 다음과 같은 용어로 구분한다.
호출하는 쪽 : Caller Method
호출되는 쪽 : Callee Method
여기서 주의해야 할 것은 선언부에 있다고, 모두 Callee
가 아니다. 다른 method
가 실행시 호출되어야 만 Callee
이다.
그래서 Callee
는 Caller
에게 자신의 결과 값을 Caller
에게 반환한다. 그렇기 때문에 코드의 흐름이 Caller
가 Callee
를 호출할 시, 밖으로 탈출하여 Callee
로 들어간 후 다시 호출부로 돌아오게 된다.
이런 점을 통해서 알 수 있는 것은 method
는 특정 기능을 수행하는 코드 집합체이란 것이다.
method
는 인자값을 외부로부터 받아 일련의 기능을 수행하고 그 값을 반환한다.
따라서 코드를 기능별로 분할 관리하기 때문에 프로그램의 가독성을 높이고, 에러 검출에 용이하다. 또한 그 기능을 언제든지 재사용할 수 있기에 프로그램 개발과 유지 보수에 효율적이다.
매개변수(Parameter)
매개변수는 method
생성시, () 안에 들어가는 ‘변수’로서, 매개변수 선언부에서는 그 공간을 만들어 준다. 이후, method
호출 시 공간에 값을 넣어주는데 이를 ‘인자 값’이라 한다.
시스템 method
이렇게 method
에 대해서 전반적으로 살펴봤다. 그러나 이는 우리가 method
를 만들어서 쓰는 입장이다. 하지만 프로그램을 작성한 것을 돌아보면 주로 우린 다른 사람들이 만든 method
를 사용했고 이를 1단계라고 하자.
이젠 1단계를 넘어서 ‘남이 만든 시스템 method
를 사용하는’ 2단계로 넘어가자.
이클립스에서 method
를 호출하면 다음과 같은 화면이 나온다.
위 사진에서 참조 연산자 .
뒤로 사용할 수 있는 method
의 목록이 뜬다.
이제 우리는 method
명과 매개변수, 그리고 리턴값만을 보고 그 의미를 유추해야한다.
먼저 문자열 a
이후의 ‘char’은 문자형 자료형을 의미하고, ‘At’은 “~에서”라는 의미다.
이를 의역하면 ‘문자열을 문자형에서’라는 것이다. 그리고 매개변수는 int형 index라는 값을 받는다.
그렇다면 문자라는 하나의 배열의 인덱스를 받아서 뭘로 준다는 것인가?
바로 그 옆에 반환 값은 char
으로 되어 있다. 이를 판단할 때, charAt()
이란 method
는 문자열의 특정 단어를 인덱스로 받아서 이를 문자형으로 반환해주는 것이다.
이렇게 우리는 설명만 보고서 그 기능을 유추해서 원하는 걸 사용할 줄도 알아야 한다.
왜냐면 천재가 아니라 모든 걸 외우고 사용할 수 없기 때문이다.
Method Overloading
사실 method
오버로딩은 그렇게 대단한 것은 아니다. 하지만 알아두면 method
를 어떻게 응용해야될 지를 알 수 있다.
오버로딩의 개념은 “같은 이름의 다른 기능을 가진 method
를 만들고 매개변수만을 통해 이를 구분하여 사용하는 것”이다.
처음 method
를 만들 때, method
가 정상 작동하려면 반환값과 반환자료형이 일치해야 된다고 배웠다. 하지만 이는 각 1개씩만 설정이 가능하다.
그렇다면 다양한 값을 받고 이를 반환하는 method
를 만들고 싶다면?
아마도 오버로딩을 모른다면 기능은 비슷한데 값만 다른 method
를 계속 만들어야 한다.
굉장히 비효율적이다.
이를 해결하기 위해 ‘오버로딩’을 사용한다.
주로 우리가 사용하는 println()
도 오버로딩이 적용된 것이다.
println()
을 보면 어떤 값을 받는 반환한다.
이는 method
작성 원리에 모순되는 것인데, 막상 보면 println()
은 한 개가 아니라 다양하게 존재한다.
그럼 그걸 어떻게 아느냐?
원래 컴퓨터는 알지 못한다. 하지만 오버로딩이 생겨나면서 이를 매개변수만을 보고 구분할 수 있게 되었다.
컴파일러는 같은 이름의 method
라고 할지라도 매개변수의 차이를 보고 구분하여서 호출한다. 따라서 오버로딩을 사용하려면 매개변수의 수와 자료형을 다르게 설정해줘야 한다.
객체지향은 현 시대의 프로그래밍에 대한 하나의 패러다임이다.
절차 지향이 주류이던 시절부터 존재했지만 정형화되지 않고, 다루기 어려웠기에 비주류이던 개념이다.
먼저 절차지향적 프로그래밍은 1972 ~ 96년까지 주류 패러다임 중에 한가지로 대표언어가 바로 C언어이다. 하지만 96년으로 들어오면서 이론으로만 존재했던 객체지향이 자바로 실용화되어 나타났다.
여기서 오해하지 말 것은 객체지향의 발전은 절차지향의 쇠퇴를 의미하지 않는다는 것이다.
오히려 절차지향은 여전히 중요 분야에서 사용된다.
곧, 절차지향과 객체지향은 분리된 것이 아닌 절차지향 위에 올려진 것이다.
그래서 진정한 프로그래밍을 위해선 절차 지향을 이해할 필요가 있다.
그러면 절차지향을 알면 다 된 거 아닐까? 그건 또 아니다.
패러다임의 시작은 단순하지만 시간이 지나면서 거대해지고, 테크닉이 만들어지면서 객체지향은 다양한 관점을 내포하고 있다.
그래서 처음 단계부터 그 개념을 다룰 것이 아니라, 문법을 직접 사용해보면서 객체지향이 무엇인지 느껴보는 것이 중요하다.
먼저 객체지향 문법은 두 분류로 사용한다.
기초 문법
Constructor
| setter & getter
| this
| static
public
| protected
| pravate
| packge
위의 나열된 것이 객체지향의 기본문법인데, 일단 이를 사용하다 보면 남의 것을 가져다가 사용하는 것이 가능해진다.
이 단계를 넘어서면 중급으로 넘어가는데, 이 시기엔 ‘남의 것처럼 만드는 방법’을 배운다. 하지만 문법을 배우기보단 수업이 만들고, 써보면서 그 감각을 익히는 거라 생각하면 된다.
절차지향의 기본 원리가 만들고자하는 것의 원리를 이해하고 이를 사건의 흐름에 따라 프로그램을 작성하는 것이었다면 객체지향은 ‘프로그램을 만드려면 어떤 것이 필요한가?’ 라는 질문에서 출발한다.
바로 여기서 우리가 구현하고자 하는 것을 ‘객체’라고 한다.
흔히 TV 설계도와 TV 그 자체를 두고 비교하는데, 객체는 TV를 의미한다.
그럼 무엇이 먼저인가? 당연히 TV가 먼저가 아니라, TV설계도를 만드는 것이 먼저이다.
그래서 우리가 돌아볼 것은 여태 흔히 사용한 ‘class’라는 개념이다.
클래스는 프로그램을 작성할 때, main()
을 위한 용도로 만드는 하나의 파일단위처럼 느껴졌지만 객체지향에서 클래스는 바로 ‘설계도’ 이다.
바로 이 부분에서부터 객체지향의 정체성이 생겨난다. 따라서 우리가 기존에 클래스를 다루던 기법은 단순 프로그램의 실행을 위해 자바의 원칙을 따른 것뿐이다.
그래서 main()
은 클래스 안에 들어갈 필요가 없다. main()
을 클래스에 넣는 것은 원칙에 따라 프로그램을 실행해야 되기 때문이다.
그럼 클래스를 어떻게 구성할까? 그 방법은 다음과 같다.
클래스를 구성하는 방법
1) 내가 만들고자 하는 대상을 선정한다.
2) 선택된 대상의 속성과 기능을 분류한다.
3) 이를 기반으로 클래스로 작성한다.
여기서 객체지향의 이론은 “존재하는” 세상의 모든 것을 두 가지로 분류할 수 있다.
바로 속성과 기능이다. 전자는 데이터값을, 후자는 그 객체가 ‘할 수 있는 것’을 의미한다.
이를 기반으로 Tv를 예로 들면 다음과 같다.
속성 : 정보 값
가격, 크기, 브랜드, 볼륨의 크기, 채널이 몇 번?
기능 : 할 수 있는 것.
전원 ON / OFF
채널 UP / Down
볼륨 UP / Down
밝기 UP / Down
이를 3단계인 코드로 표현하면 다음과 같다.
public class Tv {
// 속성
int price;
int size;
String brand;
String brand1;
String brand2;
// 기능
void powerOn() {}
void powerOff() {}
void channelUp() {}
void channelDown() {}
}
여기서 속성들은 일반 지역변수가 아닌, 멤버필드라고 부른다. 그래서 메모리에서 stack에 형성되는 것이 아닌, new
로 객체가 생성될 때, heap에 생성되므로 참조변수의 성질을 가지고 있다.
또한 이렇게 작성된 클래스들은 new
를 통해서 실제 생성이 되어야 한다.
코드를 통해서 보자면 다음과 같다.
Tv tv; // Tv 클래스의 tv라는 참조변수를 stack에 만든다.
new Tv(); // 메모리 안에 실제 객체를 만든다.
Tv tv = new Tv(); // 이를 통해 heap에 있는 객체와 stack의 참조변수를 연결한다.
따라서 우리는 이제 Tv 클래스를 통해서 만들어진 객체를 tv
라는 변수를 통해서 제어하고 접근할 수 있다. 곧, Tv에 있는 기능들을 사용할 수 있다는 것이다.
더 나아가 Tv라는 클래스가 선언되는 위치를 보면 알 수 있는 것이 있다.
바로 Tv 자체는 하나의 자료형으로 이 때문에 클래스는 사용자 지정 자료형이 된다.
이러한 클래스들은 한 두가지가 아니다. 세계 곳곳의 많은 개발자들이 클래스를 만들고 오픈소스로 배포하는데, 이것이 바로 ‘라이브러리’ 이다.