티스토리 뷰

주의 사항!

  • 이 글은 제가 직접 공부하는 중에 작성되고 있습니다.
  • 따라서 제가 이해하는 그대로의 내용이 포함됩니다.
  • 따라서 이 글은 사실과는 다른 내용이 포함될 수 있습니다.

 

사전적 의미로 추상은 실체 간에 공통되는 특성을 추출한 것을 말합니다. 예를 들어서 새, 곤충, 물고기 등의 실체에서 공통되는 특성을 추출해보면 동물이라는 공통점이 있습니다. 또 다른 예로 삼성, 현대, LG 등의 실체에서 공통되는 특성을 추출해보면 회사라는 공통점이 있습니다. 이와 같이 동물이나 회사는 구체적인 실체라기보다는 실체들의 공통되는 특성을 가지고 있는 추상적인 것이라고 볼 수 있습니다.

 

객체를 직접 생성할 수 있는 클래스를 실체 클래스라고 한다면 이 클래스들의 공통적인 특성을 추출해서 선언한 클래스를 추상 클래스라고 합니다. 추상 클래스와 실체 클래스는 상속의 관계를 가지고 있습니다. 추상 클래스가 부모이고 실체 클래스가 자식으로 구현되어 실체 클래스는 추상 클래스의 모든 특성을 물려받고, 추가적인 특성을 가질 수 있습니다. 여기서 특성이란 필드와 메서드들을 말합니다. 예를 들어 Bird, Insect, Fish 등의 실체 클래스에서 공통되는 필드와 메서드를 따로 선언한 Animal 클래스를 만들 수 있는데 이것이 바로 추상 클래스입니다.

 

추상 클래스는 객체를 직접 생성할 수 없습니다. 즉, new 연산자를 사용해서 인스턴스를 생성하지 못합니다. 추상 클래스는 새로운 실체 클래스를 만들기 위해 부모 클래스로만 사용됩니다. 

 

추상 클래스의 용도

첫 번째, 실체 클래스들의 공통된 필드와 메서드의 이름을 통일할 목적

실체 클래스를 설계하는 사람이 여러 사람일 경우, 실체 클래스마다 필드와 메서드가 제각기 다른 이름을 가질 수 있습니다. 예를 들어 소유자의 이름을 저장하는 필드를 Telephone에서는 owner라고 하고, SmartPhone에서는 user라고 할 수 있습니다. 그리고 전원을 켜는 메서드를 Telephone에서는 turnOn()으로 설계하고, SmartPhone에서는 powerOn()이라고 할 수 있습니다. 동일한 데이터와 기능임에도 불구하고 이름이 다르다 보니, 객체마다 사용 방법이 달라집니다.

 

두 번째, 실체 클래스를 작성할 때 시간을 절약

공통적인 필드와 메서드는 추상 클래스인  Phone에 모두 선언해 두고, 실체 클래스마다 다른 점만 실체 클래스에 선언하게 되면 실체 클래스를 작성하는 데 시간을 절약할 수 있습니다.

 

개발 프로젝트에서 설계자와 코더(코드를 작성하는 사람)는 일반적으로 다른 사람입니다. 설계자는 코더에게 클래스는 어떤 구조로 작성해야 한다는 것을 알려줄 필요성이 있습니다. 코더가 작성해야 할 클래스가 다수이고, 이 클래스들이 동일한 필드와 메서드를 가져야 할 경우, 설계자는 이 내용들을 추려내여 추상 클래스로 설계 구격을 만드는 것이 좋습니다.

 

예를 들어 자동차를 설계할 때에는 일반적인 타이어 규격에 맞추어서 작성해야 합니다. 특정한 타이어만 사용할 수 있도록 자동차를 설계하지는 않습니다. 일반적인 타이어 규격에 준수하는 어떠한 타이어든 부착할 수 있도록 하기 위함입니다. 여기서 타이어 규격은 추상 클래스라고 볼 수 있고, 타이어 규격에 준수하는 한국 타이어나 금호 타이어는 추상 클래스를 상속하는 실체 타이어 클래스라고 볼 수 있습니다.

 

