본문 바로가기
카테고리 없음

230125 TIL

by hbIncoding 2023. 1. 25.

JAVA 공부 4일차

 

객체지향 Part. 2 (상속, 오버라이딩, 캡슐화, 다향성, 추상 클래스, 인터페이스 등)

 

1) 상속

ㄱ. 상속 : 기존의 클래스로 새로운 클래스를 작성하며 extends 를 이용해 부모자식 관계를 만들어 준다.

  • 자손은 조상의 모든 멤버를 상속 받는다. (생성자와 초기화 블럭은 제외)
  • 자손의 변경은 조상에게 영향을 주지 않는다.
  • 상속받은 클래스를 상속받을 수 있다. (부모가 아니라 조상까지 갈 수 있다)
  • java는 단일 상속만 허용, Diamond Problem
  • 모든 클래스는 Object 클래스로 부터 상속 받는다.

ㄴ. Overriding : 상속받은 메서드를 자신에게 맞게 변경

  • 선언부는 변경 불가능
  • 메서드 내부의 내용만 변경 가능
  • 선언부가 조상의 메서드와 일치해야함
  • 접근 제어자를 조상의 메서드 보다 좁은 범위로 변경할 수 없음
  • 예외는 조상 클래스의 메서드 보다 많이 선언할 수 없음.
  • ※오버로딩 : 기존에 없는 새로운 메서드를 정의

ㄷ. super & super() : this & this()와 반대라고 볼 수 있으며 조상의 멤버를 자신의 멤버와 구별 할 때 사용한다.

  • super
  • 객체 자신을 가리키는 참조 변수 ex) super.params
  • 인스턴스 메서드(생성자) 내에서만 존재
  • 조상의 멤버를 자신의 멤버와 구별할 때 사용
  • super()
  • 조상의 생성자를 호출
  • 조상의 멤버를 조상의 생성자를 호출해서 초기화
  • 생성자의 첫 줄에 반드시 생성자를 호출
class Parent {
    int x,y,z;

    public Parent(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

class Child extends Parent {

    Child() {
        // super() 를 통해서 부모 클래스의 멤버변수를 초기화합니다.
        super(10,20,30);
    }
}

2) package와 import

. package

  • 서로 관련된 클래스의 묶음
  • 클래스의 실제 이름은 패키지를 포함 ex) java.lang.String

. package 선언

  • 패키지는 소스파일의 첫 번째 문장으로 단 한번만 선언
  • 같은 소스 파일의 클래스들은 모두 같은 패키징에 속함
  • 패키지 선언이 없으면 default 패키지에 속함

. package 선언

  • 클래스 파일(.class)의 위치를 알려주는 경로
  • classpath(환경변수)로 관리하며 경로간의 구분자는 ; 사용
  • classpath에 패키지의 루트를 등록해줘야 한다.

ㄹ. import

  • 클래스가 속한 패키지를 알려주며, 클래스 사용시 패키지 이름을 생략할 수 있게 해준다.
  • java.lang 패키지는 중요해서 생략 가능하게 되어있음

. static import

  • static 멤저를 사용할 때 클래스 이름 생략 가능
  • ex ) import static java.lang.System.out; >> out.println("출력가능");

 

3) 제어자와 접근 제어자

ㄱ. 제어자

  • 클래스와 멤버에 부가적인 의미 부여, 하나의 대상에 여러 제어자 사용 가능
  • static

  • final

  • abstract

ㄴ. 접근 제어자

  • private : 같은 클래스 내에서만 접근이 가능합니다.
  • (default) : 같은 패키지 내에서만 접근이 가능합니다. (생략가능)
  • protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손 클래스에서 접근이 가능합니다.
  • public : 접근 제한이 전혀 없습니다.

ㄷ. 접근 제어자 조합 주의

 
대상
사용가능한 접근 제어자
클래스
public, (default), final, abstract
메서드
모든 접근제어자, final, abstract, static
멤버변수
모든 접근제어자, final, static
지역변수
final
  • 메서드에 static과 abstract 함께 사용 물가 : static 메서드는 몸통이 있는 메서드만 사용 가능
  • class에는 abstract와 final을 동시 사용 불가 : abstract와 final의 기능 모순
  • abstract메서드의 접근 제어자가 private일 수 없음 : 자손 클래스에서 구현해야하기 때문
  • 메서드에서 private과final을 같이 사용할 필요는 없음 : 이 둘 중 하나만 사용해도 의미가 충분

 

