728x90

이 강의는 자바의 프로젝트를 어떻게 만드는지, 또한 빌드를 어떻게 하는지에 대한 강의를 진행하지 않는다.

그러나 자바의 기본적인, 그리고 자바에 필수적인 기능들도 분명 존재하고 이 블로그엔 그 작업에 필요한 포스팅도 함께 제공하고 있다.

그 정보를 확인하고 싶다면 여기를 참조하라. 양이 조금 되고 현재진행형으로 늘어나고 있으므로 페이지내의 찾기(ctrl+f 나 cmd+f)로 찾아보도록하자.


저번의 코드를 보자 각각 Shape와 Shape를 상속받은 Circle과 Rectangle이 존재한다.


public class Shape {
private int x;
private int y;
private int width;
private int height;

public Shape(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}

public int getWidth() {
return width;
}

public void setWidth(int width) {
this.width = width;
}

public int getHeight() {
return height;
}

public void setHeight(int height) {
this.height = height;
}

public float getArea() {
return 0;
};
}
public class Circle extends Shape {

public Circle(int x, int y, int width, int height) {
super(x, y, width, height);
}

public float getArea() {
return getWidth() / 2 * getHeight() / 2 * 3.14f;
}

}
public class Rectangle extends Shape {

public Rectangle(int x, int y, int width, int height) {
super(x, y, width, height);
}

public float getArea() {
return getWidth() * getHeight();
}
}


이 코드에서 뭔가 이상한점이 없는가?

보면 알겠지만 Shape에서 getArea는 말그대로 아무것도 하는게 없는 메소드이다.

그러면 getArea를 지워도 되는가? 그렇지도 않다. 아래의 Main클래스를 보자.


public class Main {

public static void main(String[] args) {
Shape r = new Rectangle(0, 0, 10, 20);
Shape c = new Circle(0, 0, 9, 9);
System.out.println(r.getArea());
System.out.println(c.getArea());
}

}


이것도 전의 예제인데 우리는 Shape라는 클래스로 변수를 호출한다.

만약 getArea를 지운다면 Shape라는 클래스는 getArea가 없으므로 위의 코드는 실행되지 않는다.

억울하다. Circle과 Rectangle는 분명 getArea가 존재하기 때문이다.

그러면 어쩔수 없이 Shape라는 메소드는 더미데이터로 남겨둘 수 밖에 없다는 것이다.

그리고 그 getArea를 오버라이딩으로 써야하는 것이다.


이는 문법상으로 보기는 좋지 않다. 게다가 만약 새로이 Triangle이라는 클래스를 만들경우 getArea를 반드시 만들어줘야한다.

이러한 문제점을 해결하기 위해서 만든것이 abstract라는 제도이다.

한번 보자.


abstract public class Shape {
private int x;
private int y;
private int width;
private int height;

public Shape(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}

public int getWidth() {
return width;
}

public void setWidth(int width) {
this.width = width;
}

public int getHeight() {
return height;
}

public void setHeight(int height) {
this.height = height;
}

abstract public float getArea();
}


getArea를 abstract라는 키워드를 붙혀주자. 그러면 class에도 abstract키워드를 붙혀줘야한다.

그리고 getArea의 몸체를 모조리 지워주자. 이 까지는 문법적으로 강제이다.

이렇게 사용하는 abstract 메소드는 몸체는 존재하지 않는다. 이는 형식상으로만, 즉 다형성을 위해서만 존재하는 메소드인 것이다.

특정 클래스에 하나라도 abstract 메소드가 존재한다면 클래스는 자동으로 abstract 클래스가 된다.


abstract클래스는 중요한점이 인스턴스를 만들 수 없다는 점이다.

그렇다. 반드시 상속을 해줘야한다. 상속으로 사용이 강제된다.

즉 우리는 Shape인스턴스를 new를 사용해서 만들 수 없다는 것이다.

궁금하면 한번 도전해봐라. 안된다.

또한 상속받는 클래스는 abstract메소드를 반드시 오버라이딩해줘야한다. 이 역시 강제다.

이는 단점이 아니라 장점이다. 상속받는 클래스는 abstract메소드를 반드시 만들게해서 문법적 오류를 피하게 하는 것이다.

+ Recent posts