Java 8일차 : 상속, 다형성, 인터페이스

상속

class 서브클래스명 extends 수퍼클래스명{
  ...
}
  • this. : 현재 자신의 주소를 가지고 있는 인스턴스 변수
  • super. : 수퍼클래스의 주소를 가지고 있는 인스턴스 변수
  • 서브클래스 생성시 생성자로 값을 받아 수퍼클래스로 넘긴다.
  • 이 때, 접근이 가능한 변수는 super. 얻으면 되는데, 만약 private 이면 직접 줄 수가 없으니 부모생성자를 호출하여 넘긴다. (단, 이때 부모 생성자 안의 내용이 본인(부모)의 private변수에 대한 처리가 있어야 한다.)
  • 부모생성자 호출 : super() => 반드시 첫줄에 있어야 한다.
this() : 현재 클래스의 생성자호출
super() : 부모 클래스의 생성자호출

예시

package test.day0412;

class Apple1{

  String msg;

  Apple1(String msg){
    this.msg = msg;
  }

  public Apple1() {
    System.out.println("부모클래스의 디폴트생성자 ");
  }
}

class Orange1 extends Apple1{

  String carName;
  int price;

  Orange1(String msg, String carName, int price) {
    //기본적으로 super()은 항상 내부적으로 실행되므로 1. 부모클래스에 디폴트생성자를 만들던지, 2. super(msg)라 주든지. 
    //super();
    super.msg = msg; //super는 부모의 주소를 가지고 있는 인스턴스 변수
    //super의 멤버변수는 변수이름이 중복되지 않는한 super, this로 모두 접근 가능
    this.carName = carName;
    this.price = price;
  }

  public void write() {

    System.out.println(super.msg);
    System.out.println(this.carName);
    System.out.println(this.price);
  }
}

public class SuperEx1 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    Apple1 ap = new Apple1();
    Orange1 or = new Orange1("호호호", "소나타", 2000);
    or.write();
    System.out.println(or.msg); //부모의 변수지만 자식에게서 호출도 되는군? 

  }

}
package test.day0412;

class Apple1{

  String msg;

  Apple1(String msg){
    this.msg = msg;
  }

  public Apple1() {
    System.out.println("부모클래스의 디폴트생성자 ");
  }
}

class Orange1 extends Apple1{

  String carName;
  int price;

  Orange1(String msg, String carName, int price) {
    //기본적으로 super()은 항상 내부적으로 실행되므로 1. 부모클래스에 디폴트생성자를 만들던지, 2. super(msg)라 주든지. 
    //super();
    super.msg = msg; //super는 부모의 주소를 가지고 있는 인스턴스 변수
    //super의 멤버변수는 변수이름이 중복되지 않는한 super, this로 모두 접근 가능
    this.carName = carName;
    this.price = price;
  }

  public void write() {

    System.out.println(super.msg);
    System.out.println(this.carName);
    System.out.println(this.price);
  }
}

public class SuperEx1 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    Apple1 ap = new Apple1();
    Orange1 or = new Orange1("호호호", "소나타", 2000);
    or.write();
    System.out.println(or.msg); //부모의 변수지만 자식에게서 호출도 되는군? 

  }
}

클래스의 멤버변수가 모두 private 일 경우 서브클래스에서 접근하기

package test.day0412;

class Apple2{

  private String msg;
  private int day;

  Apple2(){
    System.out.println("수퍼클래스의 디폴트 생성자 ");
    msg = "default";
    day=1;
  }

  Apple2(String msg, int day){
    System.out.println("수퍼클래스의 두번째 생성자 ");
    this.msg = msg;
    this.day = day;
  }

  public void writeData() {
    System.out.println("메세지= " + msg);
    System.out.println("날짜= " + day);
  }
}

class Orange2 extends Apple2{

  private String carName;

  Orange2(){
    System.out.println("서브클래스의 디폴트 생성자 ");
    carName = "그랜져";
  }

  Orange2(String msg, int day, String carName){
    super(msg, day); //반드시 첫줄 
    this.carName = carName;
  }

  @Override
  public void writeData() {
    // TODO Auto-generated method stub
    super.writeData(); 
    //부모의 변수가 private이라 직접 불러오기 거시기하므로 
    //미리 부모클래스에서 자기 변수를 public메서드안에서 한번씩 불러주면 
    //그 메시드를 자식에서 호출하는건 가능함. 즉 간접적으로 부모의 private변수를 가져오려면 이렇게...
    System.out.println("차종= " + carName);
  }
}

public class SuperEx2 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    Orange2 or2 = new Orange2();
    or2.writeData();

    Orange2 or1 = new Orange2("오늘은 금요일", 12, "벤츠");
    or1.writeData();

  }
}

오버라이딩

  • 자식의 오버라이딩 메서드는 접근지정자가 부모의 그것보다 항상 같거나 넓어야함
package test.day0412;

class Apple3{
  protected void hello1() {
    System.out.println("super hello1");
  }

  void hello2() {
    System.out.println("super hello2");
  }
}

