TIL_240212

라미·2024년 2월 12일

TIL

목록 보기
11/25
post-thumbnail

상속(Inheritance)

상속이란?

  • 기존 클래스의 특성(필드와 메서드)을 새로운 클래스에서 이어받아 재사용 하는 것이다.(부모가 자식에게 상속해준다!)
  • 두 클래스를 부모와 자식으로 관계를 맺어준다.

상속 방법(extends 키워드)

// 클래스를 상속하는 방법
class 자식클래스명 extends 부모클래스명 {

}

//예시
class Parent{//부모class(super class)
}
class Child extends Parent{//자식class(sub class)
}
  • extends 키워드를 사용하여 클래스를 상속한다.
  • 위 코드에서 Parent class와 Child 클래스는 상속관계에 있다.

상속의 특징

👻 다중 상속 제약 : Java에서는 단일 상속만 허용한다(하나의 자식은 하나의 부모만 상속 받을 수 있다.)

// 다중상속 불가능 error
class Child extends Parent1, Parent2{
}

👻부모를 상속하는 자식의 개수는 제한이 없다. (하나의 자식 : 여러 부모 X / 하나의 부모 : 여러 자식 O)

public class Car{}
public class SportsCar extends Car{}
public class CampingCar extends Car{}

👻자식 클래스는 부모 클래스의 속성(field)와 메서드(Method)를 상속받아 사옹 할 수 있다. → 코드의 재사용성 증가
👻자식 클래스에 새로운 속성이나 메서드를 추가해도 부모 클래스에 영향이 가지 않는다.
👻자식 멤버 개수는 조상보다 적을 수 없다.(같거나 많다.)
👻오버라이딩(Overriding) : 자식클래스에서 부모 클래스의 메서드를 재정의(Override) 하여 사용 하는 것. 본인의 필요 기능에 맞게 변경한다.

public class Car {
    //Car class field
    String model;
    String color;
    
    //Car class 메서드
    public void horn() {
        System.out.println("부모 빵빵");
    }
    public void stopCar(){
        System.out.println("차 멈춤");
    }
}
public class SportsCar extends Car {
    String engin;
    @Override // 메서드 오버라이딩
    public void horn() {
        System.out.println("자식 뿡뿡뿡");
    }
    public void booster(String engin){
        this.engin = engin;
        System.out.println(engin+"출력~");
    }
}
public class Main {
    public static void main(String[] args) {
        //자식 객체 생성
        SportsCar car = new SportsCar();
        Car pCar = new Car();

        car.model = "람보르기니";
        car.color = "yellow";

        // 부모 클래스의 field와 method를 물려받아 그대로 사용
        car.stopCar();
        System.out.println("car model : "+ car.model+" / car color :"+car.color);

        // 부모에게 물려받았지만 필요에의해 자식이 메서드 내용을 재정의하여 사용(method overriding)
        car.horn();
        pCar.horn(); //비교를 위한 부모 객체 메서드 실행

        // 자식에게만 있는 메서드와 필드 -> 자식 > 부모
        car.booster("자식 엔진");
        System.out.print("자식 엔진 : "+car.engin);

        //자식 클래스의 멤버 추가는 부모 클래스에 영향이 가지 X
        pCar.engin = "부모 엔진추가"; //error
        pCar.booster("브모 엔진"); // error
    }
}
실행결과
차 멈춤
car model : 람보르기니 / car color :yellow
자식 뿡뿡뿡
부모 빵빵
자식 엔진출력~
자식 엔진 : 자식 엔진

→실행결과에서 알 수 있듯이 자식은 부모 클래스의 모든 필드와 메서드를 사용 할 수 있다.
→자식 클래스는 부모 클래스에서 물려받은 메서드를 필요에 의해 재정의 하여 사용 할 수 있다. 이를 메서드 오버라이딩 이라고 한다. 위 코드 SportCar class의 horn() 메서드 부분을 보면 메서드 오버라이딩 확인 할 수 있다.

Object class

  • Object 클래스는 Java 모든 클래스들의 최상위 부모 클래스이다.
  • Java의 모든 클래스는 Object 클래스를 자동으로 상속받는다.
  • 모든 클래스는 Object의 메서드를 사용할 수 있다.

    Object 클래스의 주요 메서드

  • Object clone() : 해당 객체의 복제본을 생성하여 반환함.
  • boolean equals(Object object) : 해당 객체와 전달받은 객체가 같은지 여부를 반환함.
  • Class getClass() : 해당 객체의 클래스 타입을 반환함.
  • int hashCode() : 자바에서 객체를 식별하는 정수값인 해시 코드를 반환함.
  • String toString() : 해당 객체의 정보를 문자열
    로 반환함. & Object 클래스에서는 클래스이름 @해쉬코드값 리턴함.

super와 상속관계에서의 생성자

super 키워드 : 자식 클래스가 부모 클래스를 가르키는 예약어

