본문 바로가기

Learning/JAVA

객체지향의 다형성, toString()으로 오버라이딩, instanceof, 추상클래스-abstract, interface-implements, ArrayList

  • 자바의 다형성-상위 클래스를 통해 하위 클래스의 값을 다양한 형태로 돌려줌. 각 도형의 넓이의 합을 구할때. (Shape, ShapeMain, ShapeManager, Circle, Square)
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
package day07;
import java.util.Scanner;
public class ShapeMain {
     static Scanner sc=new Scanner(System.in);
     
     public static void showMenu() {
          System.out.println("선택하세요...");
          System.out.println("1.원 2.사각형 3.보기 4.종료");
          System.out.print("선택:");
     }
     
     public static void main(String[] args) {
              ShapeManager sm=new ShapeManager();
              
              while(true) {
              ShapeMain.showMenu();
              //클래스 이름에 static 불였으니까 ShapeMain으로 부를 수 있음.
              int num=sc.nextInt();
              switch(num) {
              case 1 : //원입력
              case 2 : sm.inputData(num); break//사각형입력
              case 3 : sm.viewData(); break//전체보기
              case 4 : System.out.println("종료");
                         System.exit(0);
              default : System.out.println("입력오류");
              }
          }
     }
}

 

 

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
32
33
34
35
36
37
38
39
package day07;
public class ShapeManager {
     //입력받은 좌표, 반지름, 너비, 높이 등을 저장하기 위해 배열 선언
     //부모형으로 선언을 해야 Circle, Square 모두 적용가능
     Shape[]arr=new Shape[50];
     int cnt;
     
     public void inputData(int num) { //원->x,y,r 사각형->x,y,w,h
          System.out.println("도형입력....");
          System.out.print("x 좌표>>");
          int x=ShapeMain.sc.nextInt();
          System.out.print("y 좌표>>");
          int y=ShapeMain.sc.nextInt();
          
          if(num==1) { //원
              System.out.print("반지름>>");
              int r=ShapeMain.sc.nextInt();
              arr[cnt++]=new Circle(x,y,r);
          }
          else if(num==2) { //사각형
              System.out.print("너비>>");
              int w=ShapeMain.sc.nextInt();
              System.out.print("높이>>");
              int h=ShapeMain.sc.nextInt();
              arr[cnt++]=new Square(x,y,w,h);
          }
     }
     
