본문 바로가기
JAVA

CH05. 상속, 오버라이딩, package, 제어자, 다형성, 추상클래스, 인터페이스

by MINNI_ 2021. 5. 3.

[ CH05. 상속, 오버라이딩, package, 제어자, 다형성, 추상클래스, 인터페이스 ]

 

1. 상속

1.1 상속

  • 정의
    - 부모 클래스(슈퍼 클래스)에 만들어진 필드, 메소드를 자식 클래스(서브 클래스)가 물려받음
      (생성자, 초기화블럭 제외)
    - 상속을 통해 간결한 자식 클래스 작성 가능
       - 공통부분은 부모클래스에서 관리, 개별 부분은 자식 클래스에서 관리

  • 장점
    - 클래스의 간결화  -> 멤버의 중복 작성 X
    - 클래스 관리 용이 -> 클래스들의 계층적 분류
    - 소프트웨어 생산성 향상 -> 클래스 재사용과 확장, 새로운 클래스 작성 속도 빠름
  • 선언
    - extends 키워드 사용
public class Person {
}
public class Student extends Person { // Person을 상속받는 클래스 Student 선언
}
public class StudentWorker extends Student { // Student를 상속받는 StudentWorker 선언
}
  • 예제
class Point{
	private int x,y; // 한 점을 구성하는 x, y 좌표
	public void set(int x, int y) {
		this.x = x; this.y= y;
	}
	public void showPoint() { // 점의 좌표 출력
		System.out.println("("+x+"," + y + ")");
	}
}

class ColorPoint extends Point{ // Point를 상속받는 colorPoint 선언
	private String color; // 점의 색
	public void setColor(String color) {
		this.color = color;
	}
	public void showColorPoint() { // 컬러점의 좌표 출력
		System.out.print(color);
		showPoint(); // Point 클래스의 showPoint() 호출
	}
}
public class ColorPointEx {
	public static void main(String[] args) {
		Point p = new Point(); // Point 객체 생성
		p.set(1, 2); // Point 클래스의 set() 호출
		p.showPoint();
		
		ColorPoint cp = new ColorPoint(); // colorPoint 객체 생성
		cp.set(1, 2); // Point 클래스의 set() 호출
		cp.setColor("red"); // colorPoint 클래스의 setColor() 호출
		cp.showColorPoint(); // 컬러의 좌표 춮력
	}
}

// [ 출력 결과 ]
// (1, 2)
// red(3,4)

  • 특징
    - 다중 상속 X ( 자식 클래스가 여러 부모 클래스를 상속받는 것 X )
    - 상속 횟수 무제한
    - 상속의 최상위 조상 클래스: java.lang.Object 클래스
       - 모든 클래스는 자바 컴파일러에 의해 Object클래스 상속이 자동으로 이루어짐 → 11개 메서드 상속
  • 접근 지정자
    - 슈퍼 클래스의 private 멤버
       - 다른 모든 클래스에 접근 불허
       - 클래스 내의 멤버들에게만 접근 허용
    - 슈퍼 클래스의 디폴트 멤버
       - 같은 패키지 내 모든 클래스에 접근 허용
    - 슈퍼 클래스의 public 멤버
       - 다른 모든 클래스에 접근 허용
    - 슈퍼 클래스의 protected 멤버
       - 같은 패키지 내의 모든 클래스 접근 허용
       - 다른 패키지에 있어도 서브 클래스는 접근 허용

  • 슈퍼 클래스와 서브 클래스의 생성자 간의 호출 및 실행
    - new에 의해 서브 클래스의 객체가 생성될 때, 슈퍼 클래스의 생성자와 서브 클래스 생성자 모두 실행
    - 호출 순서
       - 서브 클래스 생성자 -> 실행 전 슈퍼 클래스 생성자
    - 실행 순서
       - 슈퍼 클래스의 생성자 -> 서브 클래스의 생성자

  • 서브 클래스에서 슈퍼 클래스 생성자 선택
    - 서브 클래스에서 슈퍼 클래스 생성자 하나를 선택함
    - 서브 클래스에서 슈퍼 클래스 생성자를 선택 X -> 컴파일러가 자동으로 슈퍼 클래스의 기본 생성자 선택
    - 서브 클래스에서 명시적으로 슈퍼 클래스의 생성자 선택하는 방법
       - super() 이용

  • super
    - 서브 클래스에서 슈퍼 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조 변수
    - 상속받은 멤버와 자신의 멤버가 중복 정의되어 구별해야 할 때 사용
    - 인스턴스 메서드에서만 사용 O