super : 부모클래스의 멤버를 참조할 수 있다.

  • 객체 내부 생성자 및 메서드에서 부모 클래스의 멤버에 접근하기 위해 사용.
  • 자식 멤버(자기자신)와 부모 멤버를 구분하기 위해 사용한다.

super(): 부모 클래스의 생성자를 호출하기 위해 사용한다.

상속 관계에서의 생성자

  • 부모 클래스의 생성자는 상속되지 않고, 자식 클래스로 객체를 생성할때 자동적으로 부모의 생성자를 호출한다.(부모 클래스 멤버 초기화 작업 먼저 그 후 자식 클래스 멤버 초기화)
  • 생성자가 정의된 클래스는 객체 생성을 위해 생성자 파라미터를 반드시 전달받아야 하기 때문에 생성자가 정의된 클래스를 상속 받게 되면 에러가 발생된다.(파라미터를 갖는 생성자)

부모 생성자 강제 호출

  • 생성자가 정의된 클래스를 상속받는 경우에는 자식 클래스의 생성자를 통해서 부모 생성자를 강제로 호출해야 한다.
  • super(); 키워드를 사용하여 부모 생성자를 호출해 준다.
class Parent{
    public Parent(String str){
        System.out.println("부모 생성자 호출 : " + str);
    }
    public Parent(){
        System.out.println("부모부모");
    }
}

Class Child extends Parent {
    public Child(String str){
        super(str);
        Systemout.println("자식 호출호출호출");
        // super(str); // super의 위치는 항상 생성자의 첫줄에 있어야 한다.
    }
    public Child(){
        System.out.println(자식자식);
    }
}

public class main{
    public static void main(Stringp[] args){
        Child c = new Child("생성자");
        Child c2 = new Child();
    }
}
👍실행 결과
부모 생성자 호출 : 생성자
자식 생성자 호출
부모부모
자식자식

→ 위 실행결과를 보면 알 수 있듯이 자식 생성자 초기화 전에 부모 생성자가 초기화 되는 걸 확인 할 수 있다.


제어자(modifier)

  • 클래스와 클래스의 멤버(멤버 변수,메서드)에 부가적인 의미를 부여
  • 하나의 대상에 여러 제어자를 같이 사용할 수 있다.(접근 제어자는 하나만 사용 가능하다.)
    접근 제어자 : public, protected, defalult, private
    그 외 : static, final, abstract, native, transient, synchronized,volatile, strictfp

제어자 static,final,abstract

제어자대상의미
static멤버변수- 모든 인스턴스에 공통적으로 사용되는 클래스 변수가 된다.
-인스턴스를 생성하지 않고 사용 가능하다.
-클래스가 메모리에 로드될 때 생성된다.
메서드-인스턴스를 생성하지 않고 호출이 가능하다.
-static 메서드 내에서는 인스턴스 멤버들을 직접 사용할 수 없다.
final클래스-변경될 수 없는 클래스, 확장될 수없는 클래스가 된다.
-다른 클래스의 조상이 될 수 없다.(상속불가능)
메서드-변경될 수 없는 메서드가 된다. 오버라이딩을 통해 재정의 될 수 없다.
멤버변수
지역변수
-값을 변경할 수 없는 상수가 된다.
abstract클래스-클래스 내에 추상 메서드가 선언되어 있음을 의미
메서드-선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알린다.

접근 제어자

public : 접근 제한이 없다
protected : 같은 패키지 내, 다른 패키지의 자손 클래스에서 접근이 가능
default : 같은 패키지 내에서만 접근 가능
private : 같은 클래스 내에서만 접근 가능

alt text


캡슐화와 접근제어자

접근 제어자를 사용하는 이유

  • 외부로부터 데이터를 보호하기 위해서
  • 외부에는 불필요한 내부적으로만 사용되는 부분을 감추기 위해서

📝예시

<public class Time{
    // 멤버 변수의 접근제어자를 private 으로 해줘서 외부에서 직접 접근 할 수 없게한다.
    private int hour;
    private int minute;
    private int secound;

    // 메서드를 통하여 private 변수에 접근
    public int getHour(){};
    public void setHour(int hour){this.hour = hour;}
}

public class Main{
    public static void main(String[] args){
        Time t= new Time();
        t.hour = 25; // error -> 멤버 변수의 접근제어자가 private이기 때문에 직접 접근 불가능

        // private 변수에 접근하기 위해 메서드를 통한 간접접근
        hour = t.getHour();
        t.setHour(25); 
    } 
}

👍접근제어자를 사용하여 외부로 부터 직접 접근 방지

- 멤버 변수 접근제어자를 private 으로 설정
- method 접근제어자 public 으로 설정
- 메서드를 통해 멤버변수에 접근 할 수 있도록 설정해 준다.
- 우클릭 - Generate 에서 Getter & Setter 쉽게 만들 수 있다.

다형성

다형성이란?

  • 하나의 객체가 여러가지 타입을 가질 수 있는 것.
  • 부모 클래스 타입으로 자식 클래스 객체참조 할 수 있다.(자식 클래스 타입으로 부모 클래스 객체 참조 불가)
  • 객체지향 프로그래밍의 유연성, 재활용성, 유지보수성의 기본
  • 대표적으로 오버라이딩, 오버로딩이 있다.

