100일 챌린지/빅데이터기반 인공지능 융합 서비스 개발자

Day 07 - 상속

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);
        }
    }