목표
자바의 Class에 대해 학습하세요.
학습할 것 (필수)
- 클래스 정의하는 방법
- 객체 만드는 방법 (new 키워드 이해하기)
- 메소드 정의하는 방법
- 생성자 정의하는 방법
- this 키워드 이해하기
마감일시
2020년 12월 19일 토요일 오후 1시까지.
과제 (Optional)
- int 값을 가지고 있는 이진 트리를 나타내는 Node 라는 클래스를 정의하세요.
- int value, Node left, right를 가지고 있어야 합니다.
- BinrayTree라는 클래스를 정의하고 주어진 노드를 기준으로 출력하는 bfs(Node node)와 dfs(Node node) 메소드를 구현하세요.
- DFS는 왼쪽, 루트, 오른쪽 순으로 순회하세요.
0. 왜 객체 지향 언어?
객체 지향언어를 이해하기 위해선 이 객체 지향언어가 기존의 절차적 언어와 다른 점들을 살펴보면 좋다.
그렇기 위해서 간단한 미션이 주어졌을때, 언어별로 어떻게 다르게 접근하는지 차이가 존재한다.
미션: 원을 회전한다.
원을 회전하는 미션이 주어졌을때, 객체 지향 언어와 절차적 언어는 다음과 같이 미션을 접근하고, 해결한다.
객체 지향 언어: 원을 먼저 구현한다. 그 다음에 원을 회전시킨다.
절차적 언어: 회전시키는 기능을 구현한다. 원을 구현한다.
이 두 언어는 이처럼 서로 다른 것에 초점을 두고 있는 것을 알 수 있다.
객체 지향 언어는 기능을 가지고 있는 '것' object, thing 에 초점을 두고 먼저 개발을 한다.
그와 달리 절차적 언어는 기능에 초점을 두고 먼저 개발하는 것을 살펴볼 수 있다.
궁극적으로 두 언어는 미션을 해결할 수 있지만, 이렇게 접근방식의 차이로 인해 상황에 따라 선호되는 언어가 다르며, 각 언어는 장단점이 존재하게 된다.
0.1 객체 지향 언어 VS 절차적 언어
각 언어의 차이는 위의 표를 참고하면 된다.
결국, 객체 지향언어를 사용하는 이유는 비록 개발하는데 시간이 오래걸리지만, 유지 보수성이 좋기 때문이다. 새로운 객체를 언제든지 만들 수 있으며, 기능 또한 쉽게 추가가 가능하다. (사용자 code의 변동 없이)
1. 클래스
1.1 클래스 정의
클래스란, 설계도와 같다고 생각하면 편하다. 만들고 싶은 물건을 어떻게 만들어야 할지 그 안에 재료와 방법이 들어 있다. 이 재료와 방법이 필드와 메서드가 된다. 클래스를 통해서 객체를 생성할 수 있다. 객체란 object로서, 만들고자 하는 thing이라고 생각하면 편리하다.
1.2 클래스 선언
그렇다면, 클래스는 어떻게 작성해야 할까?
클래스는 다음과 같은 규칙을 따라서 작성을 해야 한다.
번호 | 작성규칙 | 예 |
1 | 하나 이상의 문자로 이루어져야 한다. | Car, SportsCar |
2 | 첫 번째 글자는 숫자가 올 수 없다. | Car, 3Car(X) |
3 | '$', '_' 외의 특수문자는 사용할 수 없다. | $Car, &Car(X), @Car(X) |
4 | 자바 키워드는 사용할 수 없다. | int (x), for(x) |
출처 : 이것이 자바다
클래스를 만들 때는, 소스파일과 클래스의 이름은 동일해야 하며, 일반적으로 첫글자는 대문자로 해서 만든다.
클래스를 선언하기 위해선 다음과 같이 소스파일을 만들어야 한다.
클래스를 선언할때, {은 클래스의 시작을 의미하며, } 은 클래스의 끝을 의미한다.
1.2.1 한 소스 파일에 여러 개의 클래스 선언
일반적으로 한 소스 파일에 2개 이상의 클래스가 선언이 되는 경우가 있다. 이럴 경우에는 소스 파일은 한 개지만, 컴파일을 할때, 클래프 파일은 2개 이상이 된다.
즉 소스 파일은 클래스 선언을 담고 있는 저장 단위일뿐, 클래스 자체가 아닌것을 기억해야 한다.
1.3.1 클래스의 구성 요소
클래스에서는 객체가 가져야할 구성 요소들이 선언된다. 이는 필드(Field), 생성자(Constructor), 메소드(Method)가 존재한다. 이 각 3요소들은 생략이 되거나, 여러 개가 선언될 수 있다.
1.3.1.1 필드(Field)
필드란, 객체를 생성했을 때, 객체가 가지고 있는 변수들의 값을 보유한 곳이라고 생각하면 된다. 즉, 객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳이라고 한다. 필드는 생성자와 메소드 내에서 사용이 되며, 객체가 사라져야지 사라진다. 필드는 일반 변수랑 구부을 해야 하며, 객체 내에서 자유롭게 사용할 수 있다.
1.3.1.2 생성자
생성자는 main method가 들어가 있는 실행문에서 new 예약어로 호출되는 특별한 중괄호{} 블록이다. 생성자는 객체 생성 시 초기화의 역할을 담당한다. 필드를 초기화하거나, 메소드를 호출해서 객체를 사용할 준비를 한다. 생성자는 메소드의 특별한 형태이지만 잘보면, 클래스의 이름으로 되어 있으며, 리턴 타입이 없는 것을 확인할 수 있다.
1.3.1.3 메소드
메소드는 객체를 이용해서 자유롭게 기능을 구현할 수 있는 곳이다. 즉 객체의 동작에 해당하는 실행이라고 생각할 수 있다. 즉 메소드는 객체의 동작에 해당하는 중괄호 {} 블록을 말한다. 보통 중괄호 블록의 앞부분의 이름이 메소드의 이름이 된다.
2. 필드
필드(Field) 는 앞서 클래스에서 살펴봤듯이, 객체의 고유 데이터, 객체가 가져야 할 부품, 객체의 현재 상태 데이터를 저장하는 곳이다. 필드를 선언할 때는, 기본형 자료들은 자료형을 적은 뒤, 변수 명을 적으면 된다. 이외에 참조형 데이터의 경우에는 해당하는 클래스를 적은 뒤, 필드 이름을 적으면 된다.
위의 그림에 보이다시피, int field, String color, Body body, Engine engine 모두 필드에 해당된다. 다만, int field를 제외하고 나머지는 각 클래스들을 참조한 값인 것을 알 수 있다.
2.1 필드 선언
필드 선언은 클래스 중괄호 블록{} 어디서든 존재할 수 있다. 단, 메소드와 생성자의 중괄호에는 불가능하다. 메소드와 생성자 중괄호 안에 있는 것은 모두 로컬 변수라고 일컫는다. 필드는 클래스 내부에서 변수 처럼 선언이 되기 때문에 이를 멤버 필드, 멤버 변수라고도 부르기도 한다.
2.1.1 필드의 초기값
필드는 객체가 생성되는 시점에 자동으로 초기화가 되는데, 데이터 타입에 따라 초기값이 각각 다르게 된다. 만약 필드를 선언 할때, 특정 값으로 초기화를 진행했다면 지정된 값으로 초기화가 된다. 다음은 데이터 타입에 따른 객체 생성 시 초기화 값들이다.
분류 | 데이터 타입 | 초기값 | ||||||||||||
기본 타입 | 정수타입 | byte | 0 | |||||||||||
char | \u0000 | |||||||||||||
short | 0 | |||||||||||||
int | 0 | |||||||||||||
long | 0L | |||||||||||||
실수타입 | float | 0.0F | ||||||||||||
double | 0.0 | |||||||||||||
논리타입 | boolean | false | ||||||||||||
참조 타입 | 배열 | null | ||||||||||||
클래스 (String 포함) | null | |||||||||||||
인터페이스 | null |
2.1.2 필드 사용
필드는 생성된 클래스 내에서는 자유롭게 사용이 가능하다. 하지만, 다른 외부 클래스에서 사용을 할 경우, 반드시 '객체'를 생성해야 한다. 그 이유는 필드는 객체에 소속된 데이터이기 때문에 객체가 없으면 필드도 존재하지 않는다. 그렇기 때문에, 필드가 들어있는 클래스를 만든 뒤, 실행을 하려고 하는 main method에서 객체를 생성하면 자유롭게 필드를 사용할 수 있다. 다음 예시 코드를 보면 이해가 쉽다.
위의 소스 코드를 보면, TTokbokki라는 클래스가 선언된것을 볼 수있다.
이 것만 살펴보고 java에서 클래스를 실행하는 방법 순서대로 코드를 읽으면 편리하다.
JAVA 클래스 실행 순서
1. java -cp -bin NewClass
> NewClass 파일을 bin 폴더에서 찾는다.
2. JVM 메모리 상단에 New Class 를 올린다.
> 이 과정이 있어야, 실행이 가능하다.
3. NewClass.class 파일은 바이트 코드로 구성이 되어있는데, 컴퓨터가 읽을 수 있도록 바이너리 코드로 변환한다.
4. static 변수들이 있는지 확인하고, 초기화를 한다. (현재 소스코드에는 존재하지 않는다)
5. main method를 실행한다.
> 여기서부터 소스코드와 함께 보면 편리하다.
public static void main(String[] args) {
5-1. String Class Class Area 저장
String 클래스를 클래스 저장 영역에 저장해둔다. Class Area에 Class 가 저장될 때는 바이너리 코드 즉, 컴퓨터가 이해할 수 있는 0과 1로 저장이 된다.
public static void main(String[] args) {
5-2. args 변수 Stack 메모리 영역에 저장
args 변수를 stack 영역에 저장한다. 이때 args는 String 타입의 배열로 선언되었지만, 값이 주어지지 않았기 때문에 참조하는 값이 없다. 그래서 빈 메모리 공간으로 표현하겠다.
TTokbokki shinjeon = new TTokbokki();
5-3.객체 생성
TTokbokki 라는 클래스를 가지는 shinjeon이라는 이름을 가진 객체를 생성한다. 이때, new 예약어를 통해서 shinjeon은 TTokbokki의 클래스가 가지는 요소들을 갖게 된다. TTokbookki의 필드값, 메소드 선언부, 생성자 선언부를 저장하게 되는데 현재는 필드값만 가지고 있기 때문에 필드값만 저장이 된다. 또한, shinjeon이라는 객체는 stack 영역에 메모리가 생성이 되지만, 이는 객체를 참조하는 값으로 주소를 가진것과 유사하다. 실제 객체는 Heap 영역에 생성이 된다.
이렇게 객체가 생성이 되었을때, heap 메모리 영역에 TTokbokki 클래스와 유사한 필드값을 가진 객체가 형성된것을 볼 수 있다. 그리고 앞서 말했듯이, 객체가 생성되면 필드의 값들은 초기화 되기 때문에, name 은 string 자료 타입 이니까 null이 되었다. price의 경우에는 int형 자료 타입이기 때문에 0이 되었다. signatureMenu 또한 string 자료 타입이니까 null이 된것을 알 수 있다.
이때, 객체가 생성이 되면서 TTokbokki Class를 소스코드에 보게 되면서 Class Area에 TTokbokki Class가 로드 된것을 확인할 수 있다.
shinjeon.name = "신전 떡볶이";
shinjeon.price = 14_000;
shinjeon.signatureMenu = "오뎅튀김, 신전 김밥";
5.4 필드의 변수에 값 대입
이제는 객체에 존재하는 필드값들에 값들을 대입하면 된다. 먼저, 객체에 존재하는 필드를 대입하기 위해서는 이 필드들을 소환해야 한다.
그러기 위해서는 클래스를 먼저 써준뒤, "." 도트 연산자를 뒤에 쓴 다음 필드의 이름을 적으면 된다. 그 다음 TTokbokki 클래스에서 지정한 해당하는 필드의 자료형 타입에 맞게 값을 대입하면 된다.
예를 들어 name 필드의 경우 String 형이기 때문에 " " 이렇게 쌍따옴표로 되어있는 문자열을 대입할 수 있다.
price 필드의 경우 int형이기 때문에 정수형의 숫자를 대입할 수 있다.
signatureMenu도 name과 동일한 String 자료형이기 때문에 " " 의 쌍따옴표 처리를 한 문자열을 사용하여 대입을 하면 된다.
실제로 이렇게 간단한 소스코드이지만, 메모리 영역에서는 다음 그림과 같이 저장이 된다.
여기서 알 수 있다 싶이, int 형이자 기본형인 price만 메모리에 직접 값이 대입되었고, 나머지 String 참조형 데이터들은 heap의 다른 메모리가 저장되어 참조되는 형태인것을 알 수 있다.
System.out.println("어디 떡볶이 입니까?" +" "+shinjeon.name+ "입니다.");
System.out.println("떡볶이 가격은 얼마입니까?" +" "+shinjeon.price+ "입니다.");
System.out.println("대표 메뉴는 무엇입니까?" +" "+shinjeon.signatureMenu+ "입니다.");
5.5 출력
이렇게 객체에 저장되어 있는 name, price, signatureMenu 필드에 접근하기 위해 값을 대입했을 때처럼, 객체의 이름을 쓰고, 도트 연산자를 사용한 다음에 필드값을 적게 되면 필드 값에 대입되어 있는 값들을 확인할 수 있다.
6. JVM 메모리 정리
이렇게 소스코드가 끝이 나게 되면, JVM은 가장 먼저 실행이 끝난 메소드를 날리고, 메인마저 끝나면 메모리를 지우게 되어 다시 JVM 영역들이 깨끗해진다~~~
번외)
만약 새로운 객체를 생성한 다음에 처음에 생성한 객체를 대입하면 어떻게 될까?
코드부터 살펴보면 다음과 같다.
TTokbokki shinjeon2 = new TTokbokki();
shinjeon2 라는 새로운 객체를 생성했다. shinjeon1과 동일하게 TTokbokki클래스를 객체로 가지고 있다.
여기서 shinjeon2객체에다가 shinjeon을 대입한다.
shinjeon2 = shinjeon;
이렇게 될경우, shinjeon은 heap 영역에 있던 객체를 참조하고 있었던 것이 shinjeon2도 동일한 객체를 참조하게 된다. 이를 그림으로 표현하면 다음과 같다.
이렇게 되었을때, shinjeon2 객체의 name, price, signatureMenu 필드를 출력해보면 shinjeon1과 동일한 값이 나오게 된다.
둘이 동일한 객체를 가리키는 것을 확인하고 싶으면, shinjeon2가 price 필드를 바꾼 뒤, shinjeon 객체의 price 필드값을 호출해보면 된다. 다음과 같다.
그리고 shinjeon을 출력하게 되면 다음과 같이 변경된 1,000으로 출력되는 것을 확인할 수 있다.
이처럼 JVM에 실행시 실시간으로 메모리에 저장되는 것을 Dynamic Load라고 부른다. 다이나믹 로드는 실행 속도는 느린 단점을 가지고 있다.
3. 생성자 (Constructor)
생성자는 new라는 예약어와 함께 사용이된다. new 예약어는 객체 생성 뿐만 아니라 메모리를 생성할 때 사용하는 예약어라고 이해하면 편리하다. 어쨋든, new를 이용한 객체 생성은 밑에서 다시 설명하겠다. 일단은 생성자에 집중하자.
생성자는 클래스로부터 객체를 생성할 때, 호출되어 객체의 초기화를 담당한다. 객체 초기화란, 필드를 초기화하거나, 메소드를 호출해서 객체를 사용할 준비를 하는것을 말한다.
생성자 없이는 클래스에서 객체를 생성할 수 없다. 생성자는 new 예약어를 이용하여, 생성자가 실행이 되면, 힙(heap)영역에 객체가 생성이되고 객체에 접근할 수 있는 주소가 생성자의 메모리에 저장이 된다. 즉 참조할 수 있게 된다.
어쨋든 생성자를 이용해야지만, 객체가 생성되니 이에 유의를 해야한다.
3.1 기본 생성자 (Default Constructor)
모든 클래스에는 기본 생성자가 존재한다. 생성자는 여러개가 존재할 수 있지만, 반드시 한 개는 존재해야 한다. 만약, 생성자를 생략하였다면 컴파일러가 알아서 기본 생성자 (Default Constructor)를 생성하게 된다. 기본 생성자는 다음과 같이 구성되어 있다.
클래스 () {}
생성자는 클래스와 동일한 이름을 사용한다. 만약 클래스가 public이면, 앞에 public이 붙겠지만, 없다면 존재하지 않는다. 예를 들어 다음 클래스에서 생성자를 생략하면, 어떤 생성자가 생성되는 지 예시를 소스 코드를 통해 설명하겠다.
이렇게 소스 코드가 선언된 경우라면, 컴파일러에서 다음과 같이 생성자를 생성하게 된다.
지금 이 그림은 직접 기입한 것처럼 보이지만...(ㅎㅎ) 컴파일러의 가상의 손이 기입한 것이라 생각하면 된다.
생성자는 이렇게 기본 생성자를 생성해도 되지만, 명시적으로 생산자를 선언하는 방법도 존재한다. 바로 객체를 생성할때를 가리킨다.
NewClass shinjeon = new NewClass();
위의 코드처럼 new 예약어 뒤에 생성자가 붙게 되는데 이렇게 해도 생성자가 생성이 된 경우이다. 하지만, 만약 이렇게 생성자를 소스코드에 기입하게 되면, 컴파일러는 기본 생성자를 생성하지 않는다. 꼭 기억하십셔~
3.2 생성자 선언
생성자를 기본 생성자 대신 다양한 방식으로 선언을 하면서 객체를 초기화할 수 있다. 생성자는 선언을 할때는 매개변수를 넣어도 되고 생략을 해도 된다. 매개변수는 개수 제한이 없지만, 생성자에서 매개 변수를 선언했다면, 추후 객체를 만들 때 생성자에서 선언한 매개 변수의 양식을 지켜야 한다. 예시와 함께 살펴보면 이해가 편하다.
main method에 yeopttok이라는 객체가 new 예약어를 통해 TTokbokki 클래스타입을 가진 객체를 생성하라는 코드이다. 이때, TTokbokki 다음 괄호안에 들어가는 것들이 매개변수라 부른다. 매개 변수가 문자열, 가격, 문자열 이런식으로 구성된 것을 볼 수 있다.
이렇게 객체를 생성하기 위해서는 먼저 TTokbokki라는 클래스에 이런 양식을 가진 생성자가 존재해야 한다. 그래서 TTokbokki 클래스에 생성자를 확인하면 된다.
TTokbokki 클래스에 새로운 생성자가 생긴것을 확인할 수 있다. 기존에는 생성자 없이 필드값만 있었는데 추가하였다. 이 생성자는 객체를 만들 때, 매개 변수가 총 3개가 필요하다. String, int, String 자료 타입들을 괄호 안에 넣어주면 된다. 그래서 위의 객체 생성을 하기 위해서 main 에서 다음의 양식을 지킨것을 볼 수 있다.
하지만 만약 이렇게 덜컥 생성자를 집어넣으면, 기존에 shinjeon 객체를 만든다고 사용했던, shinjeon 객체 생성 코드들이 빨간줄이 그어진것을 볼 수 있다.
이는 TTokbokki 클래스에서 원래는 필드값만 넣어서 컴파일러가 기본 생성자를 생성하였는데, 매개변수를 활용한 생성자를 만드니, 자동으로 생성자를 만들어주지 않는다. 이를 해결하기 위해서는 그냥 shinjeon 도 객체 생성을 할 수 있도록 생성자를 main 과 동일한 양식으로 만들어서 TTokbokki 클래스에 넣어주면 된다.
이렇게 기본 생성자를 넣어주기만 하면, shinjeon 도 아무 이상없이 객체를 생성할 수 있다.
이처럼 생성자는 반드시 필요한 것이니, 꼭 주의해서 사용을 하도록 하자.
3.3 필드 초기화
필드는 기본적으로 객체를 생성할 때 기본 초기값으로 자동으로 초기화가 된다. 만약 특정한 값으로 초기화를 하고 싶다면 두 가지의 방법이 존재한다. 첫째는, 필드값을 아예 값을 지정하여 초기화를 한다. 둘째는 생성자에서 초기화를 진행하는 방법이다.
첫번째 방법처럼 필드값에다가 값을 지정해 줄 경우 클래스내에서는 해당 필드값은 모두 공통된 값을 가지게 된다. 이는 객체를 생성해서 별도로 다른 값을 지정해주지 않는 한 변동이 없다. 예를 들어 다음 코드와 같다고 생각하면 된다.
객체를 생성하는 시점에 FieldExample의 Field 값들은 자동 초기화 된다. 이때, nation만 유일하게 null로 초기화 되지 않고, 필드값으로 지정된 "대한민국"으로 지정이 된다. 그래서 main method에서 별도로 example1과 example2의 nation을 지정하지 않아도, "대한민국"이 출력되는 것을 확인할 수 있다.
이렇게 field로 초기화를 진행할 경우 객체 내에서 별도의 method로 초기화를 하지 않는 이상, 모든 객체는 동일한 field값을 갖게 되니 주의해서 사용 해야 한다.
3.4 생성자 오버로딩 (Overloading)
생성자 오버로딩은 여러 생산자를 반복해서 사용하는 경우를 일컫는다. 특히 생성자의 매개변수만 조금씩 바꾸면서 여러개의 생성자를 만드는 경우인데, 이때 매개변수는 다음 3가지 중 하나가 바뀌어야 오버로딩이라 칭한다.
1. 매개변수의 자료 타입
2. 매개 변수의 개수
3. 매개변수의 순서
다음은 생성자 오버로딩을 잘 보여주는 예시코드이다.
그림에 조금 낯선 this 예약어가 보인다. 추후에 설명하겠지만, 여기서 간략히 설명하자면, this는 해당 객체 내에 존재하는 field값을 가리킨다. 이는 매개변수와 field의 이름이 같을 경우 필드값보다 매개변수를 중요시하는 언어의 특징 때문에 객체의 필드값에 넣고싶을 경우 this를 사용해야 한다.
생성자가 각가 다른 매개변수 및 숫자를 가지고 초기화가 된 것을 확인할 수 있다. 이런 생상자를 이용해서 객체를 만들기 위해서는, 생성자의 매개 변수 양식에 맞추어서 객체를 만들어야 한다. 예를 들면 다음과 같다.
4개의 객체를 모두 각기 다른 생성자를 이용했다. 모두 생성이 가능한 것을 확인할 수 있다.
4. 메소드 (method)
메소드란 JAVA에서 함수라고 생각하면 편하다. 즉 기능을 담당하는 부분이다. method는 { } 안에 들어있는 내용을 실행하게 된다. method의 특수한 방식이 생성자라 하였는데, method를 생성하는 방법은 다음과 같다.
메소드를 작성할 때 가장 중요한 것은 리턴타입이다. 즉 어떤 자료형으로 값을 반환할지 결정해야 한다. 만약 메소드의 리턴할 값이 없을 경우에는 void를 작성하면 되고, 특정 자료형의 값을 받아야 할 경우 해당 자료형을 써주면 된다. 이와 관련된 예시는 다음 코드와 같다.
위 코드를 살펴보면, sum2라는 method는 int자료타입을 반환한다. 그리고 매개 변수를 int형으로 2개를 받는다.
그리고 매개 변수 x와 y를 이용하여, 더한 값을 int형 자료타입으로 반환한다는 뜻이다. 그래서 main 메소드에 result라는 변수에 대입을 할 수 있다. 그래서 result를 출력하면 8이 나온다.
두 번째로 storeOpen method의 경우, void 형의 자료타입인 것을 확인할 수 있다. 이는 어떠한 값도 반환하지 않는다고 하여, return도 없는 것을 확인할 수 있다. 대신 저 메소드를 실행시키면 storeOpen 메소드의 실행문이 출력되는 것을 알 수 있다.
그래서 실행 결과는 다음과 같이 나온다.
메소드 이름을 작성할 때는 다음과 같은 규칙만 지킨다면 제한 없이 생성이 가능하다.
1. 숫자로 시작해서는 안 된다.
2. $와 _ 를 제외하고 특수 문자를 사용해서는 안 된다.
3. 관례적으로 메소드명은 소문자로 작성한다.
4. 서로 다른 단어가 혼합된 경우에는 두 번째 단어는 가독성을 위해 대문자로 시작한다. (Camel case)
5. 메소드는 주로 기능에 대해 다루기 때문에 동사를 많이 사용한다.
메소드의 매개 변수
메소드에서는 매개 변수가 상당히 중요한 역할을 한다. 예를 들어, 고객 리스트가 있을 때, 특정 이름을 가진 고객의 정보를 조회한다던지 아니면 특정 ID를 지닌 고객을 조회하는 것처럼. 이럴때, 메소드를 사용하며 고객이 입력하는 값을 받아서 조회를 해야 하기 때문에 매개변수가 필요한 경우가 생긴다.
즉 매개 변수는 메소드가 실행될 때 필요한 데이터를 외부로부터 받기 위해 사용이 된다. 메소드를 실행하기 위해서 해당 데이터가 있어야지만 실행이 된다는 맥락이다.
방금 위의 예시 코드처럼 storeOpen 메소드는 메소드명 바로 뒤 () 에 아무것도 없었다. 즉 매개 변수가 없었다. 하지만, sum2 메소드 뒤에는 () 안에 매개변수 int x, int y가 있던 것을 확인할 수 있다. 이는 x와 y라는 두 값이 int형인 자료들을 필요로 한다는 의미이다.
메소드 호출
그렇다면, 이렇게 메소드를 신나게 만들었는데 클래스에서 메소드를 어떻게 사용할 수 있을까? 그건 바로 메소드를 호출하면 된다. 메소드는 클래스 안에서 그리고 클래스 밖에서 호출이 된다. 대신 클래스 밖에서 호출을 할 경우에는 객체가 생성이 되야지만 메소드가 호출된다는 점을 항상 기억하자.
다음은 메소드가 동일한 클래스에 있을 때 호출이 되는 예시 소스 코드이다.
위 소스 코드의 average2라는 메소드에 집중하자. 지금 보면, int형의 자료 타입을 반환하고, average2는 매개 변수인 a,와 b가 필요하다. a와 b는 int 자료 타입이어야 한다.
이렇게 받은 a와 b값들을 36번 줄에서 sum2라는 메소드 매개 변수로 다시 활용한 것을 볼 수 있다.
이때 sum2메소드가 호출이 된 것을 볼 수 있다. 대신, 그 안에 들어가는 매개 변수는 average2의 매개 변수이다.
이런 경우에는 sum2의 메소드가 호출되어, a와 b 값들 int x, int y 에 들어가면서 x+y 즉 a+b의 값이 int 자료형으로 반환되어 다시 average2 메소드에 돌아오게 된다.
이후 sum2로부터 받은 값을 2로 나누어준 뒤 반환이 되는 것을 볼 수 있다.
이처럼 같은 TTokbokki라는 클래스 내에서 average2가 sum2 메소드를 호출하려고 할 때, 그냥 해당 메소드의 명칭만 쓰면 되는 것을 알 수 있다. 하지만, 같은 클래스가 아니라 다른 클래스에서 메소드를 호출하려고 한다면 조금 특별한 방법을 사용해야 한다.
다음은 외부 클래스에서 메소드를 호출할 때 사용하는 방법이다. 우선, 이 소스 코드를 보기 전에는 항상 메소드를 호출하기 위해서는 객체가 먼저 생성이 되었다는 전제 조건이 있다. 그 객체의 메소드를 불러오는 방식이라고 생각하면 편하다.
우선 shinjeon이라는 객체를 생성한다. 이는 TTokbokki 클래스 타입을 가진다. 이때, sum2라는 메소드를 사용하고 싶다면, 생성된 객체 즉 shinjeon에 (.) 도트연산자를 사용한 다음에 메소드 명을 넣어주면 된다. 그리고 똑같이, 매개 변수 양식을 지켜주면 사용이 가능하다.
별로 어렵지 않으니, 사용이 익숙해질 때까지 연습을 하면 된다.
메소드 오버로딩
메소드 오버로딩은 생성자 오버로딩을 떠올리면 이해가 쉽다. 즉 클래스내에서 같은 이름의 메소드를 여러 개 선언하는 것을 의미한다. 메소드 오버로딩 또한 매개 변수의 타입, 개수, 순서중 하나만 다르면 된다.
다음은 메소드 오버로딩의 예시이다.
sum2이라는 동일한 이름의 메소드가 생성이 되었지만, 반환하는 자료형이나 매개 변수 반환형이 다른것을 볼 수 있다. 이때, 반환하는 자료형 즉 sum2 바로 앞에 있는 자료혀은 메소드 오버로딩과 연관이 없다. 매개 변수에 집중해야 한다!
그래서 해당 메소드를 main에 넣어서 실행 결과를 보면 다음과 같다.
이처럼 신비로운 메소드의 세계가 끝이 났다! 고생 많았다!! :)
5. this
this는 이것을 가리킨다. 너무 쉽다고? 맞다 하나도 안 어렵다. this는 변수들의 이름이 동일해지면서, 내가 가리키는 변수가 정확히 어떤 것을 가리키고자 할 때 사용 한다. 특히, 객체에서는 필드를 지칭할 때 사용 한다. 다음은 이와 관련된 예시 코드이다.
11번째 줄의 생성자를 보겠다. 지금 매개 변수가 String name이라고 되어 있는 것을 볼 수 있다.
그런데, 2번째 줄의 필드 값도 동일한 변수명을 사용한 것을 볼 수 있다. 이때, 매개 변수와 필드의 name을 서로 구분해주는 것이 this의 역할이 된다.
그래서 12번째 줄의 this.name 은 필드의 name을 지칭하게 되고, = 오른편의 name 은 매개 변수 name을 뜻하게 된다.
저 코드를 해석하게 되면 객체의 name 필드에 생성자의 매개 변수 값을 넣어서 초기화라는 의미와 같다.
27번의 메소드 또한 같은 원리이다. 메소드는 항상 반환값이 있어야 하니, void형으로 반환한다는 것을 확인할 수 있다. 그리고 그 다음 setPrice라는 메소드 명이 존재하며, 매개 변수 이름이 price인 것을 확인할 수 있다.
이때, 필드에도 동일한 price라는 이름이 존재하는 것을 볼 수 있다.
이런 경우에는 this를 다시 활용해서, 객체에 존재하는 필드의 price 앞에 붙여주면, 객체의 필드를 가리키게 되고, 자연슬럽게 = 오른편의 price는 매개 변수 price값이 된다. 그래서 setPrice 메소드에서는 매개 변수에 넣은 price 값으로 객체의 필드 price를 초기화 하는 모습을 볼 수 있다.
this는 필드 뿐만 아니라 메소드도 불러올 수 있는데, 보통 같은 클래스 내라면 생략을 할 뿐, 실제로는 사용이 가능하다. 다음은 이와 관련된 예시 코드이다.
28번째 줄에 setPrice라는 메소드가 약간 변경이 되었다. int형의 자료를 반환하며, 이때 반환하는 값은 return 뒤에 있는 this.price 즉 객체에 있는 필드 값을 반환하게 된다.
33번째 줄에 있는 totalPrice는 가격들의 총합을 구하려는 메소드이다.
그래서 먼저 totalPrice가 들어갈 수 있는 필드 값을 선언을 한다. (가격이 누적되어야 하므로)
그 다음 반복문을 이용하여, setPrice 메소드로 설정된 값들을 차곡차곡 더한 다음 return totalPrice하면 모두 더해진 값이 반환이 된다.
이때 setPrice는 해당 클래스내에 있는 메소드이기 때문에 this 예약어를 사용하여 해결한 모습을 확인할 수 있다. 이처럼 this 사용법까지 알아보았다! :)
과제 작업 해보기...(정말 자신 없어서 일단 해보는 만큼만 해볼게요..ㅠㅠ 이번에 클래스 개념을 알게되어서 도전해보고 싶은 용기가 생겼어요!)
노드 클래스 생성만 겨우 했네요.... ㅠ
부모클래스를 지정해서 넘기는거 글로는 쓰겠는데, 코딩하긴 또 다른 문제인듯해요...ㅠㅠ
참고자료
이것이 자바다
'JAVA > 온라인 스터디' 카테고리의 다른 글
7주차 과제: 패키지 (0) | 2020.12.27 |
---|---|
6주차 과제: 상속 #6 (0) | 2020.12.21 |
[4주차] 제어문 #4 (0) | 2020.12.10 |
[3주차] 연산자 (0) | 2020.11.27 |
2주차 라이브 방송 정리 (0) | 2020.11.22 |