ksyke 2024. 7. 30. 12:20

상속

class 클래스명 extends 부모클래스{};
  • 부모의 기능을 물려받는 것 - 반복되는 기능을 사용하기 위해서
  • 자바는 단일상속이라 다중상속을 지원하지 않음.
  • 자바의 모든 클래스는 상속을 받는다.
  • extends 부모가 코드명세가 없을시 해당 클래스는 java.lang.Object 클래스를 상속받게 된다.
    • public class Ex01은 사실 public class Ex01 extends Object이다.
  • 상속은 반드시 부모에서 자식으로 상속된다.
    • 자식이 가지고 있는기능은 부모가 사용하지 못한다.
  • 자식은 부모가 가지고 있는 메소드를 override 할 수 있다.
class Parent{
    public int money = 1000;
    public void how() {
        System.out.println( money + "원 있음");
    }
}

class Child extends Parent{
    public int money = 100;

    public void func2() {
        System.out.println( money + "원 있음");
    }
}

public class Ex01 extends Object{

    public static void main(String[] args) {
        Child me1 = new Child();
        me1.how();
        me1.func2();
    }
}

오버로드와 오버라이드의 차이

  • 오버로드 : 원칙적으로 메소드/생성자의 이름은 중복이 불가능하지만 parameter가 다를시 중복으로 사용할 수 있다.
    -> 오버로드의 기준은 매개변수 이다.
  • 오버라이드 : 상속에서 부모의 기능을 재정의하는것. (오직 메서드만 가능)
    • 오버라이드를 하기 위해서는 클래스명과 return 타입이 완전히 같아야 한다.
    • @Override: 오버라이드 되는것을 체크해주는 annotaion.

toString 오버라이드

public class Ex01 extends Object{

    public static void main(String[] args) {
Ex01 me = new Ex01();
        System.out.println(me);
        System.out.println(me.toString());
    }

    @Override
    public String toString() {
        return "내가 재정의한 toString";
    }

자식 클래스에서 오버라이드된 부모의 기능 사용하기

class Lec02{
    int su = 1111;
    public void func01() {
        System.out.println("부모의 기능");
    }
}

public class Ex02 extends Lec02{
    int su = 2222;

    public void func01() {
        super.func01(); // super는 부모의 참조변수를 호출한다. 
        System.out.println("자식의 기능");
        System.out.println(super.su); // 1111
        System.out.println(this.su); // 2222
    }

    public static void main(String[] args) {
        Ex02 me = new Ex02();
        me.func01();
    }
}
  • super는 부모 클래스의 참조변수를 호출
  • this는 자신(자식)의 참조변수를 호출

다형성

package com.Day07;

class Parent03{
    public void func01() {
        System.out.println("부모의 기능1");
    }
    public void func02() {
        System.out.println("부모의 기능2");
    }
}

class Child03 extends Parent03 {
    public void func02() {
        System.out.println("자식이 재정의한 기능");
    }
    public void func03() {
        System.out.println("자식만의 기능");
    }
}

public class Ex03 {
    public static void main(String[] args) {
        Parent03 p1 = new Parent03();
        p1.func01();
        p1.func02();
        System.out.println("---------------------");

        Child03 c1 = new Child03();
        c1.func01();
        c1.func02();
        c1.func03();
        System.out.println("---------------------");

        // 다형성
        Parent03 p2;
        p2 = new Child03();
        p2.func01(); // 부모의 메소드 
        p2.func02(); // 자식의 메소드를 호출한다.
//        p2.func03(); // 호출불가
    }

}

다형성을 이용한 클래스 활용

class Machine{
    public void on() {
        System.out.println("전원을 켜다.");
    }
    public void off() {
        System.out.println("전원을 끄다.");
    }
    public void work() {
        System.out.println("일을 함");
    }
}

class Tv extends Machine{
    public void work() {
        System.out.println("주파수를 잡아 화면을 보여주다.");
    }
}

class Radio extends Machine{
    public void work() {
        System.out.println("주파수를 잡아 소리를 들려주다.");
    }
}

class Audio extends Machine{
    public void work() {
        System.out.println("CD 음악을 들려주다.");
    }
}

public class Ex04 {

    public static void main(String[] args) {
        java.util.Scanner sc;
        sc = new java.util.Scanner(System.in);
        int input = 0;
        Machine remote = null;

        while(true) {
            System.out.print("1. tv 2. radio 3. Audio 0. exit > ");
            input = sc.nextInt();
            if(input == 0) break;
            if(input == 1) {
                remote = new Tv();
            }
            else if(input == 2) {
                remote = new Radio();
            }
            else if(input == 3) {
                remote = new Audio();
            }
            remote.on();
            remote.work();
            remote.off();
        }
    }
}

자바 상속의 계층도


Object 클래스

public class Ex05 extends java.lang.Object implements Cloneable {

    public static void main(String[] args) throws CloneNotSupportedException {
        Object obj = new Object(); 
        System.out.println(obj.toString());
        System.out.println(obj.hashCode());
        System.out.println(obj.getClass());
//        System.out.println(obj.clone()); // 사용하지 못함 

        System.out.println("-------------------------");
        Ex05 me = new Ex05();
        System.out.println(me.toString());
        System.out.println(me.hashCode());
        System.out.println(me.getClass());

        System.out.println("-------------------------");
        Object you = me.clone(); // 객체 복사
        System.out.println(you.toString());

        int[] arr1 = {1, 3, 5, 7};
        int[] arr2 = (int[])arr1.clone(); // 깊은복사 
        arr1[2] = 6;
        System.out.println(java.util.Arrays.toString(arr1));
        System.out.println(java.util.Arrays.toString(arr2));
    }
}

키워드

