450 likes | 893 Views
12. 인터페이스와 다형성. [INA470] Java Programming Youn-Hee Han http://link.kut.ac.kr. 1. 추상 클래스. 추상 클래스 (abstract class) 몸체가 구현되지 않은 메소드를 가지고 있는 클래스 메소드가 미완성이므로 추상 클래스로는 객체를 생성할 수 없다 . 주로 상속 계층에서 추상적인 개념을 나타내기 위한 용도로 사용. 구체적으로 어떤 동물인지 알 수 없기 때문에 구체적인 동작을 구현하기 힘들다. 1. 추상 클래스.
E N D
12. 인터페이스와 다형성 [INA470] Java Programming Youn-Hee Han http://link.kut.ac.kr
1. 추상 클래스 • 추상 클래스(abstract class) • 몸체가 구현되지 않은 메소드를 가지고 있는 클래스 • 메소드가 미완성이므로 추상클래스로는 객체를 생성할 수 없다. • 주로 상속 계층에서 추상적인 개념을 나타내기 위한 용도로 사용 구체적으로 어떤 동물인지 알 수 없기때문에 구체적인 동작을 구현하기 힘들다.
1. 추상 클래스 • 추상 클래스(abstract class) 선언 • 추상클래스 앞에는 abstract 키워드가붙는다. • 추상 클래스는 추상 메소드를 지닌다. • 추상 메소드 • abstract 키워드를 앞에 지닌다. • 몸체에 대한 선언이 없다. • 세미콜론(;)으로 정의가 끝난다. (중괄호가 쓰이지 않으므로…) • 추상 클래스를 상속받는 서브 클래스는 반드시 추상 메소드를 구체적으로 구현해야 한다. • 서브 클래스에서 추상 메소드를 다시 추상 메소드로 선언한다면 구체적인 구현까지 하지 않아도 된다. public abstract class Animal { public abstract void move(); … }
1. 추상 클래스 • 추상 클래스(abstract class) 구현 및 활용 예 • move()는모든 도형에서 동일한 행동양식을 가진다. 그래서, 슈퍼 클래스 Shape 에서구체적인 구현이 가능하다. • draw()는각 도형마다 그리는 방법이 다르기 때문에 슈퍼 클래스 Shape에서 구체적인 구현이 불가능하다. • draw()는 추상 메소드로 선언 Shape 도 추상 클래스로 선언 abstract class Shape { int x, y; public void move(int x, int y) { this.x = x; this.y = y; } public abstract void draw(); }
1. 추상 클래스 • 추상 클래스(abstract class) 구현 및 활용 예 class Rectangle extends Shape { private int width, height; public void draw() { System.out.println("Rectangle Draw"); } } class Triangle extends Shape { private int base, height; public void draw() { System.out.println("Triangle Draw"); } } class Circle extends Shape { private int radius; public void draw() { System.out.println("Circle Draw"); } } draw() 메소드는 각 서브 클래스에서구체적으로 구현을 한다.
2. 인터페이스 • 인터페이스 (Interface) • 추상 메소드 및 정적(static) 상수로만 이루어진다. • 특정 인터페이스를 따르는 클래스들에 대한 요구 조건 (Requirement) 를규정하는 역할을 한다. • 비유 예 • 고속도로 톨게이트에서 하이패스 서비스를 받으려면 하이패스 규격을 따르는 단말기를 가지고 있어야만 한다. • 임의의 객체묶음을 받아서 정렬을 하는 메소드를 구현한다면 그 묶음 안의 객체들은 다른 객체와 순서관계를 비교할 수 있는 약속된메소드가 있어야 한다. • 객체들이 서로 간에 상호 작용을 하기 위한 약속을 명시하는 도구이다.
2. 인터페이스 • 인터페이스 (Interface) 구현 및 활용법 • 인터페이스 선언 • 인터페이스 안의 모든 메소드는 추상 메소드로 간주되므로 abstract 키워드가 필요하지 않다. • 일반적인 필드는 허용하지 않고 static final 키워드가 사용되는 정적상수는 정의할 수 있다. interface MyInterface { public static final int MAX=100; public static final int MIN=1; public void method1(); public void method2(int a); }
2. 인터페이스 • 인터페이스 (Interface) 구현 및 활용법 • 인터페이스 활용 • 인터페이스에서 객체를 직접 생성할 수 없다. • 다른 클래스에 의하여 구현(implement)될 수 있다. • extends 대신에 implements 키워드 사용 • 즉, 다른 클래스에서 인터페이스에 선언된 추상 메소드의 몸체를 구현할 수 있다. • 임의의 클래스에서 인터페이스를 구현하면 반드시 인터페이스에 정의된 모든 메소드들을 구현해야 한다.
2. 인터페이스 • 인터페이스 (Interface) 활용 예 • 홈 네트워크 가전 시스템 • 홈 네트워크 업체에서는 홈네트워크 서버가 모든 가전 제품에 대하여 원격으로 제어할 수 있는 통일된 방법을 마련하고자 한다. • 따라서, 홈 네트워크 서버와 각각의 가전 제품에는 어떠한 약속된 메소드들에 대해 합의를 해야 한다. • 홈 네트워크 서버는 각 가전 제품에서그 메소드가 어떻게 구현되어 있는가는 전혀 알 필요가 없이 단지 메소드의 이름을 포함한 시그너쳐와 리턴형만 알면된다.
2. 인터페이스 • 인터페이스 (Interface) 활용 예 • 홈 네트워크 가전 시스템을 위한 인터페이스 정의 및 활용 인터페이스를 구현
2. 인터페이스 • 인터페이스 (Interface) 활용 예 • 홈 네트워크 가전 시스템 객체 생성 및 활용 • RemoteControl 인터페이스를 구현(implement)하는 클래스가 인터페이스에 선언된 메소드 구현 중 하나라도 빠뜨리면 컴파일러가 그것을 체크하여 오류를 알려줌 • 즉, 홈네트워크 서버와 같이 가전 제품 객체를 사용하는 측은 자신이 사용하는 가전 제품 클래스들이 RemoteControl 인터페이스를 구현하라고 강제화 하면 호환성의 문제가 자연스럽게 해결된다. Television t = new Television(); t.turnOn(); t.turnOff(); Refrigerator r = new Refrigerator(); r.turnOn(); r.turnOff();
2. 인터페이스 • 여러 개의 인터페이스 동시 구현 • 임의의 클래스는 하나 이상의 인터페이스를 구현할 수 있다. • 시리얼 통신을 위한 인터페이스 선언 • 가전제품 클래스에서는 RemoteControl과 SerialCommunication 인터페이스를 동시에 구현할 수 있다. public interface SerialCommunication { public void send(byte[] data); public byte[] receive(); } public class Television implements RemoteControl, SerialCommunication { … public void turnOn() { … } public void turnOff() { … } public void send(byte[] data) { … } public byte[] receive() { … } }
2. 인터페이스 • 인터페이스들 사이의 상속 • 인터페이스들도 클래스 처럼 서로 간에 상속의 관계를 가질 수 있다. • AdvancedRemoteControl 을 구현(implement)하는 클래스는 다음의 총 4 개의 메소드를 구현해야 한다. • turnOn(); • turnOff(); • volumeUp(); • volumeDown(); public interface AdvancedRemoteControl extends RemoteControl { public void volumeUp(); public void volumeDown(); }
2. 인터페이스 • 예제 #1 Apartment.java public class Apartment implements Comparable { private double area = 0; public Apartment(double a) { area = a; } public int compareTo(Object otherObject) { Apartment other = (Apartment) otherObject; if (this.area < other.area) return -1; else if (this.area > other.area) return 1; else return 0; } public static void main(String[] args) { Apartment o1 = new Apartment(105.3); Apartment o2 = new Apartment(85.0); if (o1.compareTo(o2) > 0) System.out.println("o1이 o2보다 더 크다"); else if (o1.compareTo(o2) < 0) System.out.println("o1이 o2보다 더 작다"); else System.out.println("o1과 o2가 같다"); } } package java.lang; public interface Comparable { int compareTo(Object other); } // 자신의 객체가 other 객체보다크면 1, 같으면 0, 작으면 -1을 리턴
2. 인터페이스 • 예제 #2-1 StudentTest.java import java.util.*; public class StudentTest { public static void main(String[] args) { Student[] students = new Student[3]; students[0] = new Student("홍길동", 3.39); students[1] = new Student("임꺽정", 4.21); students[2] = new Student("황진이", 2.19); Arrays.sort(students); for (Student s : students) System.out.println("이름=" + s.getName() + "평점=" + s.getGPA()); } } Array 클래스의 sort () 정적 메소드는 자신의 파라미터로서 Comparable 인터페이스를 구현하고 있는 객체의 배열만 받아들인다.
2. 인터페이스 • 예제 #2-2 StudentTest.java class Student implements Comparable { private String name; // 이름 private double gpa; // 평점 public Student(String n, double g) { name = n; gpa = g; } public int compareTo(Object obj) { Student other = (Student) obj; if (gpa < other.gpa) return -1; else if (gpa > other.gpa) return 1; else return 0; } public String getName() { return name; } public double getGPA() { return gpa; } }
3. 인터페이스의 활용 • 인터페이스와 타입 • 인터페이스는 일종의 타입 • 인터페이스 이름은 클래스 이름과 마찬가지로 참조 변수를 선언하는데에 사용가능 • 인터페이스 변수에 대입할 수 있는 것은 반드시 그 인터페이스를 구현한 클래스의 객체이어야 한다. • isEqualSize 메소드의 파라미터에 들어올 객체들은 추후 Comparable 인터페이스 변수인 co1과 co2에 할당될 것이므로 반드시 Comparable 인터페이스를 구현하는 클래스의 객체이어야 함.
3. 인터페이스의 활용 • 다중상속 (Multiple Inheritance) • 하나의 클래스가 여러 개의 슈퍼 클래스를 가지는 것 • 자바에서는 근본적으로 이러한 다중 상속이 허용되지 않는다.
2. 인터페이스 • 다중상속 (Multiple Inheritance) • 다음의 코드는 컴파일 오류가 발생한다. abstract class Monster { abstract void menace(); } abstract class Lethal { abstract void kill(); } abstract class Vampire extends Monster, Lethal { // 클래스간 다중상속 허용 안됨 abstract void drinkBlood(); } public class VeryBadVampire extends Vampire { public void menace() { … } public void kill() { … } public void drinkBlood() { … } public void destroy() { … } }
3. 인터페이스의 활용 • 다중상속 (Multiple Inheritance) • 하지만, 하나의 인터페이스가 서로 다른 두 개 이상의 인터페이스를 상속하는 것은 가능 • 즉, 인터페이스는 다중 상속이 가능하다. interface Monster { void menace(); } interface Lethal { void kill(); } interface Vampire extends Monster, Lethal { void drinkBlood(); } public class VeryBadVampire implements Vampire { public void menace() { … } public void kill() { … } public void drinkBlood() { … } public void destroy() { … } }
3. 인터페이스의 활용 • 다중상속 (Multiple Inheritance) • 또한, 임의의 클래스는 상속과 동시에 하나 또는 여러 개의 인터페이스를 구현할 수 있다.
3. 인터페이스의 활용 • 인터페이스와 추상 클래스 및 다중 상속 • 추상 클래스가 있는데 인터페이스를 별도로 제공하는 이유? • 만약인터페이스가 없어서 추상클래스로 MyComparable 을 구현한다면… • 위 클래스를 상속하면서 Rectangle이라는 클래스를 만든다고 가정하자… • 이 때, Rectangle 클래스가 이미Shape 클래스를 상속해야 한다면Rectangle 클래스는 더 이상MyComparable 클래스를 상속할 수 없다. • 클래스들 끼리는 다중상속이 허용안되기 때문에… abstract class MyComparable { public abstract int compareTo(Object other); } MyComparable Shape Rectangle
3. 인터페이스의 활용 • 인터페이스와 추상 클래스 및 다중 상속 클래스 MyComparable public class Rectangle extends Shape, MyComparable { … // 컴파일 오류 – 다중상속 허용 안됨 } Shape extends extends Rectangle public class Rectangle extends Shape implements MyComparable { … // OK! } 인터페이스 MyComparable Shape extends implements Rectangle
3. 인터페이스의 활용 • 상수 정의 • 인터페이스의 다른 용도 • 여러 클래스에서 사용할 수 있는 상수들을 정의하는 곳으로 활용 • 또는 다음과 같이 Days에정의된 상수를 서로 관계가 없는 다른 클래스에서 활용할 수 있다. 상수를 공유하려면 인터페이스를 구현하면 된다. … int today = Days.FRIDAY; int tomorrow = Days.SATURDAY;
4. 다형성(Polymorphism) • 다형성 (Polymorphism) • 동일한부모 클래스에서 상속된 서브 클래스의 객체들을 하나의 타입으로 취급하면서 서로 다른 행동을 할 수 있도록 허용하는 것 • 즉, 코드의 관점에서 서로 다른 타입의 객체들을 하나의 코드로 처리가 가능하다는 장점을 프로그래머에게 가져다 준다. • 다형성의 장점 • 코드 구조의 향상 • 코드 가독성 증가 • 프로그래밍의 편리성
4. 다형성(Polymorphism) • 상속과 객체 참조 • 서브 클래스의 객체는 슈퍼 클래스의 객체처럼 취급될 수 있다. • Keep the followings in your mind!!! • Shape s1 = new Rectangle(); // OK! • Shape s2 = new Triangle(); // OK! • Shape s3 = new Circle(); // OK! • Rectangle r = new Shape(); // Not OK! • Rectangle is a Shape (사각형은 일종의 도형이다.) • Triangle is a Shape (삼각형은일종의 도형이다.) • Circle isa Shape (원은일종의 도형이다.)
4. 다형성(Polymorphism) • 상속과 객체 참조 • 컴파일 시간 (Compile Time) • 컴파일시에 s.draw()에 오류가 발생하지 않으려면 s를 타입인 Shape 클래스가 draw()를 최소한 선언하고 있어야 한다. • 실행 시간 (Run Time) • 실행시간에 실제 메소드 호출시에는 참조 변수가 실제로 가리키는 객체의 메소드가 선택되어 호출된다.
4. 다형성(Polymorphism) • 상속과 객체 참조 • 바인딩 (Binding) • 메소드 호출을 실제 메소드 구현 몸체와 연결하는 것 • C/C++ 언어에서의 바인딩 • 컴파일 시간에 모든 바인딩이 완료 • Java 언어에서의 바인딩 동적 바인딩 (Dynamic Binding) • 바인딩이실행 시간시까지 연기되며 실제 메소드 호출시에 일어난다.
4. 다형성(Polymorphism) • 다형성 예제 (1/3) ShapeTest.java class Shape { protected int x, y; public void draw() { System.out.println("Shape Draw"); } } class Rectangle extends Shape { private int width, height; public void setWidth(int w) { width = w; } public void setHeight(int h) { height = h; } public void draw() { System.out.println("Rectangle Draw"); } }
4. 다형성(Polymorphism) • 다형성 예제 (2/3) ShapeTest.java class Triangle extends Shape { private int base, height; public void draw() { System.out.println("Triangle Draw"); } } class Circle extends Shape { private int radius; public void draw() { System.out.println("Circle Draw"); } }
4. 다형성(Polymorphism) • 다형성 예제 (3/3) ShapeTest.java public class ShapeTest { private static Shape arrayOfShapes[]; public static void main(String arg[]) { init(); drawAll(); } public static void init() { arrayOfShapes = new Shape[3]; arrayOfShapes[0] = new Rectangle(); arrayOfShapes[1] = new Triangle(); arrayOfShapes[2] = new Circle(); } public static void drawAll() { for (int i = 0; i < arrayOfShapes.length; i++) { arrayOfShapes[i].draw(); } } }
4. 다형성(Polymorphism) • 다형성 예제 고찰하기 • 만약 다음과 같은 Cylinder 클래스가 추가된다고 가정하자. • 다형성의 장점 이 때, 다음과 같은 drawAll() 메소드는 전혀 변경하지 않아도 된다.
4. 다형성(Polymorphism) • 객체의 타입을 알아내는 방법 • instanceof 연산자 • instanceof 연산자 사용예 • 객체 instanceof클래스 (or Interface)
4. 다형성(Polymorphism) • 메소드의매게 변수 타입 • 다형성을 활용하는 전형적인 예 • 메소드의 매개 변수로 수퍼 클래스 (or 인터페이스) 참조 변수를 이용한다
4. 다형성(Polymorphism) • 형변환 (Type Casting) • 상향 형변환 (Upcasting) • 서브클래스의 객체를 슈퍼 클래스의 변수에 할당하는 것 • Implicit 하게 형변환이 된다. • 변수 s를 통하여 Shape 클래스의 필드와 메소드는 당연히 접근할 수 있다. • 하향 형변환 (Downcasting) • 변수 s를 통하여 Rectangle 클래스의 필드와 메소드를 접근하고자 할 경우에는 Downcasting을 Explicit 하게 해주어야한다. • Shape s = new Rectangle(); • ((Rectangle)s).setWidth(100); • Rectangle r = (Rectangle)s; • r.setWidth(100);
5. 내부클래스 • 내부클래스 (Inner Class) • 임의의클래스 안에 정의된 클래스 • 특성 • 내부 클래스는 외부 클래스의멤버의 일종 • 내부 클래스는 외부 클래스의 어떠한 멤버도 직접 접근가능 • 외부 클래스 멤버의 private 멤버도 접근 가능
5. 내부클래스 • 내부클래스 (Inner Class) 사용 예 1 ShapeTest.java class OuterClass { private String secret = "Time is money"; InnerClass obj; public OuterClass() { obj = new InnerClass(); obj.method(); } private class InnerClass { public InnerClass() { System.out.println("내부 클래스 생성자입니다."); } public void method() { System.out.println(secret); } } } public class OuterClassTest { public static void main(String args[]) { new OuterClass(); } }
5. 내부클래스 • 내부클래스 (Inner Class) 사용 이유 • 특정 멤버 변수를 private로 유지하면서 자유롭게 사용할 수 있다. • 특정한 목적으로만 사용되는 클래스들을 그 클래스를 활용하는 외부 클래스 안으로 모을 수 있다. • 보다 읽기 쉽고 유지 보수가 쉬운 코드가 된다.
5. 내부클래스 • 내부클래스 (Inner Class) 사용 예 2-1 DataStructure.java public class DataStructure { private final static int SIZE = 15; private int[] arrayOfInts = new int[SIZE]; public DataStructure() { for (int i = 0; i < SIZE; i++) { arrayOfInts[i] = i; } } public void printEven() { InnerEvenIterator iterator = this.new InnerEvenIterator(); while (iterator.hasNext()) { System.out.println(iterator.getNext() + " "); } }
5. 내부클래스 • 내부클래스 (Inner Class) 사용 예 2-2 DataStructure.java private class InnerEvenIterator { private int next = 0; public boolean hasNext() { return (next <= SIZE - 1); } public int getNext() { int retValue = arrayOfInts[next]; next += 2; return retValue; } } public static void main(String s[]) { DataStructure ds = new DataStructure(); ds.printEven(); } }
5. 내부클래스 • 무명 클래스 (Anonymous Class) • 클래스몸체는 정의되어 있지만 이름이 없는 클래스 • 정의와 동시에 객체를 생성 • 클래스 이름이 없기 때문에 객체 생성은 단 한번만 가능하다. • 코드 양을 줄일 수 있는 장점이 있다. • 일반적으로 클래스 또는 interface 의 이름을 객체 생성 시에 사용하면서 추상 메소드들을 구현하여 사용한다. • 클래스 이름을 적으면 그 클래스를 부모로서 상속을 받아 활용하겠다는 의미 • Interface 이름을 적으면 그 인터페이스를 구현한다는 의미 부모 클래스 이름이나 인터페이스 이름
5. 내부클래스 • 무명 클래스 (Anonymous Class) 예제 1 AnonymousClassTest.java interface RemoteControl { void turnOn(); void turnOff(); } public class AnonymousClassTest { 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(); } }
5. 내부클래스 • 무명 클래스 (Anonymous Class) 예제 2 Test.java import javax.swing.*; import java.awt.event.*; class Test extends JFrame { private String preMessage = "The message is: "; public void setup() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JButton b = new JButton("Push Me!"); final String message = "Button pressed."; b.addActionListener(new ActionListener() { private String name = this.getClass().getName(); public void actionPerformed(ActionEvent e) { System.out.println(Test.this.preMessage + message + " Message from " + name); } } ); getContentPane().add(b); pack(); show(); } public static void main(String args[]) { Test f = new Test(); f.setup(); } }