목차
인터페이스와 다형성
- 추상 클래스
- 인터페이스
- 다형성
- 내부 클래스
- 무명 클래스
인터페이스는 클래스와 클래스를 연결하는 기법
추상 클래스
public abstract class Animal { // 추상 클래스 정의
// 추상 메소드 정의
public abstract void move(); // ;으로 종료됨을 유의
}
- 자바에서는 하나 이상의 추상 메소드를 포함하는 클래스를 “추상 클래스(abstract class)”라고 정의합니다.
- 이러한 추상 클래스는 객체 지향 프로그래밍에서 중요한 특징인 다형성을 가지는 메소드의 집합을 정의할 수 있도록 해줍니다.
- 추상 클래스는 동작이 정의되어 있지 않은 추상 메소드를 포함하고 있으므로, 인스턴스를 생성 할 수 없습니다.
추상 클래스 상속
public abstract class Animal { // 추상 클래스 정의
// 추상 메소드 정의
public abstract void speak(); // ;으로 종료됨을 유의
}
public class Dog extends Animal {
public void speak() {
System.out.println("멍멍!");
}
}
public class test {
public static void main(String[] args) {
Animal a = new Animal(); // 추상 클래스는 인스턴스를 생성할 수 없다.
Dog d = new Dog();
d.speak();
}
}
- 추상 클래스는 먼저 상속을 통해 자식 클래스를 만들고, 만든 자식 클래스에서 추상 클래스의 모든 추상 메소드를 오버라이딩하고 나서야 비로소 자식 클래스의 인스턴스를 생성할 수 있습니다.
- 만약 추상 클래스를 상속받은 자식 클래스가 추상 메소드를 구현하지 않으면 컴파일 오류가 발생한다.
추상 클래스 사용 이유
- 자바에서 추상 메소드를 선언하여 사용하는 목적은 추상 메소드가 포함된 클래스를 상속받는 자식 클래스가 반드시 추상 메소드를 구현하게 하도록 하기 위함입니다.
- 만약 일반 메소드로 구현한다면 사용자에 따라 해당 메소드를 구현할 수도 있고, 안 할 수도 있습니다.
- 하지만 추상 메소드가 포함된 추상 클래스를 상속받은 모든 자식 클래스는 추상 메소드를 구현해야만 인스턴스를 생성할 수 있으므로, 반드시 구현하게 됩니다.
인터페이스
- 인터페이스는 객체와 객체 사이의 상호 작용을 나타낸다.
- 자바에서 클래스는 다중 상속을 지원하지 않기 때문에 인터페이스에 추상 메소드들로만 정의를 하고 인터페이스를 implements 하고 따로 부모 클래스를 상속 할 수 있습니다.
public interface 인터페이스_이름 { // 인터페이스 안에는 추상 메소드들이 정의된다.
public void speak();
public void move();
}
public class 클래스_이름 implements 인터페이스_이름 {
void speak() { // 인터페이스를 구현하는 클래스는 추상 메소드의 몸체를 구현하여야 한다.
System.out.println("speak 추상 메소드 구현");
}
void move() {
System.out.println("move 추상 메소드 구현");
}
}
인터페이스와 타입
public interface RemoteControl {
// 추상 메소드 정의
public void turnOn(); // 전원 킴
public void turnOff(); // 전원 끔
}
public class Television implements RemoteControl {
public void turnOn(){ ... }
public void turnOff() { ... }
}
RemoteControl obj = new Television(); /*
Television 객체이지만 RemoteControl 인터페이스를
구현하기 때문에 RemoteControl 타입의 변수로 가리 킬 수 있다.
*/
obj.turnOn();
obj.turnOff();// obj를 통해 RemoteControl 인터페이스에 정의된 메소드만을 호출 할 수 있다.
인터페이스 동시 구현
public interface SerialCommunication {
void send(byte[] data); // 시리얼 포트에 데이터를 전송한다.
byte[] receive(); // 시리얼 포트에서 데이터를 받는다.
}
public class Television implements RemoteControl, SerialCommunication {
// RemoteControl와 SerialCommunication의 메소드를 동시에 구현하여야 한다.
public void turnOn() { ... }
public void turnOff() { ... }
public void send(byte[] data) { ... }
public byte[] receive() { ... }
}
- 클래스는 여러 개의 인터페이스를 다중 구현할 수 있다.
인터페이스 상속
public interface AdvancedRemoteControl extends RemoteControl {
public void volUp();
public void volDown();
}
- 인터페이스도 다른 인터페이스를 상속받을 수 있다.
인터페이스 활용
interface Days { // 상수가 정의된 인터페이스
public static final int SUNDAY = 1, MONDAY = 2, TUESDAY = 3,
WEDNESDAY = 4, THURSDAY = 5, FRIDAY = 6, SATURDAY = 7;
}
public class DayTest implements Days {
public static void main(String[] args) {
System.out.println("일요일 : " + SUNDAY);
}
}
다형성
- 다형성(polymorphism) 이란
- 객체들의 타입이 다르면 똑같은 메세지가 전달되더라도 서로 다른 동작을 하는 것
- 하나의 객체가 여러 가지 타입을 가질 수 있는 것을 의미합니다.
상향 형변환
Shape s;
s = new Shape(); // 당연히 가능
s = new Rectangle(); // Rectangle 객체도 가리킬 수 있다.
왜 가능한 것인가?
- 서브 클래스 객체는 수퍼 클래스 객체를 포함하고 있기 때문이다.
class Shape {
int x, y;
}
class Rectangle extends Shape {
int width, height;
}
public class ShapeTest {
public static void main(String[] args) {
Shape s;
Rectangle r = new Rectangle();
s = r; // 수퍼 클래스의 참조변수로 서브 클래스의 객체를 가리키는 것은 합법적
s.x = 0; // Shape 클래스의 필드와 메소드에 접근하는 것은 OK
s.y = 0;
s.width = 100; // s를 통해서는 Rectangle 클래스의 필드와 메소드에 접근할 수 없다.
s.height = 100; // 컴파일 오류가 발생함
}
}
- s 를 통해서는 x, y만을 사용할 수 있다. 그러나 r을 통해서는 모든 필드를 전부 사용할 수 있다.
내부 클래스
- 내부 클래스(inner class) : 클래스 안에 다른 클래스를 정의하는 것
public class OuterClass {
// 클래스의 필드와 메소드 정의
private class InnerClass {
// 내부 클래스의 필드와 메소드 정의
// 내부 클래스는 다른 클래스 내부에 정의된 클래스이다.
// 외부 클래스의 모든 멤버를 자유롭게 사용할 수 있다.
}
}
내부 클래스 사용 이유
- 멤버 변수를 private로 유지하면서 자유롭게 사용할 수 있다.
- 하나의 장소에서만 사용되는 클래스들을 한곳에 모을 수 있다.
- 보다 읽기 쉽고 유지보수가 쉬운 코드가 된다.
예제
public class OuterClass {
private String secret = "Secret Message";
public OuterClass() {
InnerClass obj = new InnerClass(); // 내부 클래스의 객체를 생성하고 내부 클래스 메소드 호출
obj.print();
}
private class InnerClass {
public InnerClass() {
System.out.println("내부 클래스 생성자 접근");
}
public void print() {
System.out.println(secret); // 외부클래스의 private 변수인 secret를 자유롭게 사용할 수 있다.
}
}
}
👉 내부 클래스 생성자 접근
Secret Message
무명 클래스
- 무명 클래스(anonymous class) : 클래스 몸체는 정의되지만 이름이 없는 클래스
new ClassOrInterface() { 클래스 몸체 }
// 상속받고자 하는 수퍼 클래스의 이름이나 구현하고자 하는 인터페이스의 이름을 적어준다.
예제
- 이름이 있는 클래스의 경우
class TV implements RemoteControl {
...
}
RemoteControl obj = new TV();
- 무명 클래스의 경우
RemoteControl obj = new RemoteControl() { ... };
interface RemoteControl {
void turnOn();
void turnOff();
}
public class test {
public static void main(String[] args) {
RemoteControl ac = new RemoteControl() {
public void turnOn() {
System.out.println("TV turnOn()");
}
public void turnOff() {
System.out.println("TV turnOff()");
}
};
ac.turnOn();
ac.turnOff();
}
}
👉 TV turnOn()
TV turnOff()
인터페이스와 다형성
- 추상 클래스
- 인터페이스
- 다형성
- 내부 클래스
- 무명 클래스
인터페이스는 클래스와 클래스를 연결하는 기법
추상 클래스
public abstract class Animal { // 추상 클래스 정의
// 추상 메소드 정의
public abstract void move(); // ;으로 종료됨을 유의
}
- 자바에서는 하나 이상의 추상 메소드를 포함하는 클래스를 “추상 클래스(abstract class)”라고 정의합니다.
- 이러한 추상 클래스는 객체 지향 프로그래밍에서 중요한 특징인 다형성을 가지는 메소드의 집합을 정의할 수 있도록 해줍니다.
- 추상 클래스는 동작이 정의되어 있지 않은 추상 메소드를 포함하고 있으므로, 인스턴스를 생성 할 수 없습니다.
추상 클래스 상속
public abstract class Animal { // 추상 클래스 정의
// 추상 메소드 정의
public abstract void speak(); // ;으로 종료됨을 유의
}
public class Dog extends Animal {
public void speak() {
System.out.println("멍멍!");
}
}
public class test {
public static void main(String[] args) {
Animal a = new Animal(); // 추상 클래스는 인스턴스를 생성할 수 없다.
Dog d = new Dog();
d.speak();
}
}
- 추상 클래스는 먼저 상속을 통해 자식 클래스를 만들고, 만든 자식 클래스에서 추상 클래스의 모든 추상 메소드를 오버라이딩하고 나서야 비로소 자식 클래스의 인스턴스를 생성할 수 있습니다.
- 만약 추상 클래스를 상속받은 자식 클래스가 추상 메소드를 구현하지 않으면 컴파일 오류가 발생한다.
추상 클래스 사용 이유
- 자바에서 추상 메소드를 선언하여 사용하는 목적은 추상 메소드가 포함된 클래스를 상속받는 자식 클래스가 반드시 추상 메소드를 구현하게 하도록 하기 위함입니다.
- 만약 일반 메소드로 구현한다면 사용자에 따라 해당 메소드를 구현할 수도 있고, 안 할 수도 있습니다.
- 하지만 추상 메소드가 포함된 추상 클래스를 상속받은 모든 자식 클래스는 추상 메소드를 구현해야만 인스턴스를 생성할 수 있으므로, 반드시 구현하게 됩니다.
인터페이스
- 인터페이스는 객체와 객체 사이의 상호 작용을 나타낸다.
- 자바에서 클래스는 다중 상속을 지원하지 않기 때문에 인터페이스에 추상 메소드들로만 정의를 하고 인터페이스를 implements 하고 따로 부모 클래스를 상속 할 수 있습니다.
public interface 인터페이스_이름 { // 인터페이스 안에는 추상 메소드들이 정의된다.
public void speak();
public void move();
}
public class 클래스_이름 implements 인터페이스_이름 {
void speak() { // 인터페이스를 구현하는 클래스는 추상 메소드의 몸체를 구현하여야 한다.
System.out.println("speak 추상 메소드 구현");
}
void move() {
System.out.println("move 추상 메소드 구현");
}
}
인터페이스와 타입
public interface RemoteControl {
// 추상 메소드 정의
public void turnOn(); // 전원 킴
public void turnOff(); // 전원 끔
}
public class Television implements RemoteControl {
public void turnOn(){ ... }
public void turnOff() { ... }
}
RemoteControl obj = new Television(); /*
Television 객체이지만 RemoteControl 인터페이스를
구현하기 때문에 RemoteControl 타입의 변수로 가리 킬 수 있다.
*/
obj.turnOn();
obj.turnOff();// obj를 통해 RemoteControl 인터페이스에 정의된 메소드만을 호출 할 수 있다.
인터페이스 동시 구현
public interface SerialCommunication {
void send(byte[] data); // 시리얼 포트에 데이터를 전송한다.
byte[] receive(); // 시리얼 포트에서 데이터를 받는다.
}
public class Television implements RemoteControl, SerialCommunication {
// RemoteControl와 SerialCommunication의 메소드를 동시에 구현하여야 한다.
public void turnOn() { ... }
public void turnOff() { ... }
public void send(byte[] data) { ... }
public byte[] receive() { ... }
}
- 클래스는 여러 개의 인터페이스를 다중 구현할 수 있다.
인터페이스 상속
public interface AdvancedRemoteControl extends RemoteControl {
public void volUp();
public void volDown();
}
- 인터페이스도 다른 인터페이스를 상속받을 수 있다.
인터페이스 활용
interface Days { // 상수가 정의된 인터페이스
public static final int SUNDAY = 1, MONDAY = 2, TUESDAY = 3,
WEDNESDAY = 4, THURSDAY = 5, FRIDAY = 6, SATURDAY = 7;
}
public class DayTest implements Days {
public static void main(String[] args) {
System.out.println("일요일 : " + SUNDAY);
}
}
다형성
- 다형성(polymorphism) 이란
- 객체들의 타입이 다르면 똑같은 메세지가 전달되더라도 서로 다른 동작을 하는 것
- 하나의 객체가 여러 가지 타입을 가질 수 있는 것을 의미합니다.
상향 형변환
Shape s;
s = new Shape(); // 당연히 가능
s = new Rectangle(); // Rectangle 객체도 가리킬 수 있다.
왜 가능한 것인가?
- 서브 클래스 객체는 수퍼 클래스 객체를 포함하고 있기 때문이다.
class Shape {
int x, y;
}
class Rectangle extends Shape {
int width, height;
}
public class ShapeTest {
public static void main(String[] args) {
Shape s;
Rectangle r = new Rectangle();
s = r; // 수퍼 클래스의 참조변수로 서브 클래스의 객체를 가리키는 것은 합법적
s.x = 0; // Shape 클래스의 필드와 메소드에 접근하는 것은 OK
s.y = 0;
s.width = 100; // s를 통해서는 Rectangle 클래스의 필드와 메소드에 접근할 수 없다.
s.height = 100; // 컴파일 오류가 발생함
}
}
- s 를 통해서는 x, y만을 사용할 수 있다. 그러나 r을 통해서는 모든 필드를 전부 사용할 수 있다.
내부 클래스
- 내부 클래스(inner class) : 클래스 안에 다른 클래스를 정의하는 것
public class OuterClass {
// 클래스의 필드와 메소드 정의
private class InnerClass {
// 내부 클래스의 필드와 메소드 정의
// 내부 클래스는 다른 클래스 내부에 정의된 클래스이다.
// 외부 클래스의 모든 멤버를 자유롭게 사용할 수 있다.
}
}
내부 클래스 사용 이유
- 멤버 변수를 private로 유지하면서 자유롭게 사용할 수 있다.
- 하나의 장소에서만 사용되는 클래스들을 한곳에 모을 수 있다.
- 보다 읽기 쉽고 유지보수가 쉬운 코드가 된다.
예제
public class OuterClass {
private String secret = "Secret Message";
public OuterClass() {
InnerClass obj = new InnerClass(); // 내부 클래스의 객체를 생성하고 내부 클래스 메소드 호출
obj.print();
}
private class InnerClass {
public InnerClass() {
System.out.println("내부 클래스 생성자 접근");
}
public void print() {
System.out.println(secret); // 외부클래스의 private 변수인 secret를 자유롭게 사용할 수 있다.
}
}
}
👉 내부 클래스 생성자 접근
Secret Message
무명 클래스
- 무명 클래스(anonymous class) : 클래스 몸체는 정의되지만 이름이 없는 클래스
new ClassOrInterface() { 클래스 몸체 }
// 상속받고자 하는 수퍼 클래스의 이름이나 구현하고자 하는 인터페이스의 이름을 적어준다.
예제
- 이름이 있는 클래스의 경우
class TV implements RemoteControl {
...
}
RemoteControl obj = new TV();
- 무명 클래스의 경우
RemoteControl obj = new RemoteControl() { ... };
interface RemoteControl {
void turnOn();
void turnOff();
}
public class test {
public static void main(String[] args) {
RemoteControl ac = new RemoteControl() {
public void turnOn() {
System.out.println("TV turnOn()");
}
public void turnOff() {
System.out.println("TV turnOff()");
}
};
ac.turnOn();
ac.turnOff();
}
}
👉 TV turnOn()
TV turnOff()