[결과] x=10, this.x=10, super.x = 20

  • super()
    - 서브 클래스에서 명시적으로 슈퍼 클래스의 생성자 선택 호출
    - 인자를 이용하여 슈퍼 클래스의 생성자와 일치하는 생성자 호출
    - Object클래스를 제외한 모든 클래스의 생성자 첫 줄에 this() 또는 super()를 호출해야 함
       - 그렇지 않으면, 컴파일러가 자동으로 super();를 생성자의 첫 줄에 삽입

1.2 포함

  • 정의
    - 한 클래스의 멤버변수로 다른 클래스 선언
    - 작은 단위의 클래스 먼저 만들고, 조합하여 하나의 커다란 클래스 생성

  • 상속 VS 포함
    - 각 클래스간의 관계를 파악하여 상속 또는 포함관계로 유기적 연결하게 작성하면 코드를 재사용함으로써 더 효율적인 코드 작성 가능
       - 상속관계 : ~은 ~이다. (is-a)
       - 포함관계 : ~은 ~를 가지고 있다. (has-a)
    - 2개의 클래스를 다중 상속받고 싶은 상황에서, 단일 상속을 위해, 비중이 높은 클래스 하나만 상속, 나머지는 포함 관계로 작성


2. 메소드 오버라이딩(method overriding)

  • 정의
    - 슈퍼 클래스의 메소드를 서브 클래스에서 재정의
    - 슈퍼 클래스의 메소드의 이름, 매개변수 타입 및 개수, 리턴 타입 등 모든 것 동일하게 작성
    - 접근제어자 변경 O → 조상클래스의 메서드의 접근제어자와 같거나 더 넓은 범위의 접근제어자만 가능
    - 조상클래스의 메서드보다 많은 수의 예외 선언 X. 조상클래스에 선언된 예외가 아닌 다른 예외는 안됨
    - 동적 바인딩 발생
       - 서브 클래스에 오버라이딩된 메소드가 무조건 실행되는 동적 바인딩
  • 동적 바인딩
    - 실행할 메소드를 실행 시(run time)에 결정
    - 오버라이딩 메소드가 항상 호출
  • 정적 바인딩
    - 컴파일러는 super의 접근을 정적 바인딩으로 처리
  • 오버라이딩 vs 오버로딩 예제
    - Circle과 Triangle은 Shape이다. (상속관계)
    - Circle은 Point를 가진다 (포함관계)
class DrawShape {
	public static void main(String[] args) {
		Point[] p = {   new Point(100, 100),
                        new Point(140,  50),
                        new Point(200, 100)
					};

		Triangle t = new Triangle(p);
		Circle   c = new Circle(new Point(150, 150), 50);

		t.draw(); // 삼각형을 그린다.
		c.draw(); // 원을 그린다.
	}
}

class Shape {
	String color = "black";
	void draw() {
		System.out.printf("[color=%s]%n", color);
	}
}

class Point {
	int x;
	int y;
	Point(int x, int y) {
		this.x = x;
		this.y = y;
	}
	Point() {
		this(0,0);
	}
	String getXY() {  
		return "("+x+","+y+")"; // x와 y의 값을 문자열로 반환
	}
}

class Circle extends Shape {
	Point center;	// 원의 원점좌표
	int r;			// 반지름
	Circle() {		
		this(new Point(0, 0), 100); // Circle(Point center, int r)를 호출
	}
	Circle(Point center, int r) {
		this.center = center;
		this.r = r;
	}
	void draw() { // 원을 그리는 대신에 원의 정보를 출력하도록 했다.
		System.out.printf("[center=(%d, %d), r=%d, color=%s]%n", center.x, center.y, r, color);
	}
}