class Orange3 extends Apple3{
  @Override
  protected void hello1() { //public과 protected만 가능 
    System.out.println("sub hello1");
  }

  @Override
  void hello2() { //public, protected, default 가능 
    System.out.println("sub hello2");
  }
}

public class SuperEx3 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    Orange3 or3 = new Orange3();
    or3.hello1();
    or3.hello2();
  }
}

Final

package test.day0412;

//class가 final이면 상속불가능 (자식 만들기 불가능)
final class Apple4{
  //메서드가 final이면 (자식클래스로부터) 오버라이딩이 안된다.
  final public void write() {
  }
}

다형성

다형성의 조건

    • 반드시 상속관계가 성립되어야 한다.

      부모클래스 변수명 = new 자식클래스();
      
    • 일반적으로 중복제거 및 재사용성을 위해 메서드의 인자를 지정할 때 다형성을 많이 적용한다

    • 부모클래스 변수 하나로 많은 자식 클래스들을 관리하기 위해서 사용한다

    • A a = new B(); 로 선언되었을 때 호출 가능한 메서드는

      1. A가 가진 메서드
      1. 오버라이드 된 메서드
      1. 불가능 : B에만 구현되어있는 메서드

예시

package test.day0412;

abstract class SuperPlay{
  public void play() {
    System.out.println("super");
  }
  //play2가 직접적으로 하는일이 없다.
  //그래서 등록만 하고 싶을 때 미완성의 메서드라는 의미로 앞에 abstract를 붙다.
  //이때 클래스의 멤버중에 한개라도 abstract가 있다면
  //클래스도 반드시 abstract라야 한다. (추상 메서드는 추상 클래스에만 존재 가능)
  //method body없이 ; 로 끝낸다.
  //추상클래스를 상속받은 클래스는 반드시 추상 메소드를 오버라이드하여야 한다.
  //만약 안할경우 그 자식클래스 역시 추상화해줘야한다.
  //추상 클래스는 직접적으로 객체 생성이 불가능.
  abstract public void play2();
}

class Draw extends SuperPlay{
  @Override
  public void play() {
    System.out.println("drawing!");
  }

  @Override
  public void play2() {
    System.out.println("drawing again!");
  }
}

class Piano extends SuperPlay{
  @Override
  public void play() {
    super.play();
    System.out.println("playing piano!!");
  }

  @Override
  public void play2() {
    System.out.println("piano again!");
  }
}

class SuperEx5 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    SuperPlay sp = null;
    sp = new Draw();
    sp.play();
    sp.play2();
    sp = new Piano();
    sp.play();
    sp.play2();
    //sp = new SuperPlay(); 추상 클래스는 객체 생성이 안된
  }
}
package test.day0412;

abstract class Apple6{
  public static void show() {
    System.out.println("super abstract");
  }
  abstract public void disp(); //추상 메서드. 메서드 바디가 없다.
}

//Apple6 를 상속받을 자식 클래스가 추상클래스가 아니라면 반드시 disp를 오버라이드 해야함 

class Orange6 extends Apple6{
  public void disp() {
    System.out.println("disp methos is overridden");
  }
}


public class AbstEx6 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    Apple6 ap = new Orange6();
    ap.disp();
    ap.show();
  }
}
  • 추상 클래스로부터 상속받는 클래스가 추상메서드를 오버라이드 하지 않으면 같이 추상화를 해줘야한다
  • 상속시 반드시 오버라이드 할 필요는 없고(추상화만 해준다면) 언젠가 후손클래스가 필요할 때 오버라이드 하면 된다.
package test.day0412;

abstract class Apple7{
  public static void show() {
    System.out.println("super abstract");
  }
  abstract public void disp(); 
}
abstract class Orange7 extends Apple7{
  public void show2() {
    System.out.println("orange7 super");
  }
  abstract public void add();
}

class Kiwi7 extends Orange7{

  @Override
  public void add() {
    // TODO Auto-generated method stub
    System.out.println("add data");
  }

  @Override
  public void disp() {
    // TODO Auto-generated method stub
    System.out.println("display data");
  }

}

public class AbstEx7 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    Apple7 ap = new Kiwi7();
    ap.disp();
    ap.show();
    Orange7 ap2 = new Kiwi7();
    ap2.add();
    ap2.disp();
    ap.show();
    ap2.show2();
  }
}

인터페이스

  • 일단 일반 메서드와 추상 메서드가 섞여 있을 경우에는 추상 클래스로 구현하면 된다.
  • 하지만, 만약 모든 메서드가 추상 메서드라면 굳이 클래스를 유지할 필요가 없다.
  • 그냥 클래스 말고 인터페이스로 만들면 된다. 인터페이스란 상수와 추상메서드로만 이루어져 있는것을 말한다
 interface 인터페이스명{ 메서드, 상수,... }
  • 인터페이스는 음식점의 메뉴판과 같다. 왜냐하면 실체는 없고 선언만 되어 있으므로..

  • 인터페이스 상속

    // 1. 클래스가 인터페이스를 상속(구현)받을 경우
    class 클래스명 implements 인터페이스명{
    	//이경우 인터페이스가 가진 모든 메소드를 오버라이딩하여야한다
    	...
    }
    // 2. 인터페이스를 인터페이스가 상속받을 경우
    interface 서브인터페이스명 extends 슈퍼인터페이스명{
    	...
    }
    