추상 클래스 선언

추상 클래스를 선언할 때에는 클래스 선언에 abstract 키워드를 붙여야 합니다. abstract를 붙이게 되면 new 연산자를 이용해서 객체를 만들지 못하고 상속을 통해 자식 클래스만 만들 수 있습니다.

public abstract class 클래스
{
	//필드
	//생성자
	//메서드
}

(여기서 하나 궁금한 게 있는데 어차피 객체를 만들지 못한다면 생성자는 굳이 선언하지 않아도 괜찮지 않을까요? 그리고 객체를 생성하지 못한다면 인스턴스 멤버들은 사용하지 못할 것이고, 정적 멤버들만 사용할 수 있을 텐데 추상 클래스의 필드와 메서드는 모두 static으로 정의해야 하는 걸까요?)

 

추상 클래스도 일반 클래스와 마찬가지로 필드, 생성자, 메서드 선언을 할 수 있습니다. new 연산자로 직접 생성자를 호출할 수는 없지만 자식 객체가 생성될 때 super(...)를 호출해서 추상 클래스 객체를 생성하므로 추상 클래스도 생성자가 반드시 있어야 합니다.

(즉, 추상 클래스는 객체를 아예 생성하지 못하는 클래스는 아니었습니다. 자식 클래스 인스턴스를 생성하기 위해 부모 클래스의 인스턴스는 반드시 필요하며 컴파일러에 의해 추상 클래스의 생성자도 호출되고 인스턴스를 생성할 수 있습니다. 다만, 개발자가 new 연산자를 이용해 직접 인스턴스를 생성하는 것만 막아둔 것으로 보입니다. 객체를 생성할 수 있다면 필드, 메서드도 static으로만 선언할 필요는 전혀 없겠죠)

 

다음은 Phone 클래스를 추상 클래스로 선언한 것입니다.

//Phone.java
package chapter00.exam00;

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("폰 전원을 끕니다.");
	}
}

다음은 Phone 추상 클래스를 상속해서 SmartPhone 자식 클래스를 정의한 것입니다. SmartPhone 클래스의 생성자를 보면 super(owner); 코드로 Phone 추상 클래스의 생성자를 호출하고 있습니다.

//SmartPhone.java
package chapter00.exam00;

public class SmartPhone extends Phone
{
	//생성자
	public SmartPhone(String owner)
	{
		super(owner);
	}
	
	//메서드
	public void internetSearch()
	{
		System.out.println("인터넷 검색을 합니다.");
	}
}

다음 코드는 Phone의 생성자를 호출해서 객체를 생성할 수 없음을 보여줍니다. 대신 자식 클래스인 SmartPhone으로 객체를 생성해서 Phone의 메서드인 turnOn(), turnOff() 메서드를 사용할 수 있음을 보여줍니다.

//exam00.java
package chapter00.exam00;

public class exam00 
{
	public static void main(String[] args)
	{
		//Phone phone = new Phone("KOEY");
		
		SmartPhone smartPhone = new SmartPhone("KOEY");
		
		smartPhone.turnOn();
		smartPhone.internetSearch();
		smartPhone.turnOff();
	}
}

/*
실행결과

폰 전원을 켭니다.
인터넷 검색을 합니다.
폰 전원을 끕니다.

*/

 

추상 메서드와 오버 라이딩

추상 클래스는 실체 클래스가 공통적으로 가져야 할 필드와 메서드들을 정의해 놓은 추상적인 클래스이므로 실체 클래스의 멤버(필드, 메서드)를 통일화하는 데 목적이 있습니다. 모든 실체들이 가지고 있는 메서드의 실행 내용이 동일하다면 추상 클래스에 메서드를 작성하는 것이 좋을 것입니다. 하지만 메서드의 선언만 통일화하고, 실행 내용은 실체 클래스마다 달라야 하는 경우가 있습니다.

 