class Triangle extends Shape {
	Point[] p = new Point[3];
	Triangle(Point[] p) {
		this.p = p;
	}
	void draw() { 
		System.out.printf("[p1=%s, p2=%s, p3=%s, color=%s]%n", p[0].getXY(), p[1].getXY(), p[2].getXY(), color);
	}
}​

 


3. package와 import

3.1 패키지(package)

  • 서로 관련된 클래스와 인터페이스의 묶음
  • 물리적으로 폴더형태
  • 서브패키지 가질 수 있으며, '.'로 구분
  • 클래스의 실제 이름은 패키지명이 포함
    ex) String 클래스의 실제 이름 : java.lang.String

3.2 패키지 선언

  • 선언 형태 : package 패키지명;
  • 패키지는 소스파일에 첫 번째 문장으로 단 한번 선언
  • 모든 클래스는 하나의 패키지에 속하며, 패키지 미선언시 이름없는(unnamed) 패키지에 속함
  • 하나의 소스파일에 둘 이상의 클래스 포함 → 같은 패키지

3.3 import문

  • 사용할 클래스가 속한 패키지를 지정
  • 클래스를 사용할 때 패키지명 생략

  • java.lang 패키지의 클래스는 import 안해도 사용 O

3.4 import문의 선언

  • 패키지문과 클래스 선언 사이에 선언

  • import 선언 방법

  • import문은 지정된 패키지에 포함된 클래스들만을 import, 서브패키지에 속하는 클래스들까지 import 하는 것 X
  • import한 패키지에 같은 이름의 클래스 존재하는 경우 → 클래스 앞에 패키지명 붙여야 함

4. 제어자(modifiers)

4.1 제어자 개념

  • 클래스, 변수, 메서드의 선언부에 사용되어 부가적인 의미 부여
  • 하나의 대상에 여러 개의 제어자 조합 O, 접근제어자는 단 하나만 사용

4.2 static

  • 위치 : 멤버변수, 메서드, 초기화 블록

4.3 final

  • 위치 : 클래스, 메서드, 멤버변수, 지역변수 

  • final이 붙은 변수는 상수 → 보통, 선언과 초기화 동시에 함, 인스턴스변수는 생성자에서 초기화 가능

4.4 abstract

  • 위치 : 클래스, 메서드

4.5 접근 제어자

  • 멤버, 클래스에 사용되며, 외부로부터의 접근 제한

  • 클래스의 접근제어자 : public, default

  • 멤버변수와 메서드 접근제어자 : public, protected, default, private

4.6 생성자의 접근제어자

  • 생성자의 접근제어자는 클래스의 접근제어자와 일치
  • 생성자에 접근제어자 사용 → 인스턴스 생성 제한 가능

4.7 제어자의 조합

  • 메서드에 static과 abstract 함께 사용 X
    - static 메서드는 구현부있는 메서드에서만 사용 가능
  • 클래스에 abstract와 final 함께 사용 X
  • abstract 메서드의 접근제어자가 private X
  • 메서드에서 private과 final 함께 사용할 필요 X

5. 다형성(polymorphism)

5.1 다형성 정의

  • 하나의 참조변수로 여러 타입의 객체 참조
  • 부모타입의 참조변수로 자식타입의 객체 참조 O
    자식타입의 참조변수로 부모타입의 객체 참조 X

5.2 업캐스팅(upcasting)

  • 정의
    - 서브 클래스 객체를 슈퍼 클래스 타입으로 타입 변환
  • 특징
    - 업캐스팅은 자동으로 타입 변환됨
    - 객체 내에 슈퍼 클래스의 멤버만 접근 가능
class Person { … }
class Student extends Person { … }

Student s = new Student();
Person p = s; // 업캐스팅, 자동타입변환

5.3 다운캐스팅(downcasting)

  • 정의
    - 슈퍼 클래스 객체를 서브 클래스 타입으로 변환
    - 개발자의 명시적 타입 변환 필요

5.4 instanceof 연산자

  • 업캐스팅된 레퍼런스로 객체의 타입 판단 어려움 => instaceof 연산자 사용
  • 정의
    - 레퍼런스가 가리키는 객체의 타입 식별
  • 사용법
    - 객체 레퍼런스 instanceof 클래스 타입
    - 연산 결과는 불린 값(true / false)
  • 예제