3) 여러가지 특성(캡슐화,다형성,형변환 등)

. 캡슐화

  • 외부로부터 데이터를 보호하기 위해 사용
  • 내부적으로만 사용되는 것을 외부로 노출시키지 않고 감추기 위해서
  • 데이터 그자체가 아닌 메서드를 통해 확인 가능 
public class Capsule {

    private int age;

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

 

. 다형성

  • 여러 가지 혀ㅇ태를 가질 수 있는 능력
  • 조상의 타입의 참조변수로 자손의 타입의 객체를 다루는 것,
  • 하지만 조상에 없고 자손만 가지는 기능 및 속성은 사용 불가
  • 아래 코드에서 Mammalia 클래스를 선언할 때 Whale로 초기화를 했다.(반대는 불가하다)
class Whale extends Mammalia{
    // 고래는 포유류 이면서 바다에 살며 수영이 가능하다.
    public void swimming() {
        System.out.println("수영 하다.");
    }

    @Override
    public void feeding() {
        System.out.println("고래는 모유 수유를 합니다.");
    }

    @Override
    public void giveBirth() {
        System.out.println("고래는 새끼를 낳습니다.");
    }
}

class Mammalia {
    // 포유류는 새끼를 낳고 수유를 한다.
    public void feeding() {
        System.out.println("모유 수유를 합니다.");
    }

    public void giveBirth() {
        System.out.println("새끼를 낳습니다.");
    }
}

class PolyTest1 {
    public static void main(String[] args) {
        // 고래는 포유류이기 때문에 Mammalia 에 담길 수 있다.
        Mammalia mammalia = new Whale();

        // 하지만 포유류 전부가 바다에 살고 수영을 할 수 있는 것은 아니기 때문에
        // 수영 하다 메서드는 실행 불가
//         mammalia.swimming(); // Error 발생

        // 또한 모든 포유류가 전부 고래 처럼 수영이 가능한 것이 아니기 때문에 아래 상황은 불가능 하다.
//         Whale whale = new Mammalia(); // Error 발생

        mammalia.giveBirth();
        mammalia.feeding();
    }
}

 

. 참조변수의 형변환

  • 사용할 수 있는 멤버의 개수를 조절하는 것
  • 조상, 자손 관계의 참조변수는 서로 형변환이 가능
class Whale extends Mammalia{
    // 고래는 포유류 이면서 바다에 살며 수영이 가능하다.
    public void swimming() {
        System.out.println("고래만 수영 하다.");
    }
    @Override
    public void feeding() {
        System.out.println("고래는 모유 수유를 합니다.");
    }
    @Override
    public void giveBirth() {
        System.out.println("고래는 새끼를 낳습니다.");
    }
}
class Mammalia {
    // 포유류는 새끼를 낳고 수유를 한다.
    public void feeding() {
        System.out.println("모유 수유를 합니다.");
    }

    public void giveBirth() {
        System.out.println("새끼를 낳습니다.");
    }
}
class Bird {
    public void fly() {
        System.out.println("Bird.fly");
    }
}

class PolyTest2 {
    public static void main(String[] args) {
        Whale whale = new Whale();
        Mammalia mammalia = (Mammalia) whale; //(Mammalia) 생략 가능!
        mammalia.giveBirth();
        mammalia.feeding();
        //현재 swimming() 불가

        // 형변환을 통해 담긴 mammalia 참조변수를 형변환을 통해
        // 다시 Whale 로 변환할 수 있습니다.
        Whale whale2 = (Whale) mammalia; // (Whale) 생략 불가능!
        whale2.swimming();
        whale2.feeding();

        // 조상, 자손 관계에서만 형변환이 가능합니다.
        Bird bird = new Bird();
//        Mammalia mammalia1 = bird; // Error
//        Mammalia mammalia2 = (Mammalia) bird; // Error

    }
}

ㄹ. A(객체) instanceof B(클래스) 연산자

