package quiz14;
public abstract class Unit {
int x = 0;
int y = 0;
int hp;
public Unit(int hp) {
this.hp = hp;
}
abstract void location();
abstract void move(int x, int y);
abstract void stop();
}
package quiz14;
public class Marine extends Unit {
public static int attack = 6;
public static int armor = 0;
public Marine() {
super(40);
}
void location() {
System.out.println("Marine 현재 위치: ( " + x + " , " + y + " )" );
}
void move(int x, int y) {
System.out.println("Marine 좌표로 이동합니다.");
this.x = x;
this.y = y;
}
void stop(){
System.out.println("Marine Stop");
}
}
package quiz14;
public class Tank extends Unit {
static int mode;
public Tank() {
super(100);
}
void location() {
System.out.println("Tank 현재 위치: ( " + x + " , " + y + " )" );
}
void move(int x, int y) {
System.out.println("Tank 좌표로 이동합니다.");
this.x = x;
this.y = y;
}
void stop(){
System.out.println("Tank Stop");
}
void changeMode() {
if(mode == 0) {
System.out.println("시저모드로 변경합니다.");
mode = 1;
}else {
System.out.println("일반모드로 변경합니다.");
mode = 0;
}
}
}
package quiz14;
public class DropShip extends Unit {
static Unit[] unit = new Unit[8];
int i = 0;
int countT;
int countM;
public DropShip() {
super(150);
}
void location() {
System.out.println("Dropship 현재 위치: ( " + x + " , " + y + " )" );
}
void move(int x, int y) {
System.out.println("DropShip 좌표로 이동합니다.");
this.x = x;
this.y = y;
}
void stop(){
System.out.println("DropShip Stop");
}
public void pick(Unit u) {
if(i < 8) {
if(u instanceof Tank){
unit[i] = u;
i+=4;
countT++;
System.out.println("탱크 " + countT+" 대 탑승완료");
System.out.println("마린 " + countM+" 명 탑승완료");
System.out.println();
}else if(u instanceof Marine) {
unit[i] = u;
i++;
countM++;
System.out.println("탱크 " + countT+" 대 탑승완료");
System.out.println("마린 " + countM+" 명 탑승완료");
System.out.println();
}
}else {
System.err.println("드랍쉽 공간 없음");
System.out.println();
}
}
}
package quiz14;
public class MainClass {
public static void main(String[] args) {
Marine m3 = new Marine();
m3.move(10, 20);
m3.location();
m3.stop();
System.out.println( Marine.armor );
System.out.println( Marine.attack );
Marine m = new Marine();
Tank t = new Tank();
DropShip d = new DropShip();
m.location();
t.location();
t.changeMode();
d.location();
t.changeMode();
m.move(4, 2);
t.move(4, 2);
d.move(4, 2);
m.location();
t.location();
d.location();
m.stop();
t.stop();
d.stop();
d.pick(t);
d.pick(m);
d.pick(m);
d.pick(m);
d.pick(m);
d.pick(m);
DropShip d1 = new DropShip();
d1.pick(m);
d1.pick(m);
d1.pick(m);
d1.pick(m);
d1.pick(m);
d1.pick(m);
d1.pick(m);
d1.pick(m);
d1.pick(m);
}
}
이렇게 추상 클래스, 추상 메서드를 사용하여 스타의 마린, 탱크, 드랍쉽의 위치를 지정하게 하였다.
추가적으로 실제 스타크래프트의 드랍쉽이 탱크랑 마린을 담을 수 있듯이 드랍쉽 클래스 안에 배열을 생성하여 탱크와 마린의 객체를 담을 수 있도록 해주었다 크기가 8이기 때문에 탱크는 4로 마린은 1인데, 8을 초과하면 err을 사용하여 더이상 탑승이 불가하다는 것을 표현해 주었다.
인터페이스는 쉽게 생각해서 메서드들을 정리하는 공간이라고 보면 좋을 거 같다. 실제 변수들이 자동으로 상수화가 되며, 메서드 또한 추상 메서드로 자동 생성이 된다.
처음에는 클래스로 상속해주면 되지 않을까 생각했지만 실제 인터페이스를 통해서 원하는 자식 클래스에만 원하는 기능을 추가해 줄 수 있기 때문에 효율적인 것 같다. 이런식으로 동물이 있을 경우 강아지에만 포유류라는 기능을 추가해 주고 싶을 때 인터페이스를 상속해주면 좋다.
실제 사용 법은 Class 클래스명 extends 부모 클래스명 implements 인터페이스이다. 인터페이스는 추상메서드를 사용하기 때문에 무조건 오버라이딩을 해줘야한다. 아닌 경우는 뒤에서 설명할테지만 static 혹은 default를 사용하여 메서드를 생성하는 경우이다. 그냥 저런 키워드 없이 사용한다면 무조건 추상 메서드화가 되기 때문에 오버라이딩 필수이다.
클래스의 경우에는 다중상속이 불가능하지만 인터페이스는 다중상속이 가능하여서 여러개의 기능을 원하는 자식 클래스에 추가해줄 수 있다. 사용법은 class Dog extends Animal implements 포유류 , IPet {} 이렇게 사용할 수 있다.
package day17.inter.basic;
public interface Inter1 {
//인터페이스는 객체생성이 불가합니다
//상수, 추상메서드 +@ (default 메서드, static 메서드)
//다만 주로 상수, 추상메서드 사용
double PI = 3.14; //인터페이스에 변수를 선언 -> public static 상수로 선언됨
void method1(); //인터페이스에 메소드를 선언 -> public 추상메서드가 됨
}
package day17.inter.basic;
public interface Inter2 {
void method2();
}
package day17.inter.basic;
//인터페이스는 implements키워드로 상속을 받습니다
public class Basic /*extends Object*/implements Inter1,Inter2 {
@Override
public void method1() {
System.out.println("오버라이딩 된 inter1메서드");
}
@Override
public void method2() {
System.out.println("오버라이딩 된 inter2메서드");
}
}
실제 인터페이스에서는 void method() 그리고 int value; 이렇게만 선언해줘도 자동으로 추상 메서드화, 상수화가 된다.
위의 Basic클래스를 보면 다중상속을 받은 것을 볼 수 있으며, 상속받은 인터페이스들의 메서드를 꼭 오버라이딩을 해줘야 한다.
package day17.inter.basic2;
public interface BasicInter {
//클래스가 가져야할 메서드를 interface에 정의
void insert(int a);
void info();
String getInfo();
int delete(int a);
}
package day17.inter.basic2;
public class Basic implements BasicInter{
// 클래스가 가져야할 메서드를 interface에 정의
@Override
public void insert(int a) {
System.out.println("insert....");
}
@Override
public void info() {
System.out.println("info....");
}
@Override
public String getInfo() {
System.out.println("getInfo....");
return "getInfo";
}
@Override
public int delete(int a) {
System.out.println("delete....");
return 0;
}
}
이 처럼 인터페이스를 상속 받는 클래스에서는 오버라이딩을 꼭 해줘야 한다.
package day17.inter.basic2;
public class MainClass {
public static void main(String[] args) {
BasicInter b = new Basic();
b.info();
b.insert(0);
b.getInfo();
b.delete(0);
}
}
이런식으로 인터페이스 타입 그리고 그 인터페이스를 상속 받는 클래스 객체를 형성해주면 기능들을 사용할 수 있게 된다.
위처럼 클래스 및 인터페이스를 만들어 주려고한다.
package day17.inter.basic3;
public abstract class Animal {
public abstract void eat();
}
추상 클래스인 Animal 기능에는 eat()이라는 추상 메서드를 만들어 준다.
package day17.inter.basic3;
public class Cat extends Animal implements IPet {
@Override
public void eat() {
System.out.println("고양이는 생선을 먹는다");
}
}
package day17.inter.basic3;
public class Dog extends Animal implements IPet {
@Override
public void eat() {
System.out.println("강아지는 사료를 먹는다");
}
}
package day17.inter.basic3;
public class Tiger extends Animal {
@Override
public void eat() {
System.out.println("호랑이는 고기를 먹는다.");
}
}
이런 식으로 3개의 클래스 dog, cat, tiger는 animal을 상속 받는다. 추상 클래스의 메서드를 오버라이딩 해준다.
package day17.inter.basic3;
public abstract class Fish {
public abstract void swim();
}
Fish 추상 클래스 에는 swim이라는 기능을 추가해준다.
package day17.inter.basic3;
public class GoldFish extends Fish implements IPet {
@Override
public void swim() {
System.out.println("금붕어는 강에서 논다");
}
}
package day17.inter.basic3;
public class Shark extends Fish {
@Override
public void swim() {
System.out.println("상어는 바다에서 논다");
}
}
이렇게 goldfish와 shark는 fish를 상속 받는 클래스 이며, 추상 클래스를 상속 받기 때문에 오버라이딩을 해준다.
package day17.inter.basic3;
public class MainClass {
public static void main(String[] args) {
//Dog d = new Dog(); // eat, play
//Animal d = new Dog(); // eat
//IPet d = new Dog(); // play
Animal baduk = new Dog();
Animal nabi = new Cat();
Animal hodol = new Tiger();
//1. Animal 배열에 저장
Animal[] arr = {baduk, nabi, hodol};
for(Animal a : arr) {
a.eat();
}
}
}
이렇게 animal 클래스 타입의 dog, cat, tiger 객체를 생성해서 기능을 출력해주면 오버라이딩이 된 메서드가 호출이된다.
실제 위의 표를 보면 강아지, 고양이, 금붕어는 IPet의 인터페이스의 상속또한 받아주기 때문에 그 과정도 추가해준다.
package day17.inter.basic3;
public interface IPet {
void play();
}
IPet에는 play라는 기능이 들어가 있다.
package day17.inter.basic3;
public class Cat extends Animal implements IPet {
@Override
public void eat() {
System.out.println("고양이는 생선을 먹는다");
}
@Override
public void play() {
System.out.println("고양이는 방에서 논다");
}
}
package day17.inter.basic3;
public class Dog extends Animal implements IPet {
@Override
public void eat() {
System.out.println("강아지는 사료를 먹는다");
}
@Override
public void play() {
System.out.println("강아지는 방에서 논다");
}
}
package day17.inter.basic3;
public class GoldFish extends Fish implements IPet {
@Override
public void swim() {
System.out.println("금붕어는 강에서 논다");
}
@Override
public void play() {
System.out.println("금붕어는 어항에서 논다");
}
}
이렇게 강아지, 고양이, 금붕어에 인터페이스의 기능인 play를 오버라이딩을 해준다. 인터페이스를 상속 받을 때는 extends가 아닌 implements를 사용하며 ,를 통해서 여러개 상속 받을 수 있다.
package day17.inter.basic3;
public class MainClass {
public static void main(String[] args) {
//Dog d = new Dog(); // eat, play
//Animal d = new Dog(); // eat
//IPet d = new Dog(); // play
Animal baduk = new Dog();
Animal nabi = new Cat();
Animal hodol = new Tiger();
//1. Animal 배열에 저장
Animal[] arr = {baduk, nabi, hodol};
for(Animal a : arr) {
a.eat();
}
System.out.println();
//2. 바둑이는 Animal이지만 생성된 클래스가
//인터페이스 상속을 받고 있다면 상호형변환이 된다. IPet으로 캐스팅 할 수 있다.
IPet i1 = (IPet) arr[0];
IPet i2 = (IPet) nabi;
IPet i3 = new GoldFish();
IPet[] arr2 = {i1, i2, i3};
for(IPet i : arr2) {
i.play();
}
System.out.println();
System.out.println("다음은 새로운 클래스에서 IPet을 받아 출력하는 메서드");
System.out.println();
PetHouse.info(i3);
PetHouse.infoAll(arr2);
}
}
이런식으로 강아지, 고양이, 금붕어는 IPet또한 상속 받기 때문에 Animal에서 IPet으로 형변환이 가능하다.
추가적으로 PetHouse라는 클래스를 만들어서 배열로 묶은 객체들을 한번에 실행하거나 하나를 실행 할 수 있는 메서드를 만들어 줬다.
package day17.inter.basic3;
public class PetHouse {
//1. IPet타입을 받아서 기능을 출력하는 메서드
public static void info(IPet i) {
i.play();
}
//2. IPet[] 타입을 받아서 기능을 전부 출력하는 메서드
public static void infoAll(IPet[] i) {
for(IPet i1 : i) {
i1.play();
}
}
}
package day17.inger.default_;
public interface MyInter {
//상수, 추상, default, static
double Pi = 3.14;
void some1();//이것만 오버라이딩 필요
//default메서드 - 인터페이스에도 몸체를 가지는 메서드 선언이 가능
//static 메서드 둘다 오버라이딩 필요 없다
default void some2() {
System.out.println("default메서드 실행");
}
static void some3() { //클래스 이름으로 접근 가능
System.out.println("static메서드 실행");
}
}
이런식으로 default 와 static을 사용하여 추상 메서드가 아닌 메서드도 생성할 수 있다. 이런경우에는 상속 받는 클래스에서 오버라이딩을 해줄 필요가 없다.
package day17.inger.default_;
public class MyClass implements MyInter {
@Override
public void some1() {
System.out.println("some1 오버라이딩");
}
}
some1()의 메서드만 오버라이딩을 해주면 된다.
package day17.inger.default_;
import java.util.List;
import java.util.stream.IntStream;
public class MainClass {
public static void main(String[] args) {
MyInter i = new MyClass();
i.some1(); //오버라이딩된 메서드
i.some2(); //default 메서드
MyInter.some3(); // static 메서드
System.out.println(MyInter.Pi);//상수
}
}
객체를 생성하여 오버라이딩이 된 메서드 호출, 그리고 default 메서드 호출, 마지막으로 static 같은 경우에는 직접 접근이 가능하기 때문에 여기서는 저렇게 인터페이스 명. 메서드로 호출해줄 수 있다.
package quiz15;
public interface SongList {
public void insertList(String song);
public void playList();
public int playLength();
}
package quiz15;
import java.util.Arrays;
public class MelonMusic implements SongList {
/*
* SongList인터페이스를 상속받아서 기능을 구현합니다.
* insertList() 는 list배열에 순서대로 저장
* playList() list의 음악을 랜덤하게 출력
* playLength() 는 저장된 음악의 개수를 반환
*/
private String[] list = new String[100];
private int count = 0;
@Override
public void insertList(String song) {
// TODO Auto-generated method stub
list[count] = song;
count++;
}
@Override
public void playList() {
for(int i = 0; i < count ; i++ ) {
int a = (int)(Math.random()* count);
System.out.println(list[a]);
}
// TODO Auto-generated method stub
}
@Override
public int playLength() {
return count;
}
}
인터페이스인 SongList를 상속 받는 클래스 MelonMusic을 만들어 준다. 이렇게 인터페이스의 상속을 받는 경우 인터페이스에 생성된 메서드가 추상메서드기 때문에 오버라이딩을 해줘야한다.
package quiz15;
import java.util.Scanner;
public class MainClass {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//바깥에 객체생성
SongList m = new MelonMusic();
while(true) {
System.out.println("메뉴[1.추가, 2.재생, 3.개수, 4.종료]");
System.out.print(">");
int num = scan.nextInt();
if(num == 1) {
System.out.print("노래>");
String name = scan.next();
m.insertList( name );
} else if(num == 2) {
if(m.playLength() == 0) {
System.out.println("재생할 곡이 없습니다");
return;
}
m.playList();
} else if(num == 3) {
int len = m.playLength();
System.out.println("재생곡 개수: " + len);
} else if(num == 4) {
System.out.println("종료");
return;
}
}
}
}
곡이 안담겼는데 재생을 할 경우 없다는 표시와 함께 종료
곡을 추가하고 재생하고 곡의 개수가 몇개인지 체크 후 종료
'JAVA' 카테고리의 다른 글
19일차 22.10.18 (0) | 2022.10.18 |
---|---|
18일차 22.10.17 (0) | 2022.10.17 |
16일차 22.10.13 (0) | 2022.10.13 |
15일차 22.10.12 (0) | 2022.10.12 |
14일차 22.10.11 (0) | 2022.10.11 |
댓글