6주차 과제. 자바의 상속에 대해 학습하세요.

Jiwon·2022년 8월 13일
0

JAVA

목록 보기
4/4

학습할 것

  • 자바 상속의 특징
  • super 키워드
  • 메소드 오버라이딩
  • 다이나믹 메소드 디스패치 (Dynamic Method Dispatch)
  • 추상 클래스
  • final 키워드
  • Object 클래스

자바 상속의 특징

상속 ( Inheritance )

Class 설계 시 특정 class 를 상속받아 그 class의 Data(변수)와 Method(기능)를 사용하는 것.

타입만 가져가려면 interface 구현
타입 + 구현(속성, 메소드) 까지 하려면 class 상속 사용

  • Generalization : 추출된 class 들의 공통적인 특성을 모아 super class 로 정의 가능
  • Specialization : 비슷한 속성과 기능을 가지고 있는 다른 class를 상속 받아 새로운 class 를 정의할 수 있다.

선택적 상속 불가능 -> All / Not 만 가능

  • 상속되는 클래스의 속성이나 기능을 선택적으로 상속받을 수 없다. 전부 다 받거나, 아예 안받거나 둘 중 하나만 가능하다.
  • 상속을 받게 되면 super 클래스의 모든 속성과 기능을 상속받아 사용 가능

생성자는 상속되지 않는다.

super 클래스에서 private 으로 정의된 member 변수는 상속은 가능하지만, 접근은 불가능하다. -> 그래서 public 으로 선언한 setter 또는 getter 를 이용한다.

상속 받은 기능 중 수정을 원하는 기능은 다시 재정의 할 수 있고 (Overriding),
필요한 속성이나 기능은 추가하여 작성할 수 있다.

객체 생성의 경우에는 재사용만 가능하고, 변경, 추가는 불가능하다.

단일 상속만 가능 (Single Inheritance)

  • 여러 조상들 중에서 이름이 같은 함수가 있을 경우, 문제의 소지가 있다.
    자바는 시스템에 문제가 생길 가능성을 아예 남겨두지 않으려고 하기 때문에 지원하지 않는다.

  • 너무 무겁다. 필요 없는 부분까지 받아야 한다.
    그러나 다중 상속의 장점 또한 많아서, 자바는 interface 다중 구현을 제공한다.

생성자는 상속되지 않는다.

  • 왜 상속되지 않을까
    생성자는 반드시 클래스 이름과 동일하게 써야 하는데, 상속하면 클래스 이름이 달라지므로 클래스 이름과 동일하게 사용할 수 없어진다.

  • 그러나 재사용을 하기 위해서 호출은 가능하다.(상속되는게 아니라 호출만 된다. super(a,b,c) 이런 식)
    이때는 반드시 첫 줄에서만 가능하다.

Super

현재 수행중인 객체의 상위 객체(super)의 reference를 가지고 있다.

  • super.멤버면수
    상속받은 멤버 변수 호출 시, 현재 수행중인 객체의 멤버변수와 상속받은 super 객체의 멤버변수 이름이 동일할 경우 사용.

  • super.method()
    상속받은 메서드 호출 시, 현재 수행중인 객체의 메서드명과 상속받은 super 객체의 메서드명이 동일할 경우 사용.

  • super(parameter_list)
    parameter_list 가 동일한 super 객체의 생성자를 호출한다.
    (단, 부모 클래스의 생성자는 자식 클래스의 생성자의 1. 첫 라인에서 2. super()로만 접근 가능하고, 3. this 와 함께 사용할 수 없다.)

상속 시 생성자 문제 나는 경우

class Solution {
	public static void main(String[] args) {
    	Bus bus = new Bus("abc", 1000, 1000);
    }
}

class Car {
	String name;
    int number;
    public Car(String name, int number){
    	this.name = name;
        this.number = number;
    }
}

class Bus extends Car {
	int fee;
    public Bus(String name, int number, int fee){
    	this.name = name;
        this.number = number;
        this.fee = fee;
    }
}

위 코드는 실행 시 오류가 난다.

  • 생성자의 기본 전제
    사용자가 생성자를 만들지 않으면, 컴파일러가 default 생성자로 내용과 인자 모두가 자동으로 빈 public Car() {} 이런 생성자를 만들어준다.
    만약 사용자가 생성자를 오버로딩해서 인자가 있는 생성자를 새로 만든다면, 컴파일러는 비어있는 생성자를 자동으로 만들어주지 않는다.

