상속이란 부모가 보유하는 것을 자식이 물려 받는 것을 의미한다. java에서도 같은 의미인데 이는 확정성과 직결되는 의미를 지닌다.
java는 단일 상속만을 지원하며 다중 상속은 지원하지 않는다. 다른 언어들은 다중 상속이 지원하는 경우가 있지만 java는 완전한 객체지향 개념에는 다중 상속이 필요치 않다고 보고 있다. 또한 다중 상속을 지원하게 되면 생성되는 객체의 명확성이 떨어지게 된다. 그래서 자바에서 상속은 특정 클래스가 가지는 일부 속성과 기능을 다른 새로운 클래스에 제공하기 위해 맺는 클래스간의 관계를 말한다. 또한 클래스간의 상속이란 extends 예약어를 통해 부모클래스(super class)를 자식 클래스(sub class)로 관계를 맺는 것인데 만약 상속을 받지 않았다면 java 최상위 클래스인 object를 묵시적으로 상속받는다.
클래스 상속은 객체의 재사용과 코드의 간결성을 제공한다.
class Good{
long id;
String name;
int price;
public void setName(String name){
this.name = name;
}
public void setPrice(int price){
this.price = price;
}
public long getId(){
return this.id;
}
public String getName(){
return this.name;
}
public int getPrice(){
return this.price;
}
}
다음과 같이 상품에 대한 클래스가 있을때
class Book extends Good{
String author
public Book(String name, int price, String author){
...
}
}
다음과 같이 자식 클래스인 Book이 부모 클래스의 Good을 상속받아 필요 멤버들을 사용할 수 있게 되었다. 이렇게 상속 받은 자식 클래스는 부모 클래스의 멤버와 메서드를 상속받아 사용하므로 코드의 재사용성이 증가되고 또한 부모 클래스의 정의된 코드들을 또 사용하지 않으므로 코드 또한 간결해지는 장점이 있다.
오버라이딩의 대한 개념은 이미 알고 있다. 메서드의 재정이라 불리며 super 클래스가 가지는 메서드를 sub 클래스에서 똑같이 새롭게 만들게 되면 더 이상 super 클래스에서 이름이 같은 메서드를 호출할 수 없다. 이를 오버라이딩이라 부르고 상속 관계에서는 '멤버 은폐'라고도 한다.
super는 앞서 배운 this를 떠올리면 쉽게 이해할 수 있다. this는 해당 객체를 참조하는 참조변수다. super라는 참조변수는 현재 객체의 바로 위의 부모 클래스를 참조하는 참조변수인 것이다.
super()란 그럼 무엇일까? super는 위에서 말한것 처럼 부모 클래스를 의미하고 super()는 부모 클래스의 생성자를 의미한다.
class Parent{
public Parent(int n){
System.out.println("부모 클래스 "+n);
}
}
class SubClass extends Parent{
public SubClass(){
super(3);
System.out.println("자식 클래스");
}
public static void main(String[] args){
SubClass sub = new SubClass();
}
}
위 코드를 실행하면
다음과 같은 결과를 확인할 수 있으며 super()가 부모 클래스의 생성자임을 확인할 수 있다.
final은 더 이상 확장이 불가능함을 알리는 예약어이다. 적용할 수 있는 범위는 변수, 메서드, 클래스이다.
변수에 final을 적용시키면 프로그램이 종료되어질 때까지 값을 변경하지 못하는 상수화가 된다. 그리고 static 예약어와 함께 정적화하여 특정 클래스의 객체가 여러개 생성되는 것을 방지하는 것이 보통이다. 또한 상수화가 되므로 변수의 이름은 대문자로 하는것도 관례이다.
메서드의 final은 더이상 오버라이드를 하지 못하게 하는 기능을 수행한다.
class의 final은 더이상 상속받지 못하게 하는 기능을 수행한다.
추상화란
pulbic abstract int getA();
이렇게 추상 메서드의 경우 {}를 생략하여 미완성된 메서드로 생성한다.추상 클래스의 경우 하나 이상의 추상 메서드를 가진 클래스를 의미한다.
pulbic abstract class TestClass{}
추상화라는 것은 일반적으로 사용할 수 있는 단계가 아닌 미완성적인 개념을 가진다. java에서는 추상화를 method와 class에 적용시킬 수 있는데. method에 적용시키면 추상(abstract) method, class에 적용시키면 추상(abstract) class가 된다. 이때 추상 메서드를 하나라도 가지게 되는 클래스가 바로 추상 클래스이며 추상 메서드를 하나 이상 가지게된 클래스에는 abstract를 항상 명시해야 한다.
추상 클래스의 상속 관계
추상 클래스의 상속에 대해서 알아보면 추상 클래스를 일반 클래스에서 상속했을 경우 미완성된 추상 메서드에 대해 오버라이드 해야하는 의무를 가진다. 또한 추상 클래스에서 추상 클래스로 상속이 가능한데. 이때 추상 메서드에 대해서 오버라이드를 하지 않아도 된다.
추상 클래스의 활용예를 들어 우리가 스타크래프트를 만든다는 가정을 해보자위와 같이 Unit class에서 이름과 에너지 그리고 공격했을때의 메서드를 각각 만들었다. hasAttack의 메서드를 왜 추상 메서드로 만들었냐면 스타크래프트의 각 종족마다 공격했을때 상대방 에너지를 줄이는 양이 다르기 때문이다.
class Zerg extends Unit{
public Zerg(Strng name){
this.name = name;
energy = 100;
}
public void hasAttack(){
energy -= 10;
}
}
class Protoss extends Unit{
public Protoss(Strng name){
this.name = name;
energy = 100;
}
public void hasAttack(){
energy -= 8;
}
}
다음과 같이 세 종족에 대한 정의를 했는데 공격을 했을때 hasAttack에 대한 메서드를 각각 정의할 수 있었고 추상 클래스를 상속받은 일반 클래스는 추상 메서드에 대해 정의할 의무를 가지기 때문에 내가 아닌 다른 개발자가 종족을 늘리거나 새로 변경하려고 할때 컴파일러에서 오류를 내주므로 알아보기 쉽게 코딩할 수 있다.이런 추상 클래스가 필요한 이유는 여러개의 클래스들이 공통된 점을 그대로 상속받고 각자 정의 해야하는 부분에 대해서는 개별적으로 따로 작성할 수 있도록 하는 것이 효율적이기 때문이다.
정리해보면 추상 클래스라는 것은 공통된 부분들만 구현하고, 공통으로 정의하지 않는 부분들에 abstract라는 예약어를 사용한 미완성 클래스이다. 클래스의 객체를 자체적으로 생성할 수 없으며 다른 클래스로 상속되어 미완성된 부분들을 반드시 재정의 해줘야한다.
class Terran extends Unit{
public Terran(Strng name){
this.name = name; energy = 100;
}
public void hasAttack(){
energy -= 6;
}
}
abstract class Unit{
String name;
int energy;
public abstract void hasAttack();
}
public class TestClass implements InterfaceClass{}
인터페이스는 다른 여러 객체들의 공통된 점들을 제안하고 이를 공유하여 인터페이스에 정의된 추상 메서들를 각 객체에 맞도록 재정의하여 사용하는 것이다. 그리고 인터페이스간의 상속은 다중 상속이 허용되어 여러개의 인터페이스를 구현하는 클래스에서 다형성을 함께 제공하며 객체 자체가 여러가지 타입을 가질 수 있게 해준다.
instance of
객체 instance of 클래스명
과 같이 사용할 수 있는데. 생성된 객체가 오른쪽 클래스로부터 생성되었는지에 대해 true false로 반환해준다.
instance of 예약어는 클래스의 형식을 비교하는 연산자이다.