  • A객체가 B클래스로 부터 상속을 받았는지 확인
  • 참조변수를 형변환 하기 전에 형변환 가능 여부를 확인 하기 위해 사용
  • 형변호나 전에는 반드시 instanceof로 확인 해야함
class A {}
class B extends A{}
class Instanceof {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();

        System.out.println("a instanceof A = " + (a instanceof A));

        // a 객체는 B 클래스의 부모 클래스 입니다.
        // 따라서 아래는 false 입니다.
        System.out.println("a instanceof B = " + (a instanceof B));

        System.out.println("b instanceof A = " + (b instanceof A));

        System.out.println("b instanceof B = " + (b instanceof B));
    }
}

ㄹ. 매개변수 다형성

  • 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다
  • 여러 종류의 객체를 배열로 다룰 수 있으며, 클래스 선언시 같은 클래스를 배열로 선언할 수 도 있다.

 

3) 추상클래스와 인터페이스

. 추상클래스

  • 일반 클래스와 똑같은데 추상 메서드가 추가된 미완성된 클래스
  • 자녀 클래스에서 오버라이딩 후 완성 시켜 사용한다

ㄴ. 인터페이스

  • 추상 메서드의 집합, 구현된 것이 전혀 없는 설계도
  • 모든 멤버가 public이다.
  • 상수 이외의 인스턴스 변수, 클래스 변수는 가질 수 없음
  • 아래와 같은 example로 사용
interface PlayingCard {
    public static final int SPADE = 4;
    final int DIAMOND = 3; // public static final int DIAMOND = 3;
    static int HEART = 2;  // public static final int HEART = 2;
    int CLOVER = 1;        // public static final int CLOVER = 1;

    public abstract String getCardNumber();
    String getCardKing(); // public abstract String getCardKing();
}

 

ㄷ. 인터페이스의 상속

  • 인터페이스의 조상은 언테이스만 가능, class처럼 object가 최고 조상이 아님
  • 상속 받으면서 구현부를 작성하기 때문에 충돌해도 상관없음 >> 다중 상속 가능
interface Fightable extends Movable, Attackable {} // 인터페이스 다중 상속

interface Movable {
    void move(int x, int y);
}

interface Attackable {
    void attack(Unit u);
}

ㄹ. 인터페이스의 구현

  • class 클래스이름 implements 인터페이스이름 {} 으로 구현
  • 추상 클래스 때와 마찬가지로 구현을 다 못한 클래스는 미완성으로 취급함으로 abstract 제어자를 클래스에 추가 해야한다.
class Unit {}

interface Fightable extends Movable, Attackable {}

interface Movable {
    void move(int x, int y);
}

interface Attackable {
    void attack(Unit u);
}

abstract class InterfaceTest implements Fightable {

    @Override
    public void move(int x, int y) {

    }
    
    // attack(Unit u); // 미 구현
    
}

ㅁ. 인터페이스의 다형성

  • 스마트폰을 할머니에게 전화기라고 말씀드리면 할머니는 전화기라고만 생각해서 다른 기능은 쓰지 않을 수 있다.또, 스마트폰을 꼬마한테 게임이야 라고 말하면 꼬마는 게임기라고 생각되어 다른 기능을 쓰지 않을 수 있다.또한 꼬마에게 줄 때, 통화 기능 등의 다른 기능들을 못쓰도록 방지하고자 잠글 수 있는데 interface는 이러한 기능 및 역할들을 모~~~~두 할 수 있기 때문에  interface다형성을 사용하는 이유이다.

ㅂ. 인터페이스의 장점

  • 두 객체 간의 '연결,대화, 소통'을 돕는 '중간 다리 역할'을 한다.
  • 선언(설계)와 구현을 분리시킬 수 있게 해준다.

 

4)참조 링크

  1. interface 다형성 사용 이유 : https://2ham-s.tistory.com/1032
 

인터페이스(interface)와 다형성 왜 사용하는가 ?

인터페이스가 어떻게 class가 할 수 없는 일을 할 수 있는가를 알아보겠다. 사진에서 인터페이스의 다향성도 마찬가지로 , 인터페이스( In 1)에서 정의된 메서드를 어떠한 클래스 ( A )가 인터페이

2ham-s.tistory.com

2. 자바-다형성의 이해 및 예제

https://kadosholy.tistory.com/99