본문 바로가기
Java

Java_오버라이딩, 추상화, 다형성(oop)

by 유서담 2023. 11. 9.

오버라이딩

 

  • 부모클래스에서 상속받은 메소드를 재정의 하는 것
  • 상속관계에 있는 부모클래스로부터 상속받은 메소드를 하위클래스에서 그대로 사용하지 않고 하위클래스에 맞게 내용을 변경하는 것 ( 무조건 상속관계에서만 발생한다 )

 

오버라이딩 조건 : 반환타입 + 메소드이름 + 매개변수이 다 부모클래스와 동일해야 한다. 그러나 구현내용만 다르게 정의해야 한다 ( 접근제한자는 달라도 상관없지만, 부모의 접근제한과 동일하거나 더 느슨한 접근제한만 가능하다)

 

오버라이딩의 목적 : 오버라이딩한 ( 메소드를 재정의한 ) 메소드를 부모타입의 참조변수로 실행하기 위해서

 

 

오버라이딩의 예

 

public class Printer {
	
	String black;
	
	public void print() {
		System.out.println("흑백으로 인쇄");
	}
	
}


public class ColorPrinter extends Printer {

	// Printer 객체의 print() 메소드를 재정의 하였다
	public void print() {
		System.out.println("컬러로 인쇄합니다");
	}
}

public class PhotoPrinter extends ColorPrinter {

	public void print() {
		System.out.println("사진품질로 인쇄합니다");
	}
}

 

 

public class PrinterApp1 {

	public static void main(String[] args) {
		
		Printer p1 = new Printer();
		p1.print();	// Printer 객체의 print()가 실행됨
		
		ColorPrinter p2 = new ColorPrinter();
		p2.print();	// ColorPrinter 객체의 재정의된 print()가 실행됨
		
		Printer p3 = new ColorPrinter();
		p3.print();	
        
        }
        
}

 

 

p3.print(); 코드의 결과는 ColorPrinter 객체의 재정의된 print() 메소드가 실행된다

Printer 객체를 참조하고 있어도 실제 생성한 ColorPrinter 객체의 재정의된 print()가 실행된다

즉, Printer 객체 타입의 참조변수로 자식 Printer 객체를 참조하고 있을 때 print()를 실행하면 실제 생성된 객체에 오버라이딩된 print()가 실행된다

 

위 코드에 대한 결과값 출력

 

 

참조변수 타입과 다르더라 내가 실제로 생성한 객체의 메소드가 실행된다

 

 

 

오버라이딩을 사용한 다른 예제

 

public class PC {
	
	Printer p;
	
	public void printDocument() {
		p.print();
	}
}

 

 

public class PCApp {
	
	public static void main(String[] args) {
		
		// 다양한 프린터객체를 준비한다.
		Printer p1 = new Printer();
		ColorPrinter p2 = new ColorPrinter();
		PhotoPrinter p3 = new PhotoPrinter();
		
		// 컴퓨터 객체를 준비한다
		PC pc = new PC();
		
		// 컴퓨터 객체와 프린터 객체를 조립한다
		pc.p = p1;
		
		// 문서를 인쇄한다
		pc.printDocument();
	}
}

 

 

pc.p = p1;

참조변수 p에 무엇을 대입하냐에 따라 출력값이 달라진다

 

어떤걸 대입하냐에 따라 출력값이 달라지는 것을 알 수 있다

 


오버로딩과의 차이

 

 

오버로딩의 정의 : 하나의 클래스 안에 매개변수가 서로 다른 같은 이름의 메소드를 여러개 정의하는 것

 

오버로딩의 목적 : 유사한 작업은 일관된 이름으로 구현하자

 

 

오버로딩의 예

public class Calculator{
	
    public int plus(int a, int b) {
    	return a + b;
    }
    
    public int plus(int a, int b, int c) {
    	return a + b + c;
    }
    
     public double plus(double a, double b) {
    	return a + b;
    }
    