5.5 참조변수와 인스턴스변수의 연결

  • 멤버변수 중복정의참조변수의 타입에 따라 연결되는 멤버변수가 달라짐 (참조변수타입에 영향받음)
  • 메서드 중복정의 ⇒ 참조변수의 타입에 관계없이 항상 실제 인스턴스의 타입에 정의된 메서드가 호출
                             (참조변수 타입에 영향 X)

5.6 매개변수의 다형성

  • 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스 넘겨줄 수 있음

5.7 여러 종류의 객체를 하나의 배열로 다루기

  • 조상타입의 배열에 자손들의 객체 담을 수 있음


6. 추상 클래스

6.1 추상 메서드(abstract method)

  • 선언되어 있으나 구현되어 있지 않은 메소드, abstract로 선언
  • 추상 메소드는 서브 클래스에서 오버라이딩하여 구현해야 함
public abstract String getName();
public abstract void setName(String s);

6.2 추상 클래스(abstract class)

  • 추상 클래스(abstract class)의 2종류
    1) 추상 메소드를 하나라도 가진 클래스
    2) 추상 메소드가 하나도 없지만 abstract로 선언된 클래스
// 1) 추상 메소드를 포함하는 추상 클래스
abstract class Shape { // 추상 클래스 선언
	public Shape() { }
	public void paint() { draw(); }
	abstract public void draw(); // 추상 메소드
}

// 2) 추상 메소드 없는 추상 클래스
abstract class MyComponent { // 추상 클래스 선언
	String name;
	public void load(String name) {
		this.name = name;
	}
}
  • 추상 클래스는 객체를 생성 X
abstrct class Shape {
...
}

public class AbstractError {
	public static void main(String [] args) {
		Shape shape;
		shape = new Shape(); // 컴파일 오류. 추상 클래스 Shape의 객체를 생성할 수 없다.
	}
}
  • 추상 클래스의 상속
    1) 추상 클래스의 단순 상속
       - 추상 클래스를 상속받아, 추상 메소드를 구현하지 않으면 추상 클래스 O
          - 이러한 서브 클래스도 abstract로 선언
    2) 추상 클래스 구현 상속
       - 서브 클래스에서 슈퍼 클래스의 추상 메소드 구현(오버라이딩)
       - 서브 클래스는 추상 클래스 X
  • 추상 메소드 구현 예시
public class GoodCalc extends Calculator {
	@Override
	public int add(int a, int b) { // 추상 메소드 구현
		return a + b;
	}
	@Override
	public int subtract(int a, int b) { // 추상 메소드 구현
		return a - b;
	}
	@Override
	public double average(int[] a) { // 추상 메소드 구현
		double sum = 0;
		for (int i = 0; i <a.length; i++)
			sum += a[i];
		return sum/a.length;
	}

	public static void main(String [] args) {
		GoodCalc c = new GoodCalc();
		System.out.println(c.add(2,3));
		System.out.println(c.subtract(2,3));
		System.out.println(c.average(new int [] { 2,3,4 }));
	}
}

// [ 출력 결과 ]
// 5
// -1
// 3.0

7. 인터페이스

7.1 인터페이스 정의

  • 클래스가 구현해야 할 메소드들이 선언되는 추상형
  • 추상메서드와 상수만을 멤버로 가질 수 있음

7.2 인터페이스 선언

  • interface 키워드로 선언 
public interface SerialDriver{...}

7.3 인터페이스의 구성 요소들

  • 상수
    - public만 허용, public static final 생략 가능
  • 추상 메소드
    - public abstract 생략 가능
  • default 메소드(java 8)
    - 인터페이스에 코드가 작성된 메소드
    - 인터페이스를 구현하는 클래스에 자동 상속
    - public 접근 지정만 허용, public  생략 가능
  • private 메소드(java 8)
    - 인터페이스 내에 메소드 코드가 작성되어야 함
    - 인터페이스 내에 있는 다른 메소드에 의해서만 호출 가능
  • static 메소드(java 8)
    - public, private 모두 지정 가능
    - public 일 때, 생략 가능