참조변수의 타입변환

자동 타입변환
부모타입 변수 = 자식타입객체; -> 부모타입객체로 자동 타입변환.

  • 자식 객체는 부모 객체의 멤버를 상속받기 때문에 부모와 동일하게 취급 된다.
  • 부모에게 상속받은 멤버에게만 접근 할 수 있다.
  • 상위클래스 형태로 형변환 되더라도 Override된 자신의 기능은 잃지 않는다.
class Human{
    public void info(){
        System.out.println("사람사람");
    }
}

class Female extends Human{
public void pregnancy(){
System.out.println("임신하다");
}

@Override
public void info(){
    System.out.println("여성여성");
}

}

public class Main{
public static void main(String[] args){
//참조변수 자동 타입변환
Human human = new Female();

    human.info();
    //human.pregnamcy(); //error 부모타입에 없는 메서드라 사용 불가
}

}

👍실행결과
여성여성


> ** 강제 타입변환 **
> `자식타입 변수 = (자식타입)부모타입객체;` 
> 부모타입객체 -> 자식타입은 자동 타입변환이 일어나지 않기 때문에 형변환 연산자를 사용하여 강제로 변환할 수 있다.
> - 자동타입변환이 일어난 객체만 강제 타입변환이 가능하다.
> - 부모타입 변수로는 자식타입의 고유 멤버를 사용 할 수 없기 때문에 자식 멤버의 사용이 필요한 경우 강제 타입변환을 사용한다..
 ```java
class Human{
    public void info(){
        System.out.println("사람사람");
    }
}
class Female extends Human{
    public void pregnancy(){
        System.out.println("임신하다");
    }

    @Override
    public void info(){
        System.out.println("여성여성");
    }
}
public class Main{
    public static void main(String[] args){
        //참조변수 자동 타입변환
        Human human = new Female();
        human.info();

        //femele의 pregnancy 사용하고 싶어짐 강제타입변환
        Female female = (Female) human;
        female.pregnancy();

        //ClassCastException 발생 자동타입변환 x 인 부모객체를 자식타입 변수로 강제 타입 변환 하려 했기 때문에.
        Human human2 = new Human();
        Female female2 = (Female) human2;
    }
}
👍실행결과
여성여성
임신하다

instanceof 연산자

  • 객체 타입 확인하는 연산자
  • 대상객체 instanceof 클래스명 으로 사용 boolean값을 반환해준다.
<// 다형성
class Parent { }
class Child extends Parent { }
class Brother extends Parent { }


public class Main {
    public static void main(String[] args) {

        Parent p = new Parent();

        System.out.println(p instanceof Object); // true 출력
        System.out.println(p instanceof Parent); // true 출력
        System.out.println(p instanceof Child);  // false 출력

        Parent c = new Child();

        System.out.println(c instanceof Object); // true 출력
        System.out.println(c instanceof Parent); // true 출력
        System.out.println(c instanceof Child);  // true 출력
    }
}

포함(composite)관계

클래스의 멤버로 참조변수를 선언하는 것

  • 작은 단위의 클래스를 만들고 조합해서 클래스를 만든다.
  • 클래스를 다른 곳에서 재사용 할 수 있다.

📝예시

class Engine {
    int capacity;
    String fuel;
    Engine(int capacity, String fuel) {
        this.capacity = capacity;
        this.fuel = fuel;
    }
}

class Car {
    Engine e = new Engine; //Car class가 Engine class를 포함하고 있다
    String model;
}

👍상속과 포함 구별 법

· 상속 관계 : is-a (~은 ~이다)로 표현
· 포함 관계 : has-a (~은 ~을 가지고 있다)로 표현

오버라이딩

오버라이딩이란? 부모에게 상속받은 메서드를 자신에 맞게 변경한는것
1. 선언부(반환타입,메서드명,매개변수목록)가 부모 클래스읭 메서드와 일치해야 한다.
2. 접근 제어자를 부모 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
3. 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.

📝예시

class Car {
    public void horn() {
        System.out.println("부모 빵빵");
    }
}

class SportsCar extends Car {
    @Override // 메서드 오버라이딩
    public void horn() {
        System.out.println("자식 뿡뿡뿡");
    }
}

public class Main{
    public static void main(String[] args){
        Car car = new Car;
        SportsCar sportsCar = new SportsCar();

        car.horn();
        sportsCar.horn();
    }
}

👍실행 결과

"부모 빵빵"
"자식 뿡뿡뿡"
  • 같은 메서드를 호출했지만 자식이 메서드를 오버라이딩 하여 재정의 했기 때문에 다른 결과를 출력한다.

오버라이딩 vs 오버로딩

오버로딩(overloading) : 기존에 없는 새로운 메서드를 정의하는 것(new) / 이름이 같은!
오버라이딩(overriding) : 상속받은 메서드의 내용을 변경하는 것(change, modify)


0개의 댓글