생성자가 있으며, 멤버변수와 메서드도 가질 수 있다.
new 연산자로 생성자를 호출할 수는 없지만 자식 객체가 생성될 때 super()를 호출해서 추상 클래스 객체를 생성한다.(즉 추상클래스는 생성자가 있어야 한다)
추상클래스로부터 상속받는 자손 클래스는 오버라이딩을 통해 추상메서드를 구현해야한다.(만약 조상으로부터 상속받은 추상메서드 중 하나라도 구현하지 않으면 자손 클래스도 추상 메서드로 지정한다)
인스턴스(객체) 생성이 불가능하다.
abstract class Player{ //추상 클래스
abstract void play(int pos); //추상 메서드
abstract void stop();
}
class AudioPlayer extends Player{
void play(int pos) { //내용생략, 추상 메서드 구현
}
void stop() {//내용 생략, 추상메서드 구현
}
}
abstract class AbstractPlayer extends Playe{
void play(int pos){
//내용 생략, 추상 메서드 구현
//추상 메서드 중 하나를 구현하지 않았으므로 추상 클래스로 지정함
}
Player p = new Player(); //에러
AudioPlayer ap = new AudioPlayer();
그럼 예시를 보자.
abstract class Player{ //추상 클래스
abstract void play(int pos); //추상 메서드
abstract void stop(); //추상 메서드
// void stop(){} //과 같음
}
class AudioPlayer extends Player{
void play(int pos) {
System.out.println(pos+"위치부터 play");
}
void stop() {
System.out.println("중지");
}
}
public class AbstractEx {
public static void main(String[] args) {
// AudioPlayer ap = new AudioPlayer();
Player ap = new AudioPlayer(); //다형성
ap.play(100);
ap.stop();
}
}
abstract class Phone {
public String owner;
public Phone(String onwer) {
this.owner = onwer;
}
public void turnOn() {
System.out.println("turn on");
}
public void turnOff() {
System.out.println("turn off");
}
}
class SmartPhone extends Phone{
public SmartPhone(String owner) {
super(owner);
}
public void internetSearch(){
System.out.println("searching");
}
}
public class PhoneEx {
public static void main(String[] args) {
//Phone p = new Phone() //phone으로 객체 생성 불가
SmartPhone sp = new SmartPhone("홍길동"); //자식클래스로 객체 생성
sp.turnOn();
sp.internetSearch();
sp.turnOff();
}
}
예시
abstract class Player{
//iv
boolean pause;
int currentPos;
Player(){ //추상클래스도 생성자가 있어야 함
pause = false;
currentPost = 0;
}
abstract void play(int pos);
abstract void stop();
//인스턴스 메서드
void play(){
play(currentPos); //추상메서드 호출. 자손이 상속을 통해 완성할 것!
}
abstract class Animal {
public String kind;
public void breath() {
System.out.println("후,...하...");
}
public abstract void sound(); //추상 메서드, 어떤 소리인지는 모름
}
class Dog extends Animal {
public Dog() {
this.kind = "포유류";
}
public void sound() {
System.out.println("댕댕"); //추상 메서드 재정의
}
}
class Cat extends Animal {
public Cat() {
this.kind = "포유류";
}
public void sound() {
System.out.println("냥냥"); //추상 메서드 재정의
}
}
public class AnimalEx {
public static void main(String[] args) {
Dog dog = new Dog();
Cat cat = new Cat();
dog.sound();
cat.sound();
System.out.println("-------");
//변수의 자동 타입 변환
Animal animal = null;
animal = new Dog();
animal.sound();
animal = new Cat();
animal.sound();
System.out.println("--------");
//메서드의 다형성
animalSound(new Dog());
animalSound(new Cat());
}
public static void animalSound(Animal animal){
animal.sound();
}
}
예시
위의 경우 stop메서드는 선언부 구현부 모두 공통이지만
Marine, Tank는 지상 유닛이고 Dropship은 공중유닛이기 때문에 이동하는 방법이 달라서 move메서드는 구현부는 다를 것이다.(선언부는 같기 때문에 추상메서드로 정의할 수 있다.)
즉 각 클래스의 공통부분을 뽑아 Unit클래스를 만들고, 이 클래스를 상속받아서 자신의 클래스에 맞게 구현하면 된다!
abstract class Unit {
int x, y;
abstract void move(int x, int y);
void stop() {
}
}
class Marine extends Unit {
void move(int x, int y) {
System.out.println("Marine[x=" + x + ",y=" + y + "]");
}
void stimPack() {
}
}
class Tank extends Unit{
void move(int x, int y){
System.out.println("Tank[x=" + x + ",y=" + y + "]");
}
void changeMode() {
}
}
class Dropship extends Unit {
void move(int x, int y) {
System.out.println("Dropship[x=" + x + ",y=" + y + "]");
}
void load() {
}
void unload() {
}
}
public class AbstractEx{
public static void main(String[] args) {
Unit[] group = {new Marine(), new Tank(), new Dropship()};
//Unit배열 타입
//Unit[] group = new Unit[3];
// group[0] = new Marine();
//group[1] = new Tank();
//group[2] = new Dropship();
//객체 변수를 묶은 객체 배열
for (int i = 0; i < group.length; i++)
group[i].move(100, 200); //group의 타입은 Unit[]. group[]은 참조변수
}
}