클래스를 상속하여 사용하도록 강제하는 것.
부모 클래스에는 메소드의 서명(껍데기)만 정의해놓고 해당 메소드의 실제 동작은 부모 클래스를 상속한
자식 클래스에서 구현하도록 책임을 위임하는것
abstract
abstract
키워드를 쓸 수 없다.package pr01;
abstract class A{
public abstract int b();
/*public abstract int c(){ // 본체가 있는 메소드는 abstract 키워드를 쓸 수 없다
System.out.println("Hi");
}*/
public void d(){ // 추상 메소드가 아닌, 일반 메소드도 추상 클래스에서 쓸 수 있다.
System.out.println("Hello");
}
}
//class B extends A{} //Error:(11, 1) java: pr01.B is not abstract and does not override abstract method b() in pr01.A --> 추상 클래스에 있는 메소드를 오버라이딩 해야함
class B extends A{ //
@Override
public int b() {
return 0;
}
}
public class test {
public static void main(String[] args) {
//A abs1 = new A(); //Error: pr01.A is abstract; cannot be instantiated
// 추상 클래스는 상속을 강제하므로, 상속을 받아서 사용해야 한다.
B abs2 = new B();
abs2.b();
abs2.d();
}
}
추상은 소규모 프로그램에서는 크게 사용할 필요가 없어 보인다. 하지만 규모가 큰 프로그램의 경우 다양한 상황에서 사용되는 하나의 기능이 있을 때, 그 기능의 공통적인 부분을 추상 클래스로 만들어서 추상 클래스에는 공통적인 로직만 구현하고, 하위 클래스에서는 용도에 따라 달라지는 기능을 구현할 수 있다.
아래의 코드를 보며 추상을 사용한 것과 사용하지 않은 코드의 차이를 확인해보자
추상 클래스 사용
package pr01;
abstract class Calculator{
int left, right;
public Calculator(int left, int right){
this.left=left;
this.right=right;
}
public abstract void sum();
public abstract void avg();
public void run(){
sum();avg();
}
}
class CalculatorPlus extends Calculator{
public CalculatorPlus(int left, int right) {
super(left, right);
}
@Override
public void sum() {
System.out.println("+ sum "+(this.left+this.right));
}
@Override
public void avg() {
System.out.println("+ avg "+(this.left+this.right)/2);
}
}
class CalculatorMinus extends Calculator{
public CalculatorMinus(int left, int right) {
super(left, right);
}
@Override
public void sum() {
System.out.println("- sum "+(this.left+this.right));
}
@Override
public void avg() {
System.out.println("- avg "+(this.left+this.right)/2);
}
}
public class test {
public static void main(String[] args) {
CalculatorPlus c1 = new CalculatorPlus(10,20);
c1.run();
CalculatorMinus c2 = new CalculatorMinus(10,20);
c2.run();
}
}
/*
+ sum 30
+ avg 15
- sum 30
- avg 15
*/
추상 클래스인 Calculator
는 2개의 추상 메소드
와 1개의 일반 메소드
가 있다.
Calculator
를 상속한 CalculatorPlus
와 CalculatorMinus
는 무조건 sum()
와 avg()
를 구현해야한다.
이 둘은 추상 메소드이기 때문이다. 만약, 이 중 하나라도 구현하지 않는다면 오류가 나며 실행이 되지 않는다.
추상 클래스를 사용하지 않음
package pr01;
class Calculator{
int left, right;
public Calculator(int left, int right){
this.left=left;
this.right=right;
}
public void sum(){System.out.println("부모입니다");}
public void avg(){}
public void run(){
sum();avg();
}
}
class CalculatorPlus extends Calculator{
public CalculatorPlus(int left, int right) {
super(left, right);
}
// sum() 메소드를 구현하지 않았다.
@Override
public void avg() {
System.out.println("+ avg "+(this.left+this.right)/2);
}
}
class CalculatorMinus extends Calculator{
public CalculatorMinus(int left, int right) {
super(left, right);
}
@Override
public void sum() {
System.out.println("- sum "+(this.left+this.right));
}
@Override
public void avg() {
System.out.println("- avg "+(this.left+this.right)/2);
}
}
public class test {
public static void main(String[] args) {
CalculatorPlus c1 = new CalculatorPlus(10,20);
c1.run();
CalculatorMinus c2 = new CalculatorMinus(10,20);
c2.run();
}
}
/*
부모입니다
+ avg 15
- sum 30
- avg 15
*/
public class
인 Calculator
는 3개의 일반 메소드
가 있다.
Calculator
를 상속한 CalculatorPlus
와 CalculatorMinus
는 sum()
와 avg()
를 구현하지 않아도 된다.
CalculatorPlus
를 보면 sum()
메소드를 구현하지 않았다. 하지만, 이래도 실행은 되고 실행결과는 부모 클래스에 있던 "부모입니다" 가 출력되었다.
CalculatorPlus
를 만들때 실수로sum()
메소드를 정의 못 할 수 있다. 이럴 경우 부모 클래스에서 구현된sum()
이 호출되어 원하지 않는 모습으로 동작할 수 있다.
추상을 사용한다면, 추상 메소드를 강제로 구현해야 하므로 이러한 실수를 사전에 방지할 수 있다.