A a = new A( );
A : (데이터타입 == 뼈대 == 설계도)
A( )(객체 == 살)
이 개념은 객체지향 프로그래밍의 매우 중요한 개념이기 때문에 잘 이해해둘 필요가 있다.
추상메소드(Abstract Method) |
{ }(body)를 가질 수 없는 메소드. 단순한 설계도. 뼈대. |
추상클래스(Abstract Class) |
추상메소드를 하나라도 가지고 있는 클래스. 추상클래스를 상속(extends)받을 경우 추상메소드를 반드시 구현해야한다. |
인터페이스(Interface) |
추상클래스의 궁극적인 형태로 추상메소드로만 구성되어 있다. 클래스가 아니기 때문에 생성자를 가질 수 없다.(객체를 가질 수 없다.) 인터페이스를 상속(Implements)받을 경우 인터페이스 내부의 모든 추상메소드를 구현해야한다. 인터페이스의 경우는 다중상속이 가능하며, 다중구현을 위해서 사용하기도 한다. |
추상클래스는 왜 쓰는가?
외부에서 클래스에 임의로 접근하는 경우 클래스가 기능하지 못하는 경우가 발생 할 수 있기 때문에, 구현하는 클래스와 실행되는 클래스를 분리하여 캡슐화 함으로써 보안을 도모할 수 있다.
또한, 기능을 구현한 것 보다 가벼우며, 기본적으로 충족되어야 하는 기능(표준)에 대한 설계도를 지정해 놓음으로써 객체를 구현 할 때 설계도를 상속받아 설계도에 구체적인 기능만 구현하면 된다. 이 경우에 추상메소드를 하나라도 구현하지 않으면 안되기 때문에, 반드시 필요한 기능을 깜빡하고 구현하지 않는 실수를 방지할 수도 있다.
추상클래스를 객체로 만드는 방법
익명클래스(Anonymous Class)를 이용하여 생성과 동시에 구현해주면 된다.
ex) ... 아래 예제中에서...
A a = new A(){//class D extends A{ 가 생략되어 있다.
public void a( ){ }
};
...
새로운 패키지 ch08abstract 생성, L01Abstract.java 생성
package com.javalesson.ch08abstract;
abstract class A{
A(){}//생성자를 가진다. -> class가 가지는 속성을 다 가진다.
abstract public void a( );//{ }<-body 바디를 가질 수 없다.
public void b( ){ }
//추상 클래스 = class + abstract method
//class + abstract method
}//class end
class B extends A{
//error : The type B must implement the inherited abstract method A.a()
public void a( ){ }//implement(구현)=={ }바디를 작성하라는 의미
//public void a() <- 뼈(설계도)
//{ } <- 살(객체)
}
public class L01Abstract {
public static void main(String[] args) {
B b = new B( );
b.a( );
//1.이유고민, 2.해결
A a = new A(){//class D extends A{ 가 생략되어 있다.
public void a( ){ }
};//익명클래스(Anonymous Class)의 body end
//이름이 없고, 객체가 클래스를 대신하고 있다.
/* 클래스가 객체로 생성되려면
* 1.모든 메소드가 바디가 있어야 한다. (모든 추상메소드의 기능을 구현해야 한다)
* 2.추상 메소드는 객체 생성시 익명클래스로 바디를 구현해주면 된다.
* 3.생성자가 존재해야 한다.
* ->프로그래머가 생성자를 작성하지 않으면 컴파일 시 default생성자가 자동작성 된다.
*/
}//main end
}//class end
ch08abstract 패키지에 새로운 클래스 L02AnonymousClass.java 생성
package com.javalesson.ch08abstract;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
class FrameDemo extends Frame{
public FrameDemo(){
super("익명클래스 수업");
this.setBounds(300, 200, 600, 400);
this.setVisible(true);
//Listener class => event가 발생하는 지 기다리고있는 클래스
this.addWindowListener(new WindowAdapter(){ //3번방법 익명클래스로 작성한 방법
//Adapter 추상클래스는 interface로 익명클래스를 작성시 작성하지 않을 메소드들을 구현하는
//번거로움을 막기 위해 만들어 둔 보조클래스이다.
public void windowClosing(WindowEvent e) {
e.getWindow().setVisible(false);//화면을 끈다.
//이것만 쓰면 화면만 꺼지고 프로그램은 종료되지 않음.
e.getWindow().dispose();//메모리를 제거 -> 자동 종료됨 (1~2초의 delay존재)
System.exit(0);//프로그램 강제 종료
}
});
/* 창 닫기 구현 방법 3가지
* 1.WindowAdapter or WindowListener를 상속받아서 구현한 class를 넣는다.
* 2.innerClass를 이용한다.
* 3.익명클래스를 사용한다.
*/
}//생성자 end
}//class end
public class L02Anonymous {
public static void main(String[] args) {
new FrameDemo();
}//main end
}//class end
L02AnonymousClass.java에서 1번WindowAdapter or WindowListener를 상속받아서 구현한 class를 넣는 방법.
package com.javalesson.ch08abstract;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
class FrameDemo extends Frame{
public FrameDemo(){
super("익명클래스 수업");
this.setBounds(300, 200, 600, 400);
this.setVisible(true);
this.addWindowListener(new EventHanler()); //1번방법
}//생성자 end
}//class end
class EventHandler implements WindowListener{ //WindowListener(interface)를 상속받아서 구현
public void windowClosing(WindowEvent e) {
e.getWindow().setVisible(false);
e.getWindow().dispose();
System.exit(0);
}
public void windowOpened(WindowEvent e) { }
public void windowClosed(WindowEvent e) { }
public void windowIconified(WindowEvent e) { }
public void windowDeiconified(WindowEvent e) { }
public void windowActivated(WindowEvent e) { }
public void windowDeactivated(WindowEvent e) { }
//WindowListner를 구현해서 WindowEvent를 설정하는 곳
}
public class L02Anonymous {
public static void main(String[] args) {
new FrameDemo();
}//main end
}//class end
L02AnonymousClass.java에서 3번 내부클래스(InnerClass)를 이용하여 구현한 방법
package com.javalesson.ch08abstract;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
class FrameDemo extends Frame{
public FrameDemo(){
super("익명클래스 수업");
this.setBounds(300, 200, 600, 400);
this.setVisible(true);
class EventHandler implements WindowListener{ //2번 innerClass를 이용한 방법
public void windowClosing(WindowEvent e) {
e.getWindow().setVisible(false);
e.getWindow().dispose();
System.exit(0);
}
public void windowOpened(WindowEvent e) { }
public void windowClosed(WindowEvent e) { }
public void windowIconified(WindowEvent e) { }
public void windowDeiconified(WindowEvent e) { }
public void windowActivated(WindowEvent e) { }
public void windowDeactivated(WindowEvent e) { }
}
this.addWindowListener(new EventHandler());//InnerClass의 객체를 생성
}//생성자 end
}//class end
public class L02Anonymous {
public static void main(String[] args) {
new FrameDemo();
}//main end
}//class end
창 닫기 구현 방법 3가지의 장단점
방법1. WindowAdapter or WindowListener를 상속받아서 구현한 class를 넣는다.
WindowListener 인터페이스를 상속받아 구현한 클래스를 이용하는 방법을 사용하면, 다른 Frame에 대한 코드를 작성하더라도 지금 만들어 놓은 클래스를 재사용하여 간편하게 WindowListener 기능을 구현할 수 있는 장점이 있음.
방법2. innerClass를 사용한다.
외부 클래스의 필드(field)와 함수(method)를 공유할 수 있는 장점이 있음.
메소드는 상속을 받을 수 없기 때문에, 클래스를 메소드처럼 상속받아 구현할 때 용이함.
또한, 지금은 같은 java파일에 모두 구현했기 때문에 1번 방법과 거의 차이가 없지만, 1번 방법에서의 클래스를 별도의 java파일로 만든다고 하면, 내부 클래스를 사용 할 시 1개의 파일에 코드를 모두 담을 수 있는 장점이 있다. 클래스 파일의 증가는 유지보수 및 관리 포인트를 증가시킬 수 있기 때문에, 적절하게 이용하면 유지보수에 편리할 수 있다.
방법3. 익명클래스를 사용한다.
편리하지만 가독성이 떨어지며 일회성이다.
새로운 패키지 ch09interface 생성 , 새로운 클래스 L01Interface.java 생성
package com.javalesson.ch09interface;
import com.sun.org.apache.xerces.internal.util.SynchronizedSymbolTable;
interface I{
abstract void a();
void b();//b() 앞에 abstract가 생략되어 있다. ->모든 메소드는 추상메소드다.
}//I end
interface I2{
void c();
void d();
}//I2 end
interface I3{
void a();
void c();
}//I3 end
class A implements I, I2{ //Interface는 다중상속이 가능하다.
public void a(){System.out.println("I.a() 호출");}
public void b(){System.out.println("I.b() 호출");}
public void c(){System.out.println("I.c() 호출");}
public void d(){System.out.println("I.d() 호출");}
}
class B implements I,I2,I3{ //Interface는 다중상속이 가능하다.
public void a(){System.out.println("I.a() 호출");}
//I3.a()는 I.a()와 형태가 같기 때문에 둘중 하나만 구현되어도 문제가 없다.
public void b(){System.out.println("I.b() 호출");}
public void c(){System.out.println("I.c() 호출");}
public void d(){System.out.println("I.d() 호출");}
}
public class L01Interface {
public static void main(String[] args) {
//객체 new A()로 함수 a() b()를 호출하는 용도로 사용할것이다.
//이때 객체 new A()의 데이터 타입으로 사용될 인터페이스는?
이 글의 맨 위 설명을 참조하면 객체 A()를 선언할 때 사용되는 데이터타입(설계도,뼈대)은
A이기도하지만 그 부모인 인터페이스I, I2이기도 하다. 그 중 a()와 b()를 가지는 I를
데이터타입으로 쓸수있다. 아래에서 I를 I2로 바꾸면 에러가 발생하게된다.
(I2는 a()와 b()를 가지고있지 않기 때문.)
I a = new A();
a.a();
a.b();
}//main end
}//class end
'JAVA > 기본다지기' 카테고리의 다른 글
JAVA 12일차 필기 (0) | 2016.08.17 |
---|---|
JAVA 11일차 필기 (0) | 2016.08.16 |
JAVA 9일차 필기 (0) | 2016.08.11 |
JAVA 8일차 필기 (0) | 2016.08.10 |
JAVA 7일차 필기 (0) | 2016.08.09 |