예시

package test.day0412;

//인터페이스는 상수, 추상 메서드로만 구성 
interface InterA{
  // final int SPEED=100;
  // abstract public void speedUp();
  int SPEED=100;
  public void speedUp(); 
  //이렇게 줘도 알아서 상수, 알아서 abstract method로 읽
}

//인터페이스를 상속받는 클래스는 반드시 모든 메서드를 오버라이드 해줘야한다 
class Car implements InterA{

  @Override
  public void speedUp() {
    // TODO Auto-generated method stub
    System.out.println("현재속도" + SPEED + "에서 업!");
  }
}

class Car2 implements InterA{
  int speed = SPEED;

  @Override
  public void speedUp() {
    // TODO Auto-generated method stub
    speed += 20;
    System.out.println("속도 " +SPEED+ "에서 " + speed + "로 스피드업!" );
  }
}

public class InterfaceEx8 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    InterA it = new Car();
    it.speedUp();
    InterA it2 = new Car2();
    it2.speedUp();
  }
}
  • 하나의 클래스에서 여러개의 인터페이스를 구현할(상속받을)수 있다

    class A implements B,C,D {
      ...
    }
    //만약 B가 클래스, C,D가 인터페이스라면
    class A extends B implements C,D {
      ...
    }
    

예시

package test.day0412;

interface One{
  public void play();
  public void draw();
}

//인터페이스 간에도 상속이 가능하다.
interface Two extends One{
  public void study();
}
class Three{
  public void write() {
    System.out.println("wirte");
  }
}

class Four extends Three implements Two{

  @Override
  public void play() {
    // TODO Auto-generated method stub
    System.out.println("play");
  }

  @Override
  public void draw() {
    // TODO Auto-generated method stub
    System.out.println("draw");

  }

  @Override
  public void study() {
    // TODO Auto-generated method stub
    System.out.println("study");

  }
}

public class InterfaceEx9 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    One one = new Four();
    one.play();
    one.draw();
    Two two = new Four();
    two.draw();
    two.play();
    two.study();
    Three three = new Four();
    three.write();
  }
}
package test.day0412;

interface InterAA{
  public void play();
}
interface InterBB{
  public void draw();
}

class Milk implements InterAA, InterBB{//인터페이스는 다중구현(상속)가능 

  @Override
  public void draw() {
    // TODO Auto-generated method stub
    System.out.println("draw!");
  }

  @Override
  public void play() {
    // TODO Auto-generated method stub
    System.out.println("play!");
  } 
}

public class InterfaceEx10 {

  public static void main(String[] args) {
    InterAA a1 = new Milk();
    a1.play();
    InterBB a2 = new Milk();
    a2.draw();
    Milk a3 = new Milk();
    a3.draw();
    a3.play();
  }
}

실습문제

[다형성에 대한 문제]

Command -write =>인터페이스

상속받은 클래스들(오버라이드 메소드)

List -write

Delete -write

Modify -write

Insert -write

================================

메인에서

Command com=null; <- 변수는 얘만 선언하세요

조건에 따라

com=new List();

com=new Delete();

..등등으로 생성한후 write 호출하세요

[메 뉴] : 추가, 삭제, 출력, 수정, 종료

import java.util.Scanner;

interface Command
{
  public void write();
}

class List implements Command{
  @Override
  public void write() {
    // TODO Auto-generated method stub
    System.out.println("게시판에 전체 게시물을 출력합니다");
  }
}
class Insert implements Command{
  @Override
  public void write() {
    // TODO Auto-generated method stub
    System.out.println("게시판에 게시글을 추가합니다");
  }
}

class Delete implements Command{
  @Override
  public void write() {
    // TODO Auto-generated method stub
    System.out.println("게시판에 게시글을 삭제합니다");
  }
}
class Modify implements Command{
  @Override
  public void write() {
    // TODO Auto-generated method stub
    System.out.println("게시판에 게시글을 수정합니다");
  }
}

public class InterfaceEx11 {
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    Scanner sc=new Scanner(System.in);
    int num=0;
    Command com = null;
    while(true)
    {
      System.out.println("[메뉴]\n1.추가\n2.삭제\n3.출력\n4.수정\n5.종료\n");
      num=sc.nextInt();
      switch(num)
      {
        case 1:
          com = new Insert(); break;
        case 2:
          com=new Delete(); break;
        case 3:
          com=new List(); break;
        case 4:
          com=new Modify(); break;
        default:
          System.out.println("종료합니다");
          System.exit(0);
      }
      com.write();//어떤 객체로 생성이 됐는냐에 따라 하는일이 달라진다
    }
  }
}

Categories:

Updated:

Comments