추상 클래스
추상 클래스의 개념
사전적 의미로 추상(abstract)은 실체 간에 공통되는 특성을 추출한 것을 말한다.
예를 들어 새, 곤충, 물고기 등의 실체에서 공통되는 특성을 추출해 보면 동물이라는 공통점이 있다.
또 다른 예로 삼성, 현대, LG 등의 실체에서 공통되는 특성을 추출해 보면 회사라는 공통점이 있다.
이와 같이 동물이나 회사는 구체적인 실체라ㅋ기보다는 실체들의 공통되는 특성을 가지고 있는 추상적인 것이라고 볼 수 있다.
클래스에서도 추상 클래스가 존재하는 데 객체를 직접 생성할 수 있는 클래스를 실체 클래스라고 하고
추상 클래스는 공통적인 특성을 추출해서 선언한 클래스를 추상 클래스라고 한다.

추상 클래스와 실체 클래스는 상속의 관계를 가지고 있다.
추상 클래스가 부모이고 실체 클래스가 자식으로 구현되어 실체 클래스는 추상 클래스의 모든 특성을 물려받고, 추가적인 특성을 가질 수 있다.
여기서 특성이란 필드와 메소드를 말하는데 Bird, Insect, Fish class 등의 실체 클래스에서 공통되는 필드와 메소드를 따로 선언한 Animal.class 클래스를 만들 수 있는데 이것이 바로 추상 클래스라고 한다.
Animal animal = new Animal(); ( x )
추상 클래스는 실체 클래스의 공통되는 필드와 메소드를 추출해서 만들었기 때문에 객체를 생성해서 사용할 수 없다.
다시 말해서 추상 클래스는 new 연산자를 사용해서 인스턴스를 생성시키지 못한다.
추상 클래스는 단독으로 객체 생성을 할 수 없고, 부모 클래스로만 사용된다.
코드로 설명하면 추상 클래스는 extends 뒤에만 올 수 있는 클래스이다.
class Cat extends Animal { ... } ( O )
추상 클래스의 용도
첫 번째, 실체 클래스들의 공통된 필드와 메소드의 이름을 통일할 목적
실체 클래스를 설계하는 사람이 여러 사람일 경우, 실체 클래스마다 필드와 메소드가 제각기 다른 이름을 가질 수 있다.예를 들어 3명의 사람이 각각 병아리, 강아지, 코끼리라는 실체 클래스를 만들려고 할 때 공통되는 필드와 메소드가 있을 것이다.
3명의 사람이 울음소리 메소드를 만들 때 각자가 다른 이름으로 정의를 한다면 동일한 데이터와 기능임에도 불구하고 이름이 다르다 보니, 객체마다 사용방법이 달라진다.
이것을 Animal 클래스에서 sound라는 메소드 이름으로 정의를 하고 Animal 클래스를 상속함으로써 메소드 이름을 통일시킬 수 있다.
두 번째, 실체 클래스를 작성할 때 시간을 절약
공통적인 필드와 메소드는 추상 클래스인 Animal에 모두 선언해 두고, 실체 클래스마다 다른 점만 실체 클래스에 선언하게 되면 실체 클래스를 작성하는 데 시간을 절약할 수 있다.
세 번째, 실체 클래스 설계 규격을 만들고자 할 때
실체 클래스가 가져야 할 필드와 메소드를 추상 클래스에 미리 정의해 놓고, 실체 클래스는 추상 클래스를 무조건 상속받아 작성하도록 한다면 통일성이 있는 프로젝트가 만들어진다.
추상 클래스 선언
추상 클래스를 선언할 때에는 클래스 선언에 abstract 키워드를 붙여야 한다.
abstract를 붙이게 되면 new 연산자를 이용해서 객체를 만들지 못하고 상속을 통해 자식 클래스만 만들 수 있다.
public abstract class Phone{
//필드
public String owner;
//생성자
public Phone( String owner ){
this.owner = owner
}
//메소드
public void turnOn(){
System.out.println( "폰 전원을 켭니다." );
}
public void turnOff(){
System.out.println( "폰 전원을 끕니다." );
}
}
추상 클래스도 일반 클래스와 마찬가지로 필드, 생성자, 메소드 선언을 할 수 있다.
new 연산자로 직접 생성자를 호출할 수는 없지만 객체가 생성될 때 super()를 호출해서 추상 클래스 객체를 생성하므로 추상 클래스도 생성자가 반드시 있어야 한다.
super() : 부모 클래스의 기본 생성자를 호출
public class SmartPhone extends Phone{
//생성자
public SmartPhone( String owner ){
super( owner ); //부모 생성자 호출 : Phone 클래스에 생성자가 매개변수를 받고 있기 때문에 super()사용 안하면 에러!!
}
//메소드
public void internetSearch(){
System.out.println( "인터넷 검색을 합니다." );
}
}
다음으로는 Phone 클래스를 new() 연산자로 객체를 생성할 수 없기 때문에 대신 자식 클래스인 SmartPhone 클래스로 객체 생성을 해서 Phone의 메소드인 turnOn(), turnOff() 메소드를 사용할 수 있음을 보여준다.
public class PhoneExample{
public static void main( String[] args ){
Phone phone = new Phone(); //불가능
SmartPhone smartPhone = new SmartPhone( "김자바" );
smartPhone.turnOn(); //Phone 메소드
smartPhone.turnOff(); //Phone 메소드
smartPhone.internetSearch(); //SmartPhone 메소드
System.out.println( smartPhone.owner );
}
}
추상 메소드와 오버라이딩
추상 메소드는 추상 클래스에서만 선언할 수 있는데, 메소드의 선언 부만 있고 메소드 실행 내용인 중괄호 {}가 없는 메소드를 말한다.
자식 클래스는 반드시 추상 메소드를 재정의( 오버라이딩 ) 해서 실행 내용을 작성해야 하는데, 그렇지 않으면 컴파일 에러가 발생한다.
public abstract class Animal{
public abstract void sound();
}
어떤 소리를 내는지는 결정할 수 없지만 동물은 소리를 낸다는 공통적인 특징이 있으므로 sound() 메소드를 추상 메소드로 선언했다.
Animal 클래스를 상속하는 하위 클래스는 고유한 소리를 내도록 sound() 메소드를 재정의 해야 한다.