    public double plus(double a, double b, double c) {
    	return a + b + c;
    }

 

  • 매개변수의 구성( 매개변수의 수, 또는 데이터 타입 ) 이 다르면 같은 이름의 메소드를 여러 개 정의할 수 있다

 

 

추상화

 

  • 추상화는 객체에서 공통된 속성과 기능을 추출하는 것
  • 자바에서 추상화는 공통된 속성과 기능을 모아서 추상클래스(Abstract Class)나 인터페이스(Interface)를 정의하는 것
  • 공통 속성은 변수나 상수로 표현하고, 기능은 추상메소드로 표현
  • 추상화를 통해서 하위 클래스들이 구현해야할 공통 기능을 정의할 수 있다

 

 

추상메소드 

 

  • 추상메소드는 구현부가 없는 메소드
  • 추상메소드는 추상클래스와 인터페이스에만 정의할 수 있다 ( 일반적인 클래스. 즉, 구현 클래스는 추상 메소드를 보유할 수 없다)
  • 추상메소드를 상속받았다면 반드시 오버라이딩을 통해 구현부가 있는 메소드로 만들어야 한다 

 

 // abstract를 붙여야 추상 메소드로 선언할 수 있다
  abstract void sample();

 

 

 

추상클래스

 

  • 추상클래스는 추상메소드를 보유하는 클래스
  • 추상클래스의 목적은 추상클래스를 상속받은 하위클래스가 추상메소드를 재정의(오버라이딩)하도록 한다
  • 인스턴스 변수, 인스턴스 메소드, 클래스 변수, 클래스 메소드, 생성자, 추상메소드 모두를 보유할 수 있다. ( new 연산자를 이용해서 객체 생성할 수 없다 )

 

추상 클래스의 목적 : 하위 클래스들이 반드시 구현할 기능을 추상메소드를 사용해서 추상화한다

모든 하위 클래스가 동일한 동작하는 기능을 추상 클래스에서 구현해서 상속시킴으로서 하위 클래스의 구현부담을 감소시켜준다 ( 인터페이스의 중간단계 역할을 할 수 있다)

 

// 추상클래스는 abstract가 붙는다
public abstract class Sample {

	// 추상 메소드
    abstract void test1();
    
}

 

 

 

추상메소드와 추상클래스 예시

 

// 추상메소드를 갖고 있기 때문에
// 추상클래스
public abstract class Chart {
	
	// 추상메소드 정의하기
	// 구현부가 없는 메소드
	public abstract void draw();
}


// 구현클래스 정의하기
// 추상 메소드를 보유할 수 없다
// 만약 부모로부터 추상 메소드를 상속받았으면, 반드시 메소드 재정의해야 한다
public class LineChart extends Chart{
	
	// 오버라이드 어노테이션
	// 부모의 메소드를 재정의 하는 것을 나타낸다
	@Override
	public void draw() {
		System.out.println("꺾은선 그래프를 그립니다");
		
	}
}

 

 

 

다형성

 

오버로딩(메소드 중복정의), 오버라이딩(메소드 재정의), 추상화, 인터페이스 등을 활용해서 다형성을 구현할 수 있다

 

 

오버로딩(메소드 중복정의)와 다형성

 

  • 동일한 이름의 메소드를 호출하지만, 매개변수에 따라서 실행결과가 다르게 나타난다

 

public class DataParser {
    Data[] parseData(String csv) {
      // csv파일을 해석해서 Data배열을 반환한다.
    }

    Data[] parseData(URL url) {
      // 지정된 url에서 데이터을 읽어서 Data배열을 반환한다.
    }

    Data[] parseData(ExcelDocument xls) {
      // 엑셀파일을 해석해서 Data배열을 반환한다.
    }
  }

 

 DataParser 클래스의 parseData() 메소드는 매개변수로 전달받는 값의 종류가 달라지면 실행내용이 달라진다

 

 

오버라이딩(메소드 재정의)와 다형성 

 

