추상클래스
추상클래스란?
미완성 설계도다. 미완성 설계도로 제품을 만들 수 없듯, 추상클래스로 인스턴스는 생성할 수 없다. 추상 클래스는 상속을 통해서 자손클래스에 의해서만 완성될 수 있다. 추상클래스를 사용한느 이유는 추상 클래스 자체로는 클래스로서 역할을 다 못하지만, 아무것도 없는 상태에서 시작하는 것 보다 완전하지 않아도 어느정도 갖춰진 상태에서 시작하는것이 나을 것 이다.
추상클래스는 키워드 'abstract'을 붙이기만 하면 된다. 추상 클래스는 추상 메서드를 포함하고 있다는 것을 제외하고는 일반 클래스와 전혀 다르지 않다. 추상클래스에도 생성자가 있으며, 멤버변수와 메서드도 갖고 있다.
추상메서드
메서드는 선언부와 구현부로 구성되어있다. 추상 메서드는 선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것이 추상메서드다. 즉, 설계만 해놓고 실제 수행될 내용은 작성x. 이렇게 하는 이유는 메서드의 내용이 상속받는 클래스에 따라 달라질 수 있기 때문이다. 이 때문에 주석으로 어떤 기능을 수행할 목적으로 작성되었는지 알려 주고, 실제 내용은 상속받는 클래스에서 구현하도록 비워둔다.
추상 메서드 역시 키워드 'abstract'를 앞에 붙여 주고, 추상메서드는 구현부가 없으므로 괄호 대신 ;를 적어준다.
추상클래스로부터 상속받는 자손클래스는 오버라이딩을 통해 조상인 추상클래스의 추상메서드를 모두 구현해주어야 한다. 만약 하나라도 구현 하지 않는다면, 자손 역시 추상 클래스로 지정해야 한다.
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) { /* 내용 생략 */ } // 추상 메서드를 구현
}
추상화는 자식 클래스들의 공통 부분을 뽑아내서 조상 클래스를 만드는 것이다. 상속 계층을 내려갈수록 클래스의 기능이 구체화 된다.
abstrcat class Player {
boolean pause; // 일시정지 상태를 저장하기 위한 변수
int currentPos; //현재 Play되고 있는 위치를 저장하기 위한 변수
Player() { //추상 클래스도 생성자가 있어야 한다.
pause = false;
currentPos = 0;
}
/* 지정되는 위치 (Pos)에서 재생을 시작하는 기능이 수행하도록 작성되어야 한다.*/
abstract void play(int pos); // 추상 메서드
/* 재생을 즉시 멈추는 기능을 수행하도록 작성되어야 한다. */
abstract void stop(); // 추상 메서드
void play() {
play(currentPos); //추상 메서드를 사용할 수 있다.
}
void pause() {
if(pause) { // pause가 true일 때 (정지상태)에서 pause가 호출되면,
pause = false; // pause의 상태를 false로 바꾸고,
play(currentPos); // 현재의 위치에서 play한다.
} else { //pause가 fals일 때 (play상태)에서 pause가 호출되면,
pause = true; // pause의 상태를 true로 바꾸고
stop(); // play를 멈춘다.
}
}
}
class CDPlayer extends Player {
void play(int currentPos) {
/* 조상의 추상 메서드를 구현. 내용 생략 */
}
void stop() {
/* 조상의 추상 메서드를 구현. 내용 생략*/
}
// COPlayer 클래스에 추가로 정의된 멤버
int currentTrack; // 현재 재생 중인 트랙
void nextTrack() {
currentTrack++;
...
}
void preTrack() {
if(currentTrack >1) {
currentTrack--;
}
...
}
}
인터페이스
인터페이스는 일종의 추상클래스다. 추상클래스보다 추상화 정도가 높아서 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없다. 오직 추상메서드와 상수만을 멤버로 가질 수 있으며, 그 외의 다른 어떠한 요소도 허용하지 않는다.
- 개발 시간을 단축시킬 수 있다.
- 표준화가 가능하다.
- 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
- 독립적인 프로그래밍이 가능하다.
인터페이스 작성
interface 인터페이스이름 {
public static final 타입 상수이름 = 값;
public abstract 메서드이름 (매개변수목록);
}
- 모든 멤버변수는 public static final 이어야 하며, 이를 생략할 수 있다.
- 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다. (단, static 메서드와 디폴트 메서드는 예외)
인터페이스 상속
인터페이스는 인터페이스로부터만 상속받을 수 있으며, 클래스와는 달리 다중상속, 즉 여러개의 인터페이스로부터 상속받는 것이 가능하다.
인터페이스 구현
추상 클래스처럼 그 자체로는 인스턴스를 생성할 수 없으며, 추상 클래스가 상속을 통해 추상 메서드를 완성하는 것처럼, 인터페이스도 자신에 정의된 추상메서드의 몸통을 만들어주는 클래스를 작성해야 한다.
class 클래스이름 implements 인터페이스이름 {
// 인터페이스에 정의된 추상 메서드를 구현해야 한다.
}
class Fighter implements Fightable {
public void move(int x, int y) { /* 내용 생략 */ }
public void attact(Unit u) {/* 내용 생략 */ }
}
인터페이스를 이용한 다형성
인터페이스 Fightable 을 클래스 Fighter가 구현했을 때, 다음과 같이 Fighter 인스턴스를 Fightable타입의 참조변수로 참조하는 것이 가능하다.
Fighter f = (Fightable)new Fighter();
// 또는
Fighter f = new Fighter();
리턴 타입을 인터페이스의 타입으로 지정하는 것도 가능하다.
Fightable method() {
...
Fighter f = new Fighter();
return f;
// return new Fighter();
}
디폴트 메서드
인터페이스에서 메서드를 추가한다는 것은, 추상 메서드를 추가한다는 것이고, 이 인터페이스를 구현한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야하기 때문이다. 때문에 default 메서드를 고안했는데, 디폴트 메서드는 추상 메서드의 기본적인 구현을 제공하는 메서드로 추상 메서드가 아니기 때문에 디폴트 메서드가 새로 추가되어도 해당 이넡페이스를 구현한 클래스를 변경하지 않아도 된다.
interface MyInterface {
void method();
void newMethod(); // 추상 메서드
}
// 위 코드처럼 newMethod()라는 추상 메서드를 추가하는 대신에
interface MyInterface {
void method();
default void newMethod(){}
}
대신, 새로 추가된 디폴트 메서드가 기존의 메서드와 이름이 중복되어 충돌하는 경우가 발생하는데, 이 충돌을 해결하는 규칙은 다음과 같다.
1. 여러 인터페이스의 디폴트 메서드 간의 충돌
- 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩 해야한다.
2. 디폴트 메서드와 조상 클래스의 메서드 간의 충돌
- 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.
내부 클래스
: 클래스 내에 선언된 클래스다. 한 클래스를 다른 클래스의 내부 클래스로 선언하면 두 클래스의 멤버들 간에 서로 쉽게 접근할 수 있다는 장점과 외부에는 불필요한 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있다는 장점이 있다.
class A {
...
class B {
...
}
}
내부 클래스 종류와 특징
class Outer {
private class InstanceInner {}
protected static class StaticInner {}
void myMethd() {
class LocalInner {}
}
}
1. 인스턴스 클래스
: 외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 인스턴스멤버처럼 다루어 진다. 주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용될 목적으로 선언된다.
2. 스태틱 클래스
: 외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 static멤버처럼 다루어진다. 주로 외부 클래스의 staitc멤버, 특히 static메서드에서 사용될 목적으로 선언된다.
3. 지역 클래스
: 외부 클래스의 메서드나 초기화블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있다.
4. 익명 클래스
: 클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스(일회용)
new 조상클래스이름() {
//멤버 선언
}
//또는
new 구현인터페이스이름 () {
// 멤버 선언
}
import java.awt.*;
import java.awt.event.*;
class InnerEx {
public static void main(String[] args) {
Button b = new Button ("Start");
b.addActionListener (new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("ActionEvent occurred!!!");
}
} // 익명 클래스의 끝
);
}
}
예외 처리
try {
//예외가 발생할 가능성이 있는 문장
} catch ( Exception1 ex1 ) {
//예외가 발생했을 경우 이를 처리하기 위한 문장들을 넣는다
} finally {
// 예외의 발생여부에 관계없이 항상 수행되어야하는 문장들을 넣는다.
}
키워드 throw를 이용해서 프로그래머가 고의로 예외를 발생시킬 수 있다.
1. 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만든다.
Exception e = new Exception("고의로 발생시켰음")
2. 키워드 throw를 이용하여 예외를 발생시킨다.
throw e;
'Study > JAVA' 카테고리의 다른 글
[Spring] 게시판 만들기 1 (5) | 2022.12.03 |
---|---|
[2022-11-30] Java의 정석 2 - 11. 컬렉션 프레임웍 (0) | 2022.11.30 |
[2022-11-28] Java의 정석 - 객체지향II (0) | 2022.11.29 |
[2022-11-28] JAVA의 정석 - 객체지향 I (1) | 2022.11.28 |
[2022-11-25] Java의 정석 (0) | 2022.11.25 |