다잘하고싶어

자바 : 상속과 다형성 본문

이론학습/JAVA

자바 : 상속과 다형성

챙영잉 2023. 1. 25. 16:17

상속 Inheritance

= 어떤 클래스의 특성을 그대로 갖는 새로운 클래스를 정의하는 것.

  • 클래스(설계도)의 상속
    • 무엇이 상속될까?
    • (1) 멤버변수, (2)메서드
  • 목적 → 기존의 설계도를 재사용하기 위함
  • 장점 → 개발시간 단축
  • 상위클래스, 부모클래스, super class
  • 하위클래스, 자식클래스, sub class
public class Person {
	String name;
	int age;
	
	public void eat() {
		System.out.println("음식을 먹는다");
	}
}//Person

-------
public class Student {
	String name;
	int age;
	
	public void eat() {
		System.out.println("음식을 먹는다");
	}
	public void study() {
		System.out.println("공부를 한다");
	}
}//Student

⇒ 위의 코드를 상속을 이용해 아래와 같이 만들 수 있다.

public class Person {
	String name;
	int age;
	
	public void eat() {
		System.out.println("음식을 먹는다");
	}
}//Person

-------

public class Student extends Person{  
	
	String major;
	
	public void study() {
		System.out.println("공부를 한다");
	}
}

 

⇒ 동일한 결과 나옴

 

(+) 옆에 어떤 클래스에 속한 변수와 메서드인지 확인할 수 있다.

(+) Object 클래스란?

→ 모든 클래스는 Object 클래스를 상속받는다.

상속의 특징

  • 확장성, 재사용성
    • 부모의 생성자와 초기화 블록은 상속되지 않는다.
  • 클래스 선언 시 extends 키워드를 사용한다
    • 자바는 다중 상속을 허용하지 않는다!
    • 단일 상속만 가능.
    • 왜?
    • 모호성 문제
     

  • 자식클래스는 부모클래스의 멤버변수와 메소드를 자신의 것처럼 사용할 수 없다.
    • 단 접근 제한자에 따라 사용 여부가 달라진다 ( 아래의 그림 참조)
     

  • Object 클래스는 모든 클래스의 조상 클래스

super 키워드

  • super() 클래스를 통해 조상클래스 생성자 호출
  • super.멤버변수
  • super.메서드();

 

Person 클래스

public class Person {
	String name;
	int age;
	 
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public void eat() {
		System.out.println("음식을 먹는다");
	}

}

Student 클래스

public class Student extends Person{  
	
	String major; 
	
	public Student(String name, int age, String major) {
		super(name, age); //부모클래스의 생성자를 호출
		this.major = major;
	}

	
	public void study() {
		System.out.println("공부를 한다");
	}
}

Test 클래스

public class Test {
	public static void main(String[] args) {
		Student st = new Student("김미미",11,"자바");

	}
}

 

오버라이딩 Overriding (재정의)

  • 자식클래스에서 부모클래스의 메서드를 재정의하는 것
 annotation 어노테이션 : 컴파일러가 읽는 주석
→ 어노테이션이 필요한 이유?
→ 오타가 났을 때 알려준다.
→ eat() 을 오버라이딩 했는데 부모클래스에 eat() 이 없다면? 알려준다!
  • 메서드의 이름, 리턴타입, 매개변수(타입, 개수, 순서)가 동일해야한다.
  • 하위 클래스의 접근제어자 범위가 상위클래스보다 크거나 같아야 한다.
    • 부모가 공개한 것을 자식이 숨길 수 없다
  • 조상보다 더 큰 예외를 던질 수 없다.
  • 메서드 오버로딩과 혼동하지 않도록 주의하기.

Object 클래스

  • 가장 최상위 클래스로 모든 클래스의 조상
  • Object의 멤버는 모든 클래스의 멤버