  • 접근 제한자
  • public, default, private, protected가 존재함
    • public : 모든 패키지에서 접근 허용
    • protected >= default : 동일 패키지에서만 접근 허용
      • protected와 default의 차이는 protected는 상속을 통해서는 모든 접근을 허용한다.
    • private : 자기자신의 클래스 내부에서만 접근을 허용한다. (상속을 통해서도 호출이 안됨
  • public protected == default private
  • 필드 == 메서드
  • 필드, 메서드, 생성자에서는 네가지 접근제한자의기능이 같다.
class Lec06{
    public void func01() {
        System.out.println("f1 public");
    }
    protected void func02() {
        System.out.println("f2 protected");
    }
    void func03() {
        System.out.println("f3 default");
    }
    private void func04() {
        System.out.println("f4 private");
    }
}

public class Ex06{

    public static void main(String[] args) {
        com.Day07.Lec06 lec = new com.Day07.Lec06();
        lec.func01();
        lec.func02();
        lec.func03();
//        lec.func04(); // 호출 못함

        com.dc.Lec06 lec2 = new com.dc.Lec06();
        lec2.func01();
//        lec2.func02(); // 호출 못함
//        lec2.func03(); // 호출 못함
//        lec.func04(); // 호출 못함

        Ex06 me = new Ex06();
        me.func01();
        me.func02();
        me.func03();
        me.func04();

    }
    public void func01() {
        System.out.println("me1 public");
    }
    protected void func02() {
        System.out.println("me2 protected");
    }
    void func03() {
        System.out.println("me3 default");
    }
    private void func04() {
        System.out.println("me4 private");
    }

}
Lec06() {}
protected Lec06(String msg){}
Lec06(String msg){}
private Lec06(double a) {}

클래스에서의 키워드

  • 한 문서상에서 public class는 (main 메서드를 갖는 class) 하나만 존재할 수 있다.
  • private와 protected는 존재하지 않음.

상속변수 final

메소드에서의 상수변수

메소드에서 final이 쓰이면 오버라이드가 불가능하다.

클래스에서의 상수변수

클래스에서 final이 쓰이면 상속이 불가능하다.


클래스가 다를 때 생성자 사용하기


추상 클래스

  • 추상 메서드를 0개 이상 갖는 클래스
    • 추상 메서드가 없는데도 abstract 키위드를 붙이는건 오직 상속을 통해서만 객체 생성을 만들게 하기 위해서다.
  • 추상 클래스는 독자적으로 객체 생성이 불가능하다.
abstract class Lec03{
    void func01() {
        System.out.println("기능");
    }
}

public class Ex03 extends Lec03{

    public static void main(String[] args) {
//        Lec03 lec = new Lec03(); // 불가능
        Lec03 me = new Ex03();
        me.func01();
    }
}

추상 메서드

  • 추상메서드를 사용하기 위해선 abstract로 선언 후 class에 abstract 키워드를 넣거나, 아니면 오버라이드를 통해 구현을 하는 방법이 있다.
abstract class Parent{
    void func01() {
        System.out.println("부모의 기능");
    }

    public abstract void func02();
}

class Child extends Parent{
    @Override
    public void func02() {
        System.out.println("자식이 오버라이드한 기능");
    }
}

public class Ex01 {

    public static void main(String[] args) {
        Child c1 = new Child();
        c1.func01();
        c1.func02();

//        Parent p = new Parent(); // 추상 클래스는 객체생성이 불가능 
        Parent p = new Child();
        p.func01(); // 부모의 기능을 호출
        p.func02(); // 자식이 오버라이드한 기능을 호출
    }
}

abstract를 사용하면 override를 강제화 할 수 있다.

abstract class Machine01{
    void on() {
        System.out.println("켜고");
    }
    void off() {
        System.out.println("껐음");
    }
    abstract void work();
}

class Tv extends Machine01{
    @Override
    void work() {
        System.out.println("화면을 출력하고");
    }
}

class Radio extends Machine01{
    @Override
    void work() {
        System.out.println("소리를 들려주고");
    }
}

class Audio extends Machine01{
    @Override
    void work() {
        System.out.println("소리를 들려주고");
    }
}
public class Ex02 {

    public static void main(String[] args) {
        Machine01 remote = null;
        java.util.Scanner sc = new java.util.Scanner(System.in);
        int input;

        while(true) {
            System.out.print("1. TV 2. Radio 3. Audio 0. Exit > ");
            input = sc.nextInt();
            if(input == 0) break;
            else if(input == 1) remote = new Tv();
            else if(input == 2) remote = new Radio();
            else if(input == 3) remote = new Audio();

            remote.on();
            remote.work();
            remote.off();
        }
    }
}

Default가 없는 클래스를 상속받기

abstract class Lec04{
    final int su;

    public Lec04(int su) {
        this.su = su;
    }

    abstract void func01();
}

public class Ex04 extends Lec04 {

    public Ex04() {
        super(4321);
    }

    public static void main(String[] args) {
        Ex04 me = new Ex04();
        me.func01();
    }

    @Override
    void func01() {
        System.out.println("su = " + super.su);
    }
}