국비교육(22-23)

17일차(2)/java(17) : Abstract Class

서리/Seori 2022. 10. 28. 22:53

추상클래스 Step09_AbstractClass

 

- 추상 클래스 : 미완성 상태의 클래스. 상속받은 클래스에서 override하도록 강제할 수 있다.

<Weapon>

package test.mypac;

//미완성된 추상메소드를 멤버로 가지고있는 클래스는 abstract예약어를 붙여서 정의해야 한다.
public abstract class Weapon {
	
	//무기작동을 준비하는 메소드
	public void prepare() {
		System.out.println("무기 작동을 준비 합니다.");
	}

	//공격을 하는 메소드의 모양만 정의하고 실제 구현은 하지 않기
	//미완성된 추상 메소드를 만들때는 abstract 예약어가 필요하다.
	public abstract void attack();
	
}

 

<MainClass01>

package test.main;

import test.mypac.MyWeapon;
import test.mypac.Weapon;
/*
 * - class 예약어 앞에 abstract 를 명시해서 클래스를 정의한다.
 * - 형태만 정의되고 실체 구현은 되지 않는 메소드가 존재할 수 있다.
 * - 형태만 정의된 메소드를 만들 때는 abstract 예약어를 뭍여서 메소드를 정의한다.
 * - 생성자는 존재하지만, 단독으로 객체 생성은 불가하다.
 * - 추상클래스 Type의 id가 필요하다면 추상클래스를 상속받은 자식클래스를 정의해서 객체를 생성한다.
 * - 추상클래스를 상속받은 자식클래스는 부모의 추상메소드를 모두 오버라이드(재정의) 해야 한다.
 */
public class MainClass01 {
	public static void main(String[] args) {
		
		//추상클래스도 데이터type의 역할을 할 수 있다.
		Weapon w1=null;
		
		//Weapon w2=new Weapon(); //추상클래스 단독으로 객체생성 불가
		
		Weapon w2=new MyWeapon();
		w2.prepare();
		w2.attack();
	}
}

 

public abstract class Weapon { }

- 미완성된 추상메소드를 멤버로 가지고있는 클래스는 abstract 예약어를 붙여서 정의해야 한다.

 (미완성인 추상메소드를 가지고 있다면 반드시 클래스에다가도 표시해야 한다.)

- prepare는 완성된 메소드, attack은 미완성된 메소드

public abstract void attack();
- 메소드의 모양만 정의하고 실제 구현은 하지 않기
- 미완성된 추상 메소드를 만들때는 abstract 예약어가 필요하다.

 

 

- 보통 메소드를 만들면 클래스의 {} 안에 메소드를 준비하는 것이 일반적이다.
- new Weapon().prepare(); 형태로 사용한다.

- 메소드에 모양만 만들어서 전달만 하고, 구현하지는 않을 수도 있다.
 abstract를 붙여서 메소드를 만들고,  (){} 하지 않고 ()만 표기한다.

- 추상 클래스도 디폴트 생성자는 존재한다!

 

- w1.prepare();로 prepare 메소드는 실행할 수 있지만,

  w1.attack(); 에는 실행할 코드가 없다.

 

- 추상클래스로는 new를 할 수 없다. 객체 생성을 할 수 없기 때문에!

 → 클래스 내부의 메소드가 미완성이니 당연히 new 할 수 없음.

 

- 실제로 해당 클래스를 new 해보면 오류가 발생한다.

 

- 그러면 new할 수 없는 Weapon 클래스를 생성하는 방법은?

→ 상속을 한 다음에, 상속받은 하위 클래스를 사용해서 new한다.(객체 생성)

 

- 새 하위클래스를 만든 다음 Weapon 타입으로 객체를 생성한다.

- 단, 자식클래스 MyWeapon 안에서 부모가 구현하지 못한 추상클래스를 구현해야 한다.(override 사용)

 상속받은 하위클래스 안에서 불완전한 추상클래스를 완전하게 만들어야한다.(재정의) 선택이 아닌 강제!

 

 

<MyWeapon>

package test.mypac;

public class MyWeapon extends Weapon {