예를 들어 모든 동물을 소리를 내기 때문에 Animal 추상 클래스에서 sound()라는 메서드를 정의했습니다. 그런데 각 동물들마다 울음소리가 다르기 때문에 이 메서드는 각 실체 클래스에서 직접 작성해야 합니다. 그렇다고 sound() 메서드를 실체에서 작성하도록 하면 sound() 메서드를 잊어버리고 작성하지 않을 수도 있기 때문에 울음소리를 내지 못하는 동물이 생길 수 있습니다.

 

이런 경우를 위해서 추상 클래스는 추상 메서드를 선언할 수 있습니다. 추상 메서드는 추상 클래스에만 선언할 수 있는데, 메서드의 선언부만 있고 메서드 실행 내용인 중괄호{}가 없는 메서드를 말합니다. 추상 클래스를 설계할 때, 하위 클래스가 반드시 실행 내용을 채우도록 강요하고 싶은 메서드가 있을 경우, 해당 메서드를 추상 메서드로 선언하면 됩니다. 자식 클래스는 반드시 추상 메서드를 오버 라이딩해서 실행 내용을 작성해야 하는데, 그렇지 않으면 컴파일 에러가 발생합니다. 다음은 추상 메서드를 선언하는 방법을 보여줍니다.

abstract 리턴타입 메서드명(매개변수, ...);

일반 메서드와의 차이점은 abstract 키워드가 붙어 있고 메서드 중괄호 {}가 없습니다. 다음은 Animal 클래스를 추상 클래스로 선언하고 sound() 메서드를 추상 메서드로 선언한 것입니다.

public abstract class Animal
{
	public abstract void sound();
}

 

Animal 클래스를 상속하는 하위 클래스는 고유한 소리를 내도록 sound() 메서드를 재정의해야 합니다. 예를 들어 Dog는 "멍멍", Cat은 "야옹" 소리를 내도록 Dog, Cat 클래스에서 sound() 메서드를 오버 라이딩해야 합니다. 다음은 Animal 클래스를 정의한 것입니다.

//Animal.java
package chapter00.exam00;

public abstract class Animal 
{
	public String kind;
	
	public Animal(String kind)
	{
		this.kind = kind;
	}
	
	public void breathe()
	{
		System.out.println("숨을 쉽니다.");
	}
	
	public abstract void sound();
}

다음 Dog 클래스는 추상 클래스인 Animal을 상속하고, 추상 메서드인 sound()를 오버 라이딩했습니다.

//Dog.java
package chapter00.exam00;

public class Dog extends Animal
{
	public Dog()
	{
		super("포유류");
	}
	
	@Override
	public void sound()
	{
		System.out.println("멍멍");
	}
}

다음의 Cat 클래스도 추상 클래스인 Animal을 상속하고, 추상 메서드인 sound()를 오버 라이딩했습니다.

//Cat.java
package chapter00.exam00;

public class Cat extends Animal
{
	public Cat()
	{
		super("포유류");
	}
	
	@Override
	public void sound()
	{
		System.out.println("야옹");
	}
}

이제 이들을 사용해 sound() 메서드를 실행해 보겠습니다.

//exam00.java
package chapter00.exam00;

public class exam00 
{
	public static void main(String[] args)
	{
		Dog dog = new Dog();
		Cat cat = new Cat();
		
		dog.sound();
		cat.sound();
		
		System.out.println("-----");
		
		//변수의 자동 타입 변환
		Animal animal = dog;
		animal.sound();
		
		animal = cat;
		animal.sound();
		System.out.println("-----");
		
		//메서드의 다형성
		animalSound(dog);
		animalSound(cat);
	}
	
	public static void animalSound(Animal animal)
	{
		animal.sound();
	}
}

/*
실행결과

멍멍
야옹
-----
멍멍
야옹
-----
멍멍
야옹

*/
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함