equals()

  • 원래 equals 는 두 객체의 주소값을 비교한다
  • 그러나 String 클래스에서 equals 를 문자열의 값을 비교하도록 재정의 되어있다.
  • 따라서 문자열의 값을 비교할 때는 equals() 메서드를 사용한다.

hashCode

  • 객체의 해시코드 : 시스템에서 객체를 구별하기 위해 사용되는 정수값
  • HashSet, HashMap 등에서 객체의 동일성을 확인하기 위해 사용
  • 해시값의 트징
    • 2개의 객체가 동일 → 같은 해시값
    • 2개가 같은 해시값 → 두 개가 동일할 수도 있고, 아닐수도 있다.
    • Set 집합에는 중복된 값이 들어가지 않는다.
    • 그렇다면 동일성을 어떻게 확인할까?
    • equals() 메서드와 해시값을 둘 다 확인한다.

student 클래스

@Override
	public boolean equals(Object obj) {
		return name.equals(((Student)obj).name);
	}

Test 클래스

 

	Set<Student> set = new HashSet<>();
	    set.add(st);
	    set.add(st22);
	    
	    System.out.println(set.size());

  • 이름만 같다면 같다고 했는데 왜 set.size()의 결과값이 2가 나올까?
  • set 에서는 equals 와 해시코드 둘 다 비교하기 때문이다
  • 해시코드까지 재정의 해야 size 가 1이 나온다.

final

  • final 클래스 : 상속 금지
  • final 메서드 : 오버라이드 금지
  • final 변수 : 상수 값

다형성

  • 다형성이란 (많을다, 형상형) 다양한 형상을 가질 수 있는 성질
  • 상속 관계에 있을 때 조상 클래스 타입으로 자식 클래스 객체를 참조할 수 있다.
  • 상속 관계에 있을 때 부모 클래스의 타입으로 자식 클래스 객체를 참조할 수 있다.
    • 자식클래스의 타입을 부모클래스가 참조할 수는 없다! ( 부모가 더 큰 범위 )

활용

  • 다른 타입의 객체를 다루는 배열

  • 매개변수의 다형성
    • 원래 다른 파라미터를 사용하기 위해서는 메서드 오버로딩을 해야한다. 만약 매개변수의 타입을 부모클래스로 지정한다면 오버로딩 없이, 다양한 자식클래스를 매개변수로 활용할 수 있다.
    • 파라미터로 Object를 설정해두면 모든 객체를 처리할 수 있다.
     

→ Student 객체에 있는 major 은 보이지 않는다. 왜?

부모클래스로 참조할 수있지만 부모클래스의 관점에서 보기 때문에 접근가능한 범위가 달라진다.

⇒ 형변환을 해줘야 한다!

 

형변환

  • 작은집(child)에서 큰집(super) 으로 ⇒ 묵시적 캐스팅
    • 자손 타입의 객체를 조상타입으로 참조 : 형변환 생략 가능
  • 큰집(super) 에서 작은집(child)으로 ⇒ 명시적 캐스팅
  • 참조형 객체의 형변환

명시적 캐스팅의 주의할 점 → 무늬만 형변환 한 것

조상을 무작정 자손으로 바꿀 수 없다.

⇒ 형변환하기 전 후, 사용가능한 필드가 다름.

student 에만 있는 study(), 명시적 형변환 했으므로 사용은 가능하다. 단?

 

>> 사용은 할 수 있지만 , 실제 메모리 상에 없기 때문에 에러가 난다.

실습코드

SuperClass 클래스

public class SuperClass {
	String x = "super";
	public void method() {
		System.out.println("superclass method");
	}

}

SubClass 클래스

public class SubClass extends SuperClass{
	String x = "sub";
	 
	public void method() {
		System.out.println("subclass method");
	}

}

Test 클래스

public class Test {
	public static void main(String[] args) {
		SubClass child = new SubClass();
		System.out.println(child.x);
		child.method();
		
		SuperClass parent = child;
		System.out.println(parent.x);
		parent.method(); 
	}

}