package ex_abstract;
public class Ex1 {
public static void main(String[] args) {
/*
* 추상클래스와 추상메서드
* 1. 추상메서드
* < 추상메서드 정의 기본 문법 >
* [접근제한자] abstract 리턴타입 메서드명([매개변수...]);
*
* 2. 추상클래스
* ex) 용도
* - 공통된 필드와 메서드를 통일할 목적
* - 실체 클래스 구현 시 시간 절약
* - 규격에 맞는 실체클래스 구현
*
* < 추상클래스 정의 기본 문법 >
* [public] abstract class 클래스명 {}
*
*
*/
// Shape s = new Shape(); // 에러 발생! 추상클래스는 인스턴스 생성이 불가!
Shape c = new Circle();
c.draw();
}
}
// 추상클래스와 추상메서드를 사용하여 강제성을 부여하는 방법
// 1. 추상메서드 draw()를 갖는 추상클래스 Shape 정의
abstract class Shape {
// public abstract void draw() {} // 추상메서드는 바디를 가질 수 없다!
public abstract void draw(); // 반드시 세미콜론으로 끝남
}
// 2. 추상클래스 Shape를 상속받는 서브클래스 Circle 정의
// => 추상메서드가 존재하는 경우 서브클래스에서 반드시 추상메서드를 구현(implements)해야한다!
// 구현(implements)과 오버라이딩(Overriding)은 동일한 기능이지만 메서드 바디{}를 구현하는데 목적이
// 있기 때문에 다른 용어로 표현함
class Circle extends Shape {
@Override
public void draw() { // Shape 클래스의 draw() 메서드를 상속받아 구현!(Overriding)
System.out.println("추상클래스로부터 상속받은 추상메서드 오버라이딩!");
System.out.println("원 그리기!");
}
}
class Circle2 extends Circle {}
// Shape 클래스를 상속받는 Rectangle 클래스 정의
class Rectangle extends Shape {
// 추상메서드 오버라이딩에 대한 강제성이 부여되므로
// 개발자가 실수로 빠트릴 위험이 없어짐!
public void draw() {
System.out.println("사각형 그리기!");
}
}
// ==========================================================================
// 강제성을 부여하지 않고 클래스를 정의하게 될 경우 발생하는 문제점!
// 도형 클래스 정의
//class Shape {
//
// public void draw() {
// System.out.println("도형 그리기!");
//
// }
//
//}
//
//// 원(Circle) 클래스 정의 - Shape 상속
//class Circle extends Shape {
//
// // Shape 클래스를 상속받는 Circle 클래스는 draw() 메서드를 갖게 되지만
// // draw() 메서드를 오버라이딩 하지 않고 다른 메서드를 정의하여
// // 원을 그려도 부모(Shape) 입장에서는 강제할 방법이 없다!
// public void circleDraw() {
// System.out.println("원 그리기!");
//
// }
//
//}
//
//// 사각형(Rectangle) 클래스 정의 - Shape 상속
//class Rectangle extends Shape {
//
// // Shape 클래스를 상속받는 Rectangle 클래스도 draw() 메서드를 갖게 되지만
// // 실수로 인해 draw() 메서드를 오버라이딩을 하지 않았더라도 부모(Shpae) 입장에서는
// // 강제할 방법이 없다!
//
//}
package ex_abstract;
public class Ex2 {
public static void main(String[] args) {
SubClass sc = new SubClass();
// 접근 가능한 메서드 : 3개
// 상속받은 일반메서드
sc.normalMethod();
// MiddleClass에서 구현한 추상메서드
sc.abstractMethod1();
// SubClass에서 구현한 추상메서드
sc.abstractMethod2();
// 추상클래스로 인스턴스 생성 불가
// AbstractClass ac = new AbstractClass();
// MiddleClass mc = new MiddleClass();
// 변수 타입으로 사용되어 업캐스팅 활용은 가능
MiddleClass mc = sc;
// 참조변수 mc에서 접근 가능한 메서드 : 3개
mc.normalMethod(); // 상속받은 일반메서드
mc.abstractMethod1(); // MiddleClass에서 구현한 추상메서드
mc.abstractMethod2(); // SubClass에서 구현한 추상메서드
AbstractClass ac = sc;
ac.normalMethod();
ac.abstractMethod1();
ac.abstractMethod2();
}
}
// 추상클래스
abstract class AbstractClass {
// 일반 멤버변수
String var;
// 생성자
public AbstractClass() {}
// 일반 메서드
public void normalMethod() {
System.out.println("추상클래스의 일반 메서드!");
}
// 추상 메서드
// => 현재 클래스를 반드시 추상클래스로 선언!
public abstract void abstractMethod1();
public abstract void abstractMethod2();
}
// 추상클래스 AbstractClass를 상속받는 MiddleClass 정의
// => 2개의 추상메서드 중 하나의 메서드만 오버라이딩(abstractMethod1())
abstract class MiddleClass extends AbstractClass {
// 모든 추상메서드를 오버라이딩 하지 않고, 일부만 구현할 경우
// 여전히 추상메서드를 포함하게 되므로 일반클래스로 정의할 수 없다!
// => 추상메서드를 모두 오버라이딩 하거나, 현재클래스를 추상클래스로 선언
@Override
public void abstractMethod1() {
System.out.println("MiddleClass에서 구현한 추상메서드 abstractMethod1()");
}
}
// MiddleClass를 상속받는 SubClass 정의
// => MiddleClass에서 구현되지 않은 abstractMethod2() 메서드에 대한 구현 책임이 발생함!
// => 남은 추상메서드에 대한 구현 실행!(오버라이딩 필수)
class SubClass extends MiddleClass {
@Override
public void abstractMethod2() {
System.out.println("SubClass에서 구현한 추상메서드 abstractMethod2()");
}
}