	@Override
	public void attack() {
		System.out.println("내 마음대로 공격해요!");
	}
}

- Weapon을 부모 클래스로 받는 MyWeapon class 작성

 

public class MyWeapon extends Weapon { }

- 새 하위클래스를 만들어 상속받으면 오류가 발생한다.

- 오류 발생지점에 마우스를 가져다놓으면 오류를 수정할 수 있는 방안이 자동완성된다.

 

The type MyWeapon must implement the inherited abstract method Weapon.attack()

1) 부모클래스 Weapon의 미완성 메소드를 override해서 수정하거나

2) MyWeapon도 추상클래스로 만들거나

→ 1)을 선택하면 @override 구문이 자동완성된다.

 

- 어떤 상황에서 사용하고자 하는지 모르기 때문에 기반 상태만 준비해놓은 것.
 개발자가 하고 싶어하는 대상만 정해서 작업할 수 있도록!

 추상클래스를 상속받아서 개인의 특별한 클래스를 만들 수 있다.

 

[ 추상클래스 (Abstract Class) ]
- class 예약어 앞에 abstract 를 명시해서 클래스를 정의한다.
- 형태만 정의되고 실체 구현은 되지 않는 메소드가 존재할 수 있다.
- 형태만 정의된 메소드를 만들 때는 abstract 예약어를 뭍여서 메소드를 정의한다.
- 생성자는 존재하지만, 단독으로 객체 생성은 불가하다.
- 추상클래스 Type의 id가 필요하다면 추상클래스를 상속받은 자식클래스를 정의해서 객체를 생성한다.
- 추상클래스를 상속받은 자식클래스는 부모의 추상메소드를 모두 오버라이드(재정의) 해야 한다.

 


 

<MainClass02>

package test.main;

import test.mypac.Gun;
import test.mypac.Weapon;

public class MainClass02 {
	//run 했을때 실행의 흐름이 시작되는 특별한 main 메소드
	public static void main(String[] args) {
		//동일 클래스 안에 있는 static 메소드 호출가능
		test("안녕!!");
		
		//직접 클래스를 만들고 객체 생성을 해서 아래의 useWeapon()메소드를 호출해 보세요.
		Weapon g1=new Gun();
		useWeapon(g1);
	}
		
	public static void test(String msg) {
		System.out.println(msg);
	}
	//Weapon type을 인자로 전달받아서 사용하는 static 메소드
	public static void useWeapon(Weapon w) {		
		w.prepare();
		w.attack();		
	}
}

 

- main 메소드는 특별한 메소드. run을 누르면 실행이 시작되는 도입점 역할을 한다.
- main 메소드는 static method이므로 클래스와 함께 static영역에 올라간다.

- run을 누르면 MainClass2.main(){}; 을 실행해주는 것이다.

- 위의 test 메소드는 사용할 수 없다. static 예약어가 없으므로 static영역에 함께 올라가지 못한다.

 

- static 메소드만 main과 함께 호출된다. 밑의 test도 static을 붙여주어야 한다.(함께 static영역에 올라가야만 호출 가능)
- test(); 는 앞에 mainClass02.test(){}; 가 생략된 것! 같은 클래스 안이므로.

 

- test를 전달하는 값이 있는 메소드로 수정. static 메소드를 호출하면서 매개변수를 함께 전달할 수 있다.

 


 

<Gun>

package test.mypac;

public class Gun extends Weapon {

	@Override
	public void attack() {
		System.out.println("총으로 공격해요! 빵야~");
	}
}

- Weapon클래스를 상속하는 Gun이라는 자식클래스 생성.


Weapon g1=new Gun();
useWeapon(g1);

- 이 클래스를 나중에 만들었음에도 메인메소드 안에 끼워넣으면 함께 잘 기능한다.

 

- 하지만 Gun 클래스는 타입으로 사용하지도 않고, Gun 클래스에는 메소드도 없다.

 오직 객체를 생성하기 위한 매개체에 불과하다.

 → 나중에는 클래스 없이도 객체를 생성해줄 다른방법을 사용할 것!(다음 게시물 참고)