Car 클래스를 상속받은 Bus클래스의 생성자를 부르면 Bus 생성자는 사용자가 super(); 를 명시적으로 삽입하지 않아도 super(); 라는 내용을 자동으로 삽입한다.
즉, Car 클래스의 기본 생성자를 부르는 것이다.

그런데 위의 코드를 따라하면
Car 클래스에서는 인자 있는 생성자가 이미 정의되어 있어서 인자 없는 기본 생성자가 자동으로 생성되지 않는다.
그래서 컴퓨터 입장에서는 생성자가 없다고 생각해서 오류가 난다.

  • 해결 방법
  1. 부모의 인자 없는 생성자가 불리지 않게 한다.
class Bus extends Car{
	int fee;
    public Bus(String name, int number, int fee) {
    	super(name, number);
        this.fee = fee;
    }
}
  1. 부모 클래스에 인자 없는 생성자를 추가해 준다
class Car() {
	public Car() {...}
}

Overriding

상속을 기반으로 super 로부터 상속받은 기능 중 특정 기능을 재정의 하는 기법

sub 클래스에서 overriding 되는 메서드는
1. 상속받은 super 클래스와 이름, 반환타입, 인자리스트가 반드시 같아야 한다.
2. 접근제어자는 같거나 넓은 범위를 가져야 한다.

https://buddev.tistory.com/59

다이나믹 메서드 디스패치(Dynamic Method Dispatch)

어떤 메서드를 호출할지 결정하여 실제로 실행시키는 과정

자바는 컴파일 시에는 생성할 객체 타입에 대한 클래스 정보를 보유하고, 런타임 시 객체를 생성한다.

따라서 상속 관계 클래스들이 오버라이딩된 메서드가 있으면 컴파일 시에는 클래스 정보만을 저장하기 때문에 아직 참조변수가 어느 객체의 주소를 저장할지는 안정해진 상태이다.
때문에 어느 객체의 메서드를 호출할지 모르게 된다.

정적 메서드 디스패치(Static Method Dispatch)

컴파일 시점에서, 컴파일러가 특정 메소드를 호출할 것이라고 명확하게 알고 있는 경우

class SuperClass{
	void printImp(){
    	System.out.println("SuperClass printImp호출");
    }
}

class Main{
	public static void main(String[] args){
    	new SuperClass.printImp();
    }
}

동적 메서드 디스패치(Dynamic Dispatch)

컴파일러가 컴파일 단계에서 어떤 메소드를 호출할지 모르는 경우이다.
이런 경우에는 런타임 시점에서 컴파일러가 알게 된다.

class SuperClass{
	void printImp(){
    	System.out.println("SuperClass printImp호출");
    }
}
class SubClass1 extends SuperClass{
	void printImp(){
    	System.out.println("SubClass2 printImp호출");
    }
}
class SubClass2 extends SuperClass{
	void printImp(){
    	System.out.println("SubClass2 printImp호출");
    }
}
class Main{
	public static void main(String[] args){
    	SuperClass superC1 = new SuperClass();
        SuperClass superC2 = new Sub1Class();
        SuperClass superC3 = new Sub2Class();
        
        superC1.printImp();		//SuperClass의 printImp 호출
        superC2.printImp();		//Sub1Class의 printImp 호출
        superC3.printImp();		//Sub2Class의 printImp 호출
    }
}

https://jddng.tistory.com/154

추상 클래스

추상화
공통의 속성이나 기능을 묶어 이름을 붙이는 것.

불필요한 정보는 숨기고 중요한 정보만을 표현한다.

자료의 추상화 : 객체지향 관점에서 클래스를 정의하는 것
추상클래스 : 여러 클래스간 비슷한 필드와 메서드를 공통적으로 추출해 만들어진 클래스
인터페이스 : 동일한 목적 하에 동일한 기능을 수행하게끔 강제하는 것

상속 관계 : ~는 ~이다. ==( is -a )
포함 관계 : ~는 ~을 가지고 있다. ==( has -a )

class Circle{
  int x;    // 원점의 x 좌표
  int y;    // 원점의 y 좌표
  int r;    // 원의 반지름
}
 
