Java 기초 : Inheritence, Polymorphism, Overriding, Casting

soir·2021년 2월 18일
0

Java

목록 보기
2/3

Inheritance(상속)

자바에는 여러 클래스들이 있는데, 이 클래스의 가장 위에 위치하는 최상위 클래스 Object가 있다. 자바의 모든 클래스들은 Object 클래스를 상속받게 된다. Object 클래스는 lang 패키지에 위치한다. 따라서 import 시 import java.lang.Object를 통해 추가할 수 있으나, 모든 클래스들은 Object 클래스를 상속받으므로 따로 명시할 필요는 없다.

상속 시에는 child extends parent와 같은 형식으로 extends 명령어를 사용하여 상속받는다. 자식 클래스가 앞, 부모 클래스가 뒤에 위치하게 된다.

*Java는 단일 상속을 지원하고 있다. 다중 상속을 지원할 경우, 상속받는 두 부모 클래스에 동일한 이름의 메소드가 존재할 경우 자식 클래스는 이를 구분할 수 없게 된다(Diamond Issue). 같은 객체 지향 프로그래밍 언어인 C++에서는 다중 상속을 지원하고 있다.

결론적으로, 자식 클래스는 부모 클래스보다 더 많은 요소를 가지게 된다(부모-자식으로 생각하여 혼동하는 경우가 종종 있음).

Object 클래스의 주요 메소드

toString()
객체 정보(해시값)를 문자열으로 반환한다. 해시값을 반환하므로 해당 메소드를 자식 클래스에서 재정의할 경우 데이터를 원하는 형태로 반환하는 것이 가능하다.

hashCode()
해시코드를 리턴한다. 해시코드(HashCode)는 데이터가 메모리에 위치할 때 정해지는 고유 주소와 같다.

equals()
객체 데이터 값이 아닌 객체 해시코드를 비교한다. 따라서 equals()를 if(a instanceof b)와 같은 코드로 두 객체가 형식이 같은지 비교하고, downCasting 한 후 데이터 값을 비교하는 식으로 오버라이딩하여 사용할 수 있다.

  • instanceof 연산자 : 객체의 data type(클래스)이 같은지 확인할 수 있다.

+) equals관련 추가

객체를 == 연산자를 사용하여 비교할 경우 객체의 주소값을 비교하게 된다. 그러나 모든 객체는 생성 시 고유의 주소값을 가지므로, 모든 객체는 서로 다른 주소값을 가져 항상 false값을 리턴하게 된다.

따라서 객체 비교 시에는 Object 클래스의 equals() 메소드를 사용한다. 그러나 실제로 main() 클래스에서 임의로 두 String 객체를 생성해 equals로 비교할 경우 false를 반환한다. 이는 메소드 오버라이딩으로 해결 가능하다.

Override

부모 클래스를 상속받은 자식 클래스는 부모 클래스에 들어있던 메소드의 사용이 가능하다. 이 때 이 메소드를 자식 클래스에서 내용을 재정의하여 사용할 수 있다. 이를 덮어쓰기, 즉 오버라이드(Override)라고 한다.

*오버로딩Overloading과 오버라이딩의 차이점 : 오버로딩은 생성자 및 메소드를 이름이 같고, 파라미터의 타입이나 개수만 다르게 하여 여러 개 생성하는 것을 뜻한다. 오버라이딩과 이름이 비슷해 혼동하기 쉽다.

Polymorphism(다형성)

상속의 개념을 생각해보면, 부모 클래스는 하나만 존재할 수 있으나 자식 클래스는 여러 개가 존재 가능하다. 예를 들어 자식 클래스가 여러 개 존재할 경우, 이 자식 객체들을 한 배열에 넣는 것은 불가능하다. 그러나 자식 클래스를 포괄하는 개념의 부모 클래스로 배열 타입을 정의할 경우, 자식 객체를 배열에 넣을 수 있게 된다. 이러한 개념을 다형성으로 정의한다.
다형성 개념을 통해 코드를 절감할 수 있다.

Casting

Cat[] cats = new Cat[3];
cats[0] = new Cat();
cats[1] = new Dog();
cats[2] = new Lion();

이처럼 서로 다른 타입의 객체들을 한 객체 타입의 배열에 넣을 경우 에러가 발생하게 된다.

UpCasting

Animal[] animals = new Animal[3];
animals[0] = new Cat();
animals[1] = new Dog();
animals[2] = new Lion();

그러나 Cat, Dog, Lion 객체들이 모두 Animal 클래스를 상속받을 경우, Animal 배열에는 이 세 가지 객체들을 모두 넣을 수 있다. 즉 Animal이라는 타입은 Cat, Dog, Lion 세 가지 객체를 포괄 가능한 상위 타입이다.

그리고 이 자식 객체들은 상위 타입 배열에 들어가게 되며 자동으로 상위 타입인 Animal 객체로 형변환하게 된다. 이를 업캐스팅 Upcasting이라고 하며, 업캐스팅 시에는 형변환(캐스팅) 표시의 생략이 가능하다.

DownCasting

Class Cat에 다음과 같이 grooming()이라는 메소드가 존재한다고 가정해 보자.

public class Cat extends Animal{
	public void grooming() {
		System.out.println("야옹");
	}
}

animals[0]에는 new Cat() 생성자를 통해 업캐스팅 된 Cat 객체가 들어가 있다. 이 객체가 grooming() 메소드를 사용할 경우 에러가 발생하게 된다. 해당 객체는 Animal 배열을 들어가며 Animal 타입으로 업캐스팅되었기 때문이다.

따라서 grooming()을 사용하려면 다음과 같이 다시 Cat 객체로 형변환하는 작업이 필요하다. 이 때 Cat 클래스는 Animal의 하위 타입이므로, 이를 다운캐스팅DownCasting이라고 한다.

animals[0].grooming(); // error
Cat c1 = (Cat)animals[0];
c1.grooming();

다운캐스팅의 경우 (Cat)animals[0]과 같이 캐스팅 형식을 표기해주어야 한다. (생략 불가)

profile
에러 뜨면 우는 사람

0개의 댓글

관련 채용 정보