2018년 9월 6일 목요일

Java 오버로딩과 오버라이딩

이전시간에는 추상클래스, 인터페이스의 특징을 알아보면서 상속관계를 살펴보았다.
그 중 부모의 클래스에서 사용된 메소드를 상속받는 자식클래스가 사용하면서 코드를 재 작성하는 일이 줄었다.(재사용성에 용이)

 이번시간에는 상속받은 클래스에서 부모의 메소드를 어떠한 방식/형태로 사용할지에 따라서 사용자들의 입맛에 맞게 바꿀 수 있는 방법에 대해서 살펴보겠다.

먼저 부모의것과 동일하게 사용할 메소드1이 존재한다면, 상속받는 클래스는 자신의 클래스안에서 메소드1을 다시 작성할 필요가 없다.(이유 : 클래스를 인스턴스화해서 객체를 생성 -> 이 객체는 자신의 클래스에있는 메소드1을 사용할 때에 자신의 클래스에 존재하지 않는다면 상속받는 부모의 클래스에서 메소드1이 있는지 살펴보고 존재한다면 실행 시킨다.)

하지만, 다시작성하는경우.. 즉 부모의 클래스에 있는 메소드1의 동작방식을 바꾸고 싶을경우가 있을것이다. 다음과같은 경우로 말이다.

1. 부모의 메소드1을 재작성하고 싶다. (오버라이딩)
2. 부모의 메소드1도 사용할 수 있고 조금 더 덧붙여서(기능을 추가하여) 사용하고 싶다. (오버로드)

크게 이 2가지 형태로 사용하고싶은 방식이조금 달라질텐데 하나씩 살펴보자.

 오버라이딩
상속받은 자식클래스가 부모의 클래스에 존재하는 메소드를 바꾸고싶을때 사용한다.
즉, "자식인 나는 부모의 메소드를 재작성해서 사용할것이다"라고 하는 방법이다.
그렇다면 자식인 클래스가 생성한 인스턴스는 부모의 메소드가아닌 자신이 바꾼 메소드를 사용하며 원하는 형태로 동작하게 되는것이다.


 오버로딩 
상속받은 자식클래스 혹은 하나의 클래스안에 같은이름의 메소드가 존재하지만 메소드의 인자값이 다른형태로 되어있다. 또한 반환형(리턴값)이 같아야된다는 특징이 있다.
반환형이 다른점에서 의아 할 수도 있으나, 생각해보면 인스턴스화된 객체가 부모의 메소드를 사용시 이 자바 프로그램은 같은메소드이지만 어떠한 반환 형태로 사용된것인지 알 수 가 없다. 즉, 자바 프로그램이 같은 메소드를 두고 어떠한 메소드가 실행된건지 알 수 없으므로 에러를 발생시킨다.

 오버로딩과 오버라이딩이 비슷한 특징을 헷갈릴 수도 있으니 다시한번 정리하면,

오버라이딩은 => 같은 이름의 메소드를 재작성용도로 사용됨
오버로드 => 같은 이름의 메소드에 조금 더 덧붙여 사용됨

어떻게보면 둘다 재작성이지 않을까? 하는데 맞다. 솔직히 다시작성해서 원하는 코드를 만드는 목적이지만 여기서 구별할 수 있는 가장 큰 특징이 하나있다.

오버로드는 여러 같은 이름의 메소드를 모두 사용할 수 있다는점. (개방적)
오버라이딩은 여러 같은 이름의 메소드를 하나밖에 사용할 수 없다. (제한적)

 다음예제 코드를 통해 살펴보자.

1. Cal 클래스
  1. package org.java.project1.subproject;
  2. public class Cal{
  3.     public int first;
  4.     public int second;
  5.     public Cal(int first, int second) {
  6.         this.first = first;
  7.         this.second = second;
  8.     }
  9.     public int sum() {
  10.         return this.first+this.second;
  11.     }
  12.     public int sum(int third) {
  13.         return sum() + third;
  14.     }
  15.     public void printInfo() {
  16.         System.out.println("Cal클래스 실행");
  17.     }
  18. }

2. SubCal클래스 (Cal 클래스를 상속받음)
  1. package org.java.project1.subproject;
  2. public class SubCal extends Cal{
  3.    
  4.     public SubCal(int first, int second) {
  5.         super(first, second);
  6.     }
  7.    
  8.     public int sum(int third, int fourth) {
  9.         return sum(third) + fourth;
  10.     }
  11.    
  12.     public int sum(int third, int fourth, int fifth) {
  13.         return sum(third, fourth) + fifth;
  14.     }
  15.    
  16.     public void printInfo() {
  17.         System.out.println("SubCal클래스 실행!");
  18.     }
  19. }


3. 메인클래스
  1. package org.java.project1.subproject2;
  2. import org.java.project1.subproject.SubCal;
  3.  
  4. public class project2{
  5.     public static void main(String[] args) {
  6.         SubCal sub = new SubCal(10 ,40);
  7.         sub.printInfo();
  8.         System.out.println("인자가 없는 sum()실행 결과 : " + sub.sum());
  9.         System.out.println("인자가 하나인 sum(1)실행 : " + sub.sum(1));
  10.         System.out.println("인자가 두개인 sum(4, 5)실행 : " + sub.sum(45));
  11.         System.out.println("인자가 세개인 sum(4, 5, 6)실행 : " + sub.sum(456));
  12.     }
  13. }

이 코드는,
메소드 오버라이딩 printInfo();가 존재하며, 
메소드 오버로드 sum()이 4개가 존재한다.

printinfo();
클래스 Cal의 printInfo()가 존재하지만, 상속받는 클래스 SubCal은 printInfo()를 자신의 출력에 맞게 재작성하였다.

sum();
클래스 Cal, SubCal에는 같은 반환값에 같은 이름으로된 메소드가 4개나 존재하지만, 받는 인자값이 다르다. 메인에서 객체가 사용한 메소드를 살펴보니, sum에 인자값을 다르게 주었는데, 다시말해 입력받는 인자값에 따라 그에 맞는 메소드가 실행된다.
위에는 전부 int형이였으나 String형이 존재한다면 String이라는 인자값을 꼭 부여해야 사용할 수 있게 된다.

잘 사용하진 않을것같지만 밑의 헷갈리는 방식을 주의하자.
이 두 가지는 메소드 오버로드인데, 에러가 발생하지않는다. 메소드들의 인자값의 순서에 따라 자료형이 다르기 때문이다.

- public void printInfo(String name, int age);
- public void printInfo(int age, String name);

우리는 아직 오버로딩과 오버라이딩에 대해 자세히 깊게 이해하지는 못했으나 자바 코드를 작성하는데도 손 쉽게 사용하고 있었다.
바로 System이라는 클래스이다. 무슨말이냐?
System.out.println();을 보면 우리는 이제 몇가지 알 수 있다.

바로 .out이라는것은 static형태의 클래스 변수가 아니겠는가?
그렇다면 System은 클래스가 되는것이다.

System(클래스).out(변수).println(오버로딩되는 메소드)();

이제 오버로딩과 오버라이딩의 개념에 차이를 알게되었다.

다음시간에는 접근제어자에 대해서 살펴보겠다.

댓글 없음:

댓글 쓰기

[Java] N-I/O(Non-Blocking) 파일 읽기 쓰기 - GatheringByteChannel, ScatteringByteChannel, ByteBuffer 사용.

우리는 지금까지 다음과 같이 살펴보았다. 1.  InputStream / OutputStream : 입, 출력 스트림을 바이트로 처리하여 읽기, 쓰기. 2.  FileInputStream / FileOutputStream : 입, 출력 스트림을 ...