  • 재정의된 메소드는 상위 클래스타입으로 형변환되어 있더라도 실제 생성된 객체의 재정의된 메소드가 실행된다

 

오버라이딩을 이용한 다형성 예제

 public class Phone {
    String tel;
    
    void call() {
      전화통화 제공
    }
    void sms() {
      문자 송수신 지원
    }
  }

  public class SmartPhone extends Phone {
    String ip;

    @Override
    void call() {
      스마트폰 영상통화 지원
    }

    void web() {
      인터넷 지원
    }

    void pay() {
      앱 결재 지원
    }
  }

  public class Iphone extends SmartPhone {
    @Override
    void call() {
      페이스타임 통화 지원
    }

    @Override
    void web() {
      사파리 웹 브라우저로 인터넷 지원
    }

    @Override
    void pay() {
      애플페이 결재 지원
    }

    void faceId() {
      얼굴인식 인증 지원
    }
  }

  public class Galaxy extends SmartPhone {
    @Overide
    void web() {
      삼성 웹 브라우저로 인터넷 지원
    }

    @Override
    void pay() {
      삼성페이 결재 지원
    }

    void dex() {
      삼성 Dex모드 지원
    }
  }

 

 

재정의된 메소드 실행하기

 public static void main(String[] args) {

    Phone p1 = new Iphone();
    SmartPhone p2 = new Iphone();
    SmartPhone p3 = new Galaxy();

    p1.call();  // 페이스타임 통화 실행됨
    p1.sms();   // 문자송수신 지원이 실행됨
    p1.web();   // 컴파일 오류
    p1.pay();   // 컴파일 오류

    p2.call();  // 페이스타임 통화 실행됨
    p2.sms();   // 문자송수신 지원이 실행됨
    p2.web();   // 사파리 웹브라우저 지원이 실행됨
    p2.pay();   // 애플페이 결재 지원이 실행됨

    p3.call();  // 영상통화 지원이 실행됨
    p3.sms();   // 문자송수신 지원이 실행됨
    p3.web();   // 삼성 웹브라우저 지원이 실행됨
    p3.pay();   // 삼성페이 결재 지원이 실행됨
  }

 

 

 

다형성 요약

 

 

  • 오버로딩(메소드 중복정의)
    • 하나의 클래스 안에 동일한 이름의 메소드를 여러 개 정의하는 것
    • 접근제한자, 반환타입은 상관없음
    • 메소드이름이 동일하고, 매개변수의 타입, 갯수가 다르기만 하면 된다
    • 목적
      • 하나의 클래스안에 매개변수만 다르고 수행하는 작업은 비슷한 경우 일관성있고 동일한 메소드 이름으로 실행하게 한다

 

  • 오버라이딩(메소드 재정의)
    • 상속/구현관계에 있는 클래스의 자식 클래스에서 부모로부터 물려받은 메소드를 재정의 하는 것
    • 방법
      • 반환타입, 메소드이름, 매개변수의 갯수와 타입이 모두 일치하고, 구현내용(수행문의 내용)만 재정의 하는 것
      • 접근제한자는 부모측의 접근제한자와 동일하거나 더 느슨하게 정의해야 한다
    • 내용
      • 동일한 업무지만 자식클래스들 마다 세부 업무내용이 다른 경우 구체적인 구현을 자식클래스들이 부모의 메소드를 재정의해서 구현하도록 하는 것
    • 목적
      • 부모의 메소드와 자식의 메소드가 메소드 재정의 관계를 형성하게 되면 부모객체를 참조하고 있어도 자식에 재정의된 메소드를 실행할 수 있게 한다
    • 필드의 다형성, 매개변수의 다형성을 획득할 수 있다.

 

  • 다형성
    • 실행방법은 동일하지만 사용하는 객체가 달라지면 다른 결과가 발현되는 것
    • 객체지향 프로그래밍의 주요한 특징
    • 메소드 재정의, 추상화, 인터페이스 등의 기술을 활용해서 다양하게 활용할 수 있음