     public void viewData() {
          double sum=0;
          for(Shape s: arr) {
              if(s==nullbreak;
              sum+=s.getArea();
              s.print();
          }
          System.out.println("전체 넓이: "+sum);
     }
     
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package day07;
public class Shape {
     private int x;
     private int y;
     
     public Shape(int x, int y) {
          this.x=x;
          this.y=y;
     }
     
     public void print() {
          System.out.println("좌표(x,y)=("+x+","+y+")");
     }
     
     public double getArea() {
          return 0.0;
     }
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package day07;
public class Circle extends Shape {
     private int r;
     final double PI=3.14;
     
     public Circle(int x, int y, int r) {
          super(x,y);
          this.r=r;
     }
     //오버라이딩
     public void print() {
          super.print();
          System.out.println("반지름: "+r);
     }
     //오버라이딩
     public double getArea() {
          return r*r*PI;
     }
     
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package day07;
public class Square extends Shape {
     private int w,h;
     
     public Square(int x, int y, int w, int h) {
          super(x,y);
          this.w=w;
          this.h=h;
     }
     //오버라이딩
     public void print() {
          super.print();
          System.out.println("너비: "+w);
          System.out.println("높이: "+h);
     }
     //오버라이딩
     public double getArea() { //리턴될 유형이 같아야 하므로 double로 맞춰줌.
          return w*h;
          //부모 getArea()에서 0.0을 리턴하긴 했지만 오버라이딩을 통해 w*h값을 돌려줌.
     }
     
}

 


  • 자바 Api중 toString은 Object이 가지는 메소드. toString()을 통해 오버라이딩하기. (ProductMain, Product, Buyer, TV, Computer, Audio)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package inheritance;
public class ProductMain {
     
     public static void main(String[] args) {
          Buyer b=new Buyer(1000); //바이어가 가진 돈
          TV tv=new TV(50); //tv의 가격
          Computer com=new Computer(100); //computer의 가격
          Audio audio=new Audio(70); //audio의 가격
          
          b.buy(tv); //tv와 com을 아우를 수 있는 자료형은 Product
          b.buy(com);
          b.showInfo();
     }
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
package inheritance;
public class TV extends Product {
     
     public TV(int price) {
          super(price);
     }
     //toString은 Object이 가지는 메소드이기 때문에 오버라이딩 할 수 있다.
     //오버라이딩을 함으로써 주소가 아니라 TV, Computer등 문자가 나오도록 함
     @Override
     public String toString() {
          return "TV";
     }    
}

 

 

1
2
3
4
5
6
7
8
9
10
11
package inheritance;
public class Computer extends Product {
     
     public Computer(int price) {
          super(price);
     }
     
     public String toString() {
          return "Computer";
     }
}

 

1
2
3
4
5
6
7
8
9
10
11
package inheritance;
public class Audio extends Product {
     
     public Audio(int price) {
          super(price);
     }
     
     public String toString() {
          return "Audio";
     }
}

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package inheritance;
public class Product {
     protected int price;
     protected int bonusPoint;
     
     /* 생성자를 만들면 항상 부모의 생성자로 먼저 간다.
      * 부모의 생성자 Product에 인자가 있음.
      * 자식 클래스에 인자가 없는 생성자들이 있었음.
      * (Buyer클래스로 인해 하위 클래스가 인자가 있는 생성자로 바꾸면서 삭제)
      * 그러면 똑같이 인자가 없는 Product를 만들어줘야함.
     public Product() {
          
     }
     */
     public Product(int price) {
          this.price=price;
          bonusPoint=price/10;
     }    
}

 

 

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
package inheritance;
public class Buyer {
     private int money;
     private int point;
     Product[] arr=new Product[10];
     int cnt;
     
     public Buyer(int money) { //생성자는 클래스 이름과 똑같이 만듦.
          this.money=money;
     }
     //구매하기
     public void buy(Product p) {
          arr[cnt++]=p;
          money-=p.price; //바이어가 가진 돈은 물건의 가격만큼 깎인다.
          point+=p.bonusPoint;
     }
     //구매내역
     public void showInfo() {
          for(int i=0;i<cnt;i++) {
              System.out.println("구매내역: "+arr[i]);
              //그냥 배열만 출력하면 주소값이 나옴.
          }
          System.out.println("잔액: "+money);
          System.out.println("포인트: "+point);
          
     }    
}

  • 객체 따로 선언하지 않고 클래스 형태를 매개변수로 적기, instanceof (AnimalTest1)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package inheritance;
 
class Animal{
    public void move() {
        System.out.println("동물이 움직입니다.");
    }
}
 
class Human extends Animal {
    public void move() {
        System.out.println("사람이 두 발로 걷습니다.");
    }
}
 
class Tiger extends Animal {
    public void move() {
        System.out.println("호랑이가 네 발로 뜁니다.");
    }
}
 
class Eagle extends Animal {
    public void move() {
        System.out.println("독수리가 하늘을 납니다.");
    }
}
 
public class AnimalTest1 {
    public static void main(String[] args) {
        AnimalTest1 aTest=new AnimalTest1();
        aTest.moveAnimal(new Human()); 
        aTest.moveAnimal(new Tiger()); //한번만 쓰고 더이상 안만들 것은 객체를 따로 선언하지 않고 new Tiger()이런 식으로 매개변수로 적어줌
        aTest.moveAnimal(new Eagle());
        
        Human h=new Human();
        if(h instanceof Animal) { //instanceof는 이 객체가 어느 소속인지 물어보는 키워드. Human보다 Animal이 상위 개념이므로 맞다라고 출력. 
            System.out.println("맞다");
        }else {
            System.out.println("틀리다");
        }
        
        Animal a=new Animal();
        if(a instanceof Human) { //a는 Animal. Human보다 큰 개념이므로 틀리다11가 출력.
            System.out.println("맞다11");
        }else {
            System.out.println("틀리다11");
        }
        
    }
    
    public void moveAnimal(Animal animal) { //Animal에서 상속받은 클래스가 매개변수로 넘어오면 모두 Animal형으로 변환됨. animal에 휴먼, 타이거, 이글 등..올수 있음.
        animal.move();
    }
}
 

 


  • 추상클래스-abstract (AbsShape, AbsShapeMain, AbsCircle, AbsSquare)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package day07;
public class AbsShapeMain {
     public static void main(String[] args) {
          AbsCircle ac=new AbsCircle();
          ac.draw();
          ac.move();
          
          AbsSquare as=new AbsSquare();
          as.draw();
          as.move();
          as.print();
          
          //AbsShape ah=new AbsShape(); //추상이라서 안된다. 
          //추상클래스엔 객체를 생성할 수 없다. 하위클래스에서 반드시 추상클래스의 추상 메소드 구현.
          AbsShape ah=new AbsCircle(); //이런식으로 접근한다.
     }
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package day07;
public abstract class AbsShape {
     /*
      *그리다. 원을 그리면 원을 그리다. 사각형을 그리면 사각형을 그리다.
      *자식 클래스들에 따라 구현되도록.
      *그러려면 추상 메소드를 만들어놓고 클래스도 추상클래스로 변하게.
      */
     public abstract void draw();
     //이동하다
     public abstract void move();
     
     public void print() {
          System.out.println("도형그리다");
     }
     
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
package day07;
public class AbsCircle extends AbsShape {
     @Override
     public void draw() {
          // TODO Auto-generated method stub
          System.out.println("원 그리기");
     }
     @Override
     public void move() {
          // TODO Auto-generated method stub
          System.out.println("원 이동하기");
     }
}

 

 

1
2
3
4
5
6
7
8
9
package day07;
public class AbsSquare extends AbsShape {
     public void draw() { //반드시 선언해줘야함. 부모 클래스인 AbsShape은 추상클래스이기 때문에 그 안에 있는 추상메소드를 구현하도록 해야함.
          System.out.println("사각형 그리기");
     }
     public void move() {
          System.out.println("사각형 이동하기");
     }
}

 


  • 추상클래스 (Player, PlayerLevel, BeginnerLevel, AdvancedLevel, SuperLevel, MainBoard)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
package inheritance;
public class Player {
     private PlayerLevel level; //PlayerLevel이 가지는 level변수 선언
     
     public Player() {
          level=new BeginnerLevel();
          level.showLevelMessage();
     }
     
     public PlayerLevel getLevel() {
          return level;
     }
     
     public void upgradeLevel(PlayerLevel level) { //매개변수 자료형은 모든 레벨로 변환 가능한 PlayerLevel
          this.level=level; //현재 자신의 level을 매개변수로 받은 level로 변경하고 레벨 메시지 출력
          level.showLevelMessage();
     }
     
     public void play(int count) { //PlayerLevel의 템플릿 메서드 go()호출
          level.go(count);
     }
     
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package inheritance;
public abstract class PlayerLevel {
     public abstract void run();
     public abstract void jump();
     public abstract void turn();
     public abstract void showLevelMessage();
     
     final public void go(int count) {
          run();
          for(int i=0;i<count;i++) {
              jump();
          }
          turn();
     }
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package inheritance;
public class BeginnerLevel extends PlayerLevel {
     @Override
     public void run() {
          System.out.println("천천히 달립니다.");
     }
     @Override
     public void jump() {
          System.out.println("Jump할 줄 모르지롱.");
     }
     @Override
     public void turn() {
          System.out.println("Turn할 줄 모르지롱.");
     }
     @Override
     public void showLevelMessage() {
          System.out.println("******초보자 레벨입니다.******");
     }
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package inheritance;
public class AdvancedLevel extends PlayerLevel{
     @Override
     public void run() {
          System.out.println("빨리 달립니다.");
     }
     @Override
     public void jump() {
          System.out.println("높이 Jump합니다.");
     }
     @Override
     public void turn() {
          System.out.println("Turn할 줄 모르지롱.");
     }
     @Override
     public void showLevelMessage() {
          System.out.println("******중급자 레벨입니다.******");
     }
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package inheritance;
public class SuperLevel extends PlayerLevel{
     @Override
     public void run() {
          System.out.println("엄청 빨리 달립니다.");
     }
     @Override
     public void jump() {
          System.out.println("아주 높이 Jump합니다.");
     }
     @Override
     public void turn() {
          System.out.println("한 바퀴 돕니다.");
     }
     @Override
     public void showLevelMessage() {
          System.out.println("******고급자 레벨입니다.******");
     }
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package inheritance;
public class MainBoard {
     public static void main(String[] args) {
          Player player=new Player(); //처음 생성하면 BeginnerLevel
          player.play(1);
          
          AdvancedLevel aLevel=new AdvancedLevel();
          player.upgradeLevel(aLevel);
          player.play(2);
          
          SuperLevel sLevel=new SuperLevel();
          player.upgradeLevel(sLevel);
          player.play(3);
     }
}

 


  • 전부다 추상인걸로 이뤄진 것을 interface라 하고 extends가 아닌 implements를 사용. 추상과 마찬가지로 new라는 키워드로 생성불가능하지만 추상과 달리 여러개를 상속받을 수 있다. 자바의 불가능한 다중 상속을 가능하게 만들기 위해 extends와 implements를 함께 쓴다. (InterExam)
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
32
33
34
package inheritance;
interface InterTest{
     public void test();
}
//전부다 추상이라면 추상클래스라 안붙이고 interface를 붙인다.
interface InterShape{
     public void draw();
     public void move();
     public void print();
}
//interface는 extends가 아닌 implements를 사용.
class InterCircle implements InterShape, InterTest{
     //하위 클래스가 상위 추상 클래스의 메소드를 부를때는 구현(중괄호 {})해야함.꼭.
     //InterTest도 상속받았기 때문에 test(){}도 구현.
     public void draw() {}
     public void move() {}
     public void print() {}
     public void test() {}
}
class Inter {
     public void interTest() {
     }
}
//자바는 다중 상속이 안되게끔 되어있는데 다중 상속을 받아야할때는 이렇게 표현.
//상속을 받고 interface를 써줌.
class InterRectangle extends Inter implements InterShape,
InterTest{
     public void draw() {}
     public void move() {}
     public void print() {}
     public void test() {}
}
public class InterExam {
}

 


  • interface-implements로 원 넓이, 둘레, 사각형 넓이, 둘레 구하기 (InterfaceMain, Shape)
1
2
3
4
5
6
7
8
9
10
11
12
13
package interfaceTest;
public class InterfaceMain {
     
     public static void main(String[] args) {
          //앞에가 Rectangle, Circle형이 아니다. 부모클래스란 소리.
          Shape rec=new Rectangle(5,7);
          Shape circle=new Circle(5);
          System.out.println("원 넓이: "+circle.area());
          System.out.println("원 둘레: "+circle.circum());
          System.out.println("사각형 넓이: "+rec.area());
          System.out.println("사각형 둘레: "+rec.circum());
     }
}

 

 

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
32
package interfaceTest;
public interface Shape {
     double area(); //넓이
     double circum(); //둘레 
}
class Rectangle implements Shape{
     private int w, h;
     public Rectangle(int w, int h) {
          this.w=w;
          this.h=h;
     }
     public double area() {
          return w*h;
     }
     public double circum() {
          return (w+h)*2;
     }
}
class Circle implements Shape{
     private int r;
     public Circle (int r) {
          this.r=r;
     }
     public double area() {
          //Math는 수학적 계산이 완료된 클래스.
          //멤버변수로 PI가 그 중 하나.
          return r*r*Math.PI;
     }
     public double circum() {
          return 2*r*Math.PI;
     }
}

  • 원화를 달러로 변환, 키로미터를 마일로 변환하는 두 클래스는 상위의 추상클래스를 상속받는다. (ConverterMain, Converter, Won2Dollar, Km2Mile)
1
2
3
4
5
6
7
8
9
10
11
package interfaceTest;
public class ConverterMain {
     public static void main(String[] args) {
          //원화를 달러로
          Won2Dollar toDollar=new Won2Dollar(1200);
          toDollar.run();
          //km를 마일로
          Km2Mile toMile=new Km2Mile(1.6);
          toMile.run();
     }
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package interfaceTest;
import java.util.Scanner;
//추상인 메소드, 추상아닌 메소드가 섞여 있으므로 추상 클래스로 만든다. (모두 추상이면 interface)
public abstract class Converter {
     abstract protected double convert(double src);
     abstract String srcString();
     abstract String destString();
     protected double ratio;
          
     Scanner scanner=new Scanner(System.in);
     public void run() { //교환
          //srcString, destString은 돈이 들어갈 수도, 길이 단위가 들어갈 수도 있다.
          //따라서 현재 Convert 클래스로는 정의하지 못하고
          //하위 클래스들이 정의를 해야하므로 추상메소드로 바꾸고 따라서 클래스도 추상으로 바꿔야한다.
          System.out.println(srcString()+"을 "+destString()+"로 바꿉니다.");
          System.out.print(srcString()+"을 입력하세요>>");
          double val=scanner.nextDouble();
          double res=convert(val); //스캐너가 입력한 값을 인수로 받는다.
          System.out.println("변환 결과: "+res+destString()+"입니다.");
     }
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package interfaceTest;
public class Won2Dollar extends Converter {
     public Won2Dollar(int don) {
          super.ratio=don;
     }
     @Override
     protected double convert(double src) {
          //src/don이라고 하면 don이 뭔지 모르니까 부모클래스에 ratio를 주고 그걸 나누는 것
          return src/ratio;
     }
     @Override
     String srcString() {
          return "원";
     }
     @Override
     String destString() {
          return "달러";
     }
}

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package interfaceTest;
public class Km2Mile extends Converter {
     public Km2Mile (double ratio) {
          super.ratio=ratio;
     }
     @Override
     protected double convert(double src) {
          // TODO Auto-generated method stub
          return src/ratio;
     }
     @Override
     String srcString() {
          // TODO Auto-generated method stub
          return "Km";
     }
     @Override
     String destString() {
          // TODO Auto-generated method stub
          return "mile";
     }
}

 


  • ArrayList를 사용하여 배열 선언하기. ArrayList에는 객체가 들어가며 추가할때는 add, 제거할때는 remove명령어 사용 (ArrayTest)

 

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
32
33
34
35
36
37
38
package utilTest;
import java.util.ArrayList;
public class ArrayTest {
     public static void main(String[] args) {
          ArrayList arr=new ArrayList(); //ArrayList엔 객체가 들어간다. 메소드로 접근
          arr.add(1); //ArrayList에 추가하는 명령어는 add
          arr.add("안녕");
          arr.add(3.2); //Double이라는 클래스가 들어감. Wrapper 클래스로 변환되었기 때문에 추가가되는 것.
          System.out.println("마지막: " +arr.get(arr.size()-1)); //인덱스에 접근하는 메소드는 get()
          System.out.println(arr.size()); //length가 아니라 size를 사용
          arr.add(new Integer(3)); //add는 맨 끝에 붙임.
          System.out.println("크기: "+arr.size());
          System.out.println("마지막: " +arr.get(arr.size()-1));
          arr.remove(1); //안녕이 지워짐.
          arr.remove("안녕"); //안녕이 지워져있기 때문에 또 지울 수 없음.
          System.out.println("크기: "+arr.size());
          arr.add(1,"지금 자바");
          System.out.println("크기: "+arr.size());
          //ArrayList의 list엔 String형만 넣겠다. 제네릭 표시. 특정 개체로 유형을 정함.
          //클래스에 객체 오브젝이 들어감. int는 기본 자료형이기 때문에 정수만 받고 싶다면 Integer라고 적어야함.
          ArrayList<Integer>list=new ArrayList<Integer>();
          list.add(1);
          list.add(2);
          ArrayList<String>alist=new ArrayList<String>();
          alist.add("자바");
          alist.add("Java");
          for(int i=0;i<alist.size();i++) {
              System.out.println(alist.get(i));
          }
          for(String s:alist) {
              System.out.print(s+"\t");
          }
          System.out.println();
          for(int i:list) { //컴파일러가 알아서 wrapper해줘서 int를 사용할 수 있다.
              System.out.print(i+"\t");
          }
     }
}
cs

 


+이전의 ShapeManager와 Buyer 클래스에 배열을 ArrayList형식으로 바꾼다면..

 

<ShapeManager>

Shape[]arr=new Shape[50]; 

->ArrayList <Shape> slist=new ArrayList <Shape>();

 

arr[cnt++]=new Circle(x,y,r);

->slist.add(new Circle(x,y,r));

 

arr[cnt++]=new Square(x,y,w,h);

->slist.add(new Square(x,y,w,h));

 

for(Shape s: slist){

    sum+=s.getArea();

    s.print();
}


<Buyer>

Product[] arr=new Product[10];

->ArrayList <Product>list=new ArrayList<Product>();

 

arr[cnt++]=p;

->list.add(p);

 

for(int i=0;i<cnt;i++) {

->for(int i=0;i<list.size();i++) {

 

System.out.println("구매내역: "+arr[i]);

->System.out.println("구매내역: "+list.get(i)); 
System.out.println("가격: "+list.get(i).price);