자바의 정석 ch07. 객체지향 프로그래밍(2)-2

6. 추상클래스

추상클래스?

  • 미완성 설계도에 비유( ↔ 클래스: 설계도)
    완성되지 못한 채로 남겨진 설계도
  • 미완성 메서드(추상메서드)를 포함하고 있다는 의미
  • 인스턴스 생성 불가
  • 상속을 통해서 자손클래스에 의해서만 완성될 수 있음
abstract class 클래스이름 {
	//...
}
  • 생성자O, 멤버변수 & 메서드 O

추상메서드

  • 선언부만 작성, 구현부는 작성X
abstract 리턴타입 메서드이름();
  • 추상클래스로부터 상속받는 자손클래스는 오버라이딩으로 추상클래스(조상)의 추상메서드를 모두 구현해야함. 그렇지 않을 경우, 자손클래스 역시 추상클래스로 지정해주어야함.
    ex.
abstract class Player {
	abstract void play(int pos);
    abstract void stop();
}

//모두 구현
class AudioPlayer extends Player {
	void play(int pos) { /*내용 생략*/ }
    void stop() { /*내용 생략*/ }
}

//모두 구현하지 않은 경우
abstract class AbstractPlayer extends Player {
	void play(int pos) { /*내용 생략*/ } //추상 메서드 구현
}
  • 추상화: 기존의 클래스의 공통부분을 뽑아내서 조상 클래스를 만드는 것
    ( ↔ 구체화 : 상속을 통해 클래스를 구현, 확장하는 작업)


7. 인터페이스

인터페이스

  • 일종의 추상클래스
  • 오직 추상메서드와 상수만을 멤버로 가질 수 있음(일반 메서드, 멤버변수 X)
interface 인터페이스이름 {
	public static final 타입 상수이름 = 값;
    public abstract 메서드이름(매개변수목록);
}
  • 모든 멤버변수는 public static final이어야 하며, 이를 생략할 수 있다.
  • 모든 메서드는 public abstract이어야 하며, 이를 생략할 수 있다.
    단, static메서드와 디폴트 메서드는 예외

인터페이스 상속

  • 인터페이스는 인터페이스로부터만 상속받을 수 있음
  • 다중상속 가능
    ex.
interface Movable {
	void move(int x, int y); //public abstract 생략한 것
}

interface Attackable {
	void attack(Unit u); //public abstract 생략한 것
}

interface Fightable extends Movable, Attackable { }
  • 인터페이스도 추상클래스처럼 그 자체로는 인스턴스 생성 불가
  • 자신에 정의된 추상메서드의 몸통을 만들어주는 클래스를 작성해야함
class 클래스이름 implements 인터페이스이름 {
	// 인터페이스에 정의된 추상메서드 구현
}

class Figher implements Figtable {
	public void move(int x, int y) {/*내용 생략*/}
    public void attack(Unit u) {/*내용 생략*/}
}
  • 인터페이스의 메서드 중 일부만 구현한다면 abstract를 붙여서 추상클래스로 선언
  • 상속과 구현을 동시에 할 수도 있음
    ex.
class Fighter extends Unit implemets Fightable {
	public void move(int x, int y) {/*내용 생략*/}
    public void attack(Unit u) {/*내용 생략*/}
} 

인터페이스를 이용한 다중상속

  • 자바에서는 다중상속을 원칙적으로 허용하지 않지만, 인터페이스를 이용하면 다중상속이 가능하다.
  • 인터페이스에서는 static 상수만 정의할 수 있으므로, 조상클래스의 멤버변수와 충돌하는 경우는 거의 없고 충돌된다 하더라도 클래스 이름을 붙여서 구분이 가능하다.

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

  • 인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로의 형변환 가능
인터페이스 Fightable을 클래스 Fighter가 구현했을 때
Fightalbe f = (Fightable)new Fighter();
Fightable f = new Fighter();
  • 메서드의 매개변수의 타입으로 사용될 수 있음 (메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공해야함)
void attack(Fightable f) {
	//...
}

→ attack 메서드를 호출할 때는 매개변수로 Fightable 인터페이스를 구현한 클래스의 인스턴스를 넘겨주어야 함.

class Fighter extends Unit implements Fightable {
	public void move(int x, int y) {/*내용 생략*/}
    public void attack(Fightable f) {/*내용 생략*/}
}

인터페이스의 장점

  • 개발시간 단축
  • 표준화 가능
  • 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다
  • 독립적인 프로그래밍 가능

인터페이스의 이해

  • 클래스를 사용하는 쪽과 클래스를 제공하는 쪽이 있다.
  • 메서드를 사용(호출)하는 쪽에서는 사용하려는 메서드와 선언부만 알면 내용은 몰라도 된다.

디폴트 메서드와 static메서드

  • 디폴트 메서드: 추상 메서드의 기본적인 구현을 제공하는 메서드
    앞에 키워드 default를 붙이며, 추상 메서드와 달리 일반 메서드처럼 몸통{}이 있어야 함.
interface MyInterface {
	void method();
    default void newMethod() {} //디폴트 메서드
}



8. 내부클래스

내부클래스란?

  • 클래스 내에 선언된 클래스
  • 장점
    ① 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있다.
    ② 코드의 복잡성을 줄일 수 있다(캡슐화)
  • ex.
class A { //외부 클래스
	//...
    class B { //내부 클래스
    	// A를 제외하고는 다른 클래스에서 잘 사용하지 않는 것이어야 함
    }
    //...
}

내부클래스의 종류와 특징

  • 내부클래스의 종류는 변수의 선언위치에 따른 종류와 같다.
내부 클래스특징
인스턴스 클래스외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 인스턴스멤버처럼 다루어진다. 주로 외부 클래스의 인스턴스멤버들과 관련된 작업에 사용될 목적으로 선언된다.
스태틱 클래스외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 static멤버처럼 다루어 진다. 주로 외부 클래스의 static멤버, 특히 static메서드에서 사용될 목적으로 선언된다.
내부 클래스 중에서 스태틱 클래스만 static멤버를 가질 수 있다. 다만, final과 static이 동시에 붙은 변수는 상수이므로 모든 내부 클래스에서 정의가 가능하다.
지역 클래스외부 클래스의 메서드나 초기화블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있다.
익명 클래스클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스(일회용)
  • 인스턴스클래스는 외부클래스의 인스턴스멤버와 스태틱 클래스의 멤버들을 객체생성 없이 바로 사용할 수 있지만, 스태틱클래스는 외부클래스의 인스턴스멤버를 객체생성 없이 사용할 수 없다.
  • 지역클래스는 외부 클래스의 인스턴스멤버와 static멤버를 모두 사용할 수 있으며, 지역 클래스가 포함된 메서드에 정의된 지역변수도 사용할 수 있다.

익명클래스

  • 다른 내부 클래스들과는 달리 이름이 없음
  • 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한번만 사용될 수 있고 오직 하나의 객체만을 생성할 수 있는 일회용 클래스
// 1.
new 조상클래스이름() {
	// 멤버 선언
}

// 2.
new 구현인터페이스이름() {
	// 멤버 선언
}



예제

import java.awt.*; 
import java.awt.event.*;

class Exercise7_28 {
	public static void main(String[] args) {
		Frame f = new Frame(); 
		f.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				e.getWindow().setVisible(false);
				e.getWindow().dispose();
				System.exit(0);
			}
		});
	}
}

좋은 웹페이지 즐겨찾기