7.4 인터페이스 특징

  • 인터페이스의 객체 생성 불가
  • 인터페이스 타입의 레퍼런스 변수 선언 가능
  • 인터페이스 구현
    - 인터페이스를 상속받는 클래스는 인터페이스의 모든 추상 메소드 반드시 구현
  • 다른 인터페이스 상속 가능
  • 인터페이스의 다중 상속 가능
  • 인터페이스는 Object클래스와 같은 최고 조상 없음
// 오류: 인터페이스 객체 생성 불가
new PhoneInterface();

// 인터페이스의 레퍼런스 변수 선언 가능 
PhoneInterface galaxy;

7.5 인터페이스 구현

  • 인터페이스의 추상 메소드를 모두 구현한 클래스
  • implements 키워드 사용
  • 여러 개의 인터페이스 동시 구현 가능 (= 다중 인터페이스 구현)
  • 예시
class SamsungPhone implements PhoneInterface { // 인터페이스 구현
	// PhoneInterface의 모든 메소드 구현
	public void sendCall() { System.out.println("띠리리리링"); }
	public void receiveCall() { System.out.println("전화가 왔습니다."); }

	// 메소드 추가 작성
	public void flash() { System.out.println("전화기에 불이 켜졌습니다."); }
}

7.6 인터페이스 상속

  • extends 키워드 이용
  • 다중 인터페이스 상속 가능
  • 상속과 구현 동시에 가능
// extends 키워드 이용
interface MobilePhoneInterface extends PhoneInterface {
	void sendSMS(); 		// 새로운 추상 메소드 추가
	void receiveSMS(); 	// 새로운 추상 메소드 추가
}

// 다중 인터페이스 상속
interface MP3Interface {
	void play(); // 추상 메소드
	void stop(); // 추상 메소드
}

interface MusicPhoneInterface extends MobilePhoneInterface, MP3Interface {
	void playMP3RingTone(); // 새로운 추상 메소드 추가
}

// 상속과 구현 동시에 가능
class Phone extends MobilePhoneInterface implements MP3Interface{
	void play(){};
	void stop(){};
}

7.7 인터페이스를 이용한 다형성

  • 서로 다르게 구현할 수 있는 기능들을 규격 선언 -> 클래스의 다형성 실현
  • 인터페이스 타입의 변수로 인터페이스를 구현한 클래스의 인스턴스 참조 가능

  • 인터페이스를 메서드의 매개변수 타입으로 지정 O

  • 인터페이스를 메서드의 리턴타입으로 지정 O

7.8 추상 클래스 vs 인터페이스

  • 유사점
    - 객체 생성 X
    - 상속을 위한 슈퍼 클래스로만 사용
    - 클래스의 다형성 실현
  • 차이점


8. 내부 클래스(inner class)

8.1 내부 클래스 정의

  • 클래스 안에 선언된 클래스
  • 특정 클래스 내에서만 주로 사용
  • GUI어플리케이션(AWT, Swing)의 이벤트처리에 주로 사용

8.2 내부 클래스의 종류와 특징

  • 내부 클래스의 종류는 변수의 선언위치에 따른 종류와 동일

8.3 내부 클래스의 제어자와 접근성

  • 내부 클래스의 접근제어자는 변수에 사용할 수 있는 접근제어자와 동일 → private, protected, default, public 

  • static 클래스만 static 멤버를 정의 가능

  • 내부 클래스도 외부 클래스의 멤버로 간주

  • 외부 클래스의 지역변수는 final이 붙은 변수(상수)만 접근 가능

  • 내부클래스의 생성

8.4 익명 클래스(anonymous class)

  • 이름이 없는 일회용 클래스, 단 하나의 객체만을 생성

class Inner{
	public static void main(String[] args){
		Button b = new Buttn("start");
		b.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				System.out.println("ActionEvent occurred!!");
            }
         } // 익명 클래스 끝
      }; 
   } // main  메서드 끝
} // Ineer 클래스 끝
  • 익명 클래스의 클래스 파일 형태
    - 익명 클래스는 이름 X ⇒ '외부 클래스명$숫자.class'형식으로 클래스 파일명 결정

 


[ 참조 ]

1. Java의 정석 3판 (지은이 : 남궁성)

2. 명품 JAVA Programming 개정 3판 (지은이 : 황기태, 김효수) 

댓글