public abstract class Animal{
public String kind;
public void breathe(){
System.out.println( "숨을 쉽니다." );
}
public abstract void sound(); //추상 메소드
}
public class Dog extends Animal{
public Dog(){
this.kind = "포유류";
}
@Override
public void sound(){
System.out.println( "멍멍" ); // 재정의
}
}
public class Cat extends Animal{
public Cat(){
this.kind = "포유류";
}
@Override
public void sound(){
System.out.println( "야옹" ); // 재정의
}
}
1. Animal 클래스에서 sound()라는 추상 메소드를 선언
2. Dog 클래스에서 sound() 추상 메소드 재정의
3. Cat 클래스에서 sound() 추상 메소드 재정의
public class AnimalExample{
public static void main( String[] args ){
//첫 번째 방식
Dog dog = new Dog();
Cat cat = new Cat();
dog.sound(); //출력 : 멍멍
cat.sound(); //출력 : 야옹
//두 번째 방식 : 변수의 자동 타입 변환
Animal animal = null;
animal = new Dog(); //자동 타입 변환
animal.sound(); //출력 : 멍멍
animal = new Cat();
animal.sound(); //출력 : 야옹
//세 번째 방식 : 메소드의 다형성
animalSound( new Dog() ); //출력 : 멍멍
animalSound( new Cat() ); //출력 : 야옹
}
//정적 메소드
public static void animalSound( Animal animal ){//자동 타입 변환
animal.sound();//재정의된 메소드 호출
}
}
sound() 메소드를 호출하는 방법을 세 가지 방식으로 표현했다.
1. 가장 일반적인 방식으로 Dog와 Cat 변수로 호출
2. Animal 변수로 타입 변환해서 sound() 메소드를 호출
3. 부모 타입의 매개변수에 자식 객체를 대입해서 호출
첫 번째 방식은 Dog와 Cat 객체를 생성해서 재정의된 sound() 메소드가 호출된다.
두 번째 방식은 자식 타입은 부모 타입으로 자동 타입 변환이 될 수 있고, 메소드가 재정의되어 있을 경우 재정의된 자식 메소드가 호출되는 상속의 특징이 그대로 적용된다.
세 번째 방식은 부모 타입의 매개변수에 자식 객체를 대입해서 메소드의 다형성을 적용했다. 이것은 두 번째와 같은 원리로 자식 객체가 부모 타입으로 자동 타입 변환되어 재정의된 sound() 메소드가 호출된다.