class Point{
  int x;    // x 좌표
  int y;    // y 좌표
}

원을 표현하기 위한 Circle 클래스와 좌표상의 한 점을 다루기 위한 Point 클래스.
-> Point 클래스를 재사용해서 Circle 클래스를 작성하면

class Circle{        // 포함 관계
  Point c = new Point;    // 원점 좌표
  int r;    // 원의 반지름
}
 
class Point{
  int x;    // x 좌표
  int y;    // y 좌표
}

////다른 방식

class Circle extends Point{        // 상속 관계
  int r;    // 원의 반지름
}
 
class Point{
  int x;    // x 좌표
  int y;    // y 좌표
}

어떤 관계로 맺어줄 것인지 헷갈리는데
이런 때는 is-ahas-a로 비교해가며 상황에 알맞게 설계한다.

"원(Circle)은 점(Point)이다."
"원(Circle)은 점(Point)을 가지고 있다."

추상클래스
여러 클래스간 비슷한 필드와 메서드를 공통적으로 추출해 만들어진 클래스

인터페이스
동일한 목적 하에 동일한 기능을 수행하게끔 강제하는 것

https://sdesigner.tistory.com/90

final 키워드

한 번 값을 넣어두면 절대 바뀌지 않는다.

클래스, 메서드, 변수 각각에 붙일 수 있따.

final 클래스

public final class MyFinalClass {...}    // final 클래스 선언

public class ThisIsWrong extends MyFinalClass {...} // 상속 불가!

final 이 붙어있는 클래스는 상속 불가능.
보안이나 효율성 측면에서 장점이 있어, java.lang.System 및 java.lang.String 처럼 자바에서 기본적으로 제공하는 라이브러리 클래스는 final을 사용한다고 한다.

final 메서드

public class Base
{
    public       void m1() {...}
    public final void m2() {...}    // final 메서드 선언
}

public class Derived extends Base
{
    public void m1() {...}  // Base 클래스의 m1() 상속
    public void m2() {...}  // 오버라이딩, 즉 상속받은 메서드 수정 불가!
}

만약 어떤 클래스를 상속하는데 그 안에 final 메서드가 있다면, 오버라이딩으로 수정할 수 없다.

final 변수

public class Sphere {

    // PI 변수는 상수로 선언되어 수정할 수 없음
    public static final double PI = 3.141592653589793;

    public final double radius;
    public final double xPos;
    public final double yPos;
    public final double zPos;

    Sphere(double x, double y, double z, double r) {
         radius = r;
         xPos = x;
         yPos = y;
         zPos = z;
    }

    [...]
}

final 변수는 한 번 값을 할당하면 수정할 수 없다.
즉, 초기화는 한 번만 가능하다.

blank fianl 변수

public class Test {
  // 선언만 하고 초기화는 각 인스턴스에서 진행
  private final int value;

  public Test(int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }
}

먼저 선언해놓고 각각 다른 값을 갖도록 초기화 할 수 있다.
물론 이렇게 한 번 값을 할당하면 다음부터는 수정할 수 없다.

static과 final을 같이 쓰는 경우가 많은데, 그 이유는 ?
static을 붙이면 메모리에 딱 한 번만 할당(같은 주소값을 공유)되어 메모리를 효율적으로 사용할 수 있는데, 어차피 같은 값을 계속 메모리 낭비할 필요없이 하나로 쭉 쓸 수 있다.

이렇게 static과 final을 같이 쓰면 효율성이 높아져서 자주 쓰인다고 한다.

https://makemethink.tistory.com/184

Object 클래스

자바에서 '최상의 클래스'
단순하게 모든클래스(API 또는 내가 만든 class 등)는 Object 클래스의 자식클래스.
Object 클래스에는 다양한 메소드가 존재하는데,
어떤 클래스에서도 이 메소드를 호출할 수 있다.

equals() 메소드

두 객체가 동일한 객체라면 true 리턴, 다르면 false 리턴

hashCode() 메소드

객체의 메모리 번지를 이용해서 해시코드를 만들어 리턴
객체마다 다른값을 가지고 있다.

toString() 메소드

객체의 문자 정보를 리턴
객체를 문자열로 표현

https://choseongho93.tistory.com/43

profile
과연 나는 ?

0개의 댓글