상속Inheritance

코코·2020년 7월 26일
0

Java

목록 보기
5/25

📚 자바의 정석을 정리한 내용입니다.

상속Inheritance

기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것이다.

코드를 공통적으로 관리할 수 있기 때문에 유지보수 하기 쉽다.

class Child extends Parent {
	//...
}

extends만으로 간단하게 상속 받을 수 있다.

상속해주는 클래스Parent를 조상 클래스, 상속을 받는 클래스Child를 자손 클래스라고 한다.

이 두 관계를 상속관계라고 부른다.

출처 : https://www.javatpoint.com/inheritance-in-java

조상클래스는 자손 클래스가 변경 되어도 영향을 받지 않지만,

조상클래스가 변경되면 자손 클래스는 영향을 받는다.

자손 클래스는 조상 클래스의 모든 멤버를 상속 받는다. 따라서 항상 조상 클래스보다 같거나 많은 멤버를 갖는다. 상속에 상속을 거듭한다면, 멤버는 점점 확장(extends)된다. 그래서 상속을 이용한다는 것은 즉 조상 클래스를 확장extends한다는 의미이기도 하다.

자바는 단일상속만 가능하다. 두 개의 클래스를 동시에 extends할 수 없다.

필요하다면 인터페이스나 포함관계를 이용하면 된다.

포함관계

한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것을 뜻한다.

class ArcReactor{
	//...
}
class TonyStark{
	ArcReactor arc = new ArcReactor();
}

class Ironman() {
	TonyStark tony = new TonyStark();
}

위와 같이 단위별로 여러 개의 클래스를 포함해서 더 큰 클래스를 만들어낼 수 있다.

프로젝트 진행할 때 extends는 한 번도 사용하지 않았지만 포함관계는 수도 없이 많이 사용했다.

Object

Object는 모든 클래스의 조상이다. 아무것도 상속받고 있지 않은 클래스도 결국 Object를 상속받고 있다. toString()이나 equals() 같은 메서드는 모두 Object의 메서드다.

오버라이딩Overriding

상속 받은 메서드의 내용을 변경하는 것을 오버라이딩이라고 한다.

class CarCompo {
	String color;
	String gearType;
	int door;

	/*Object클래스의 toString()을 오버라이딩해서 사용*/
	@Override
	public String toString() {
		return "CarCompo [color=" + color + ", gearType=" + gearType + ", door=" + door + "]";
	}
}

이클립스 기준 alt + shift + s → Override/implements Methods를 누르면 쉽게 오버라이드 할 수 있다.

@Override 어노테이션은 혹여 오버라이딩을 잘못 했을 경우를 대비해 항상 붙이는 것이 좋다.

오버라이딩이 잘못되었다고 바로 빨간 줄을 그어주니까.

오버라이딩 조건

  • 이름이 같아야 한다
  • 매개변수가 같아야 한다
  • 반환타입이 같아야 한다
  • 접근 제어자를 좁은 범위로 변경할 수 없다.
  • 원래 메서드보다 많은 예외를 선언할 수 없다.

오버라이딩과 오버로딩은 이름만 비슷할 뿐 동료가 아니다.

오버로딩 : 기존에 없는 새로운 메서드를 정의하는 것(new)

오버라이딩:상속 받은 메서드를 변경하는 것(modify)

super

super는 일종의 this다. 상속받은 멤버와 자신의 멤버 이름이 같을 때 super를 붙여서 구분한다.

코드를 보면 이해가 쉽다.

public class Super {
	public static void main(String[] args) {
		Child child = new Child();
		child.method();
	}
}

class Parent {
	int x = 10;
}

class Child extends Parent {
	int x=20;
	
	void method() {
		System.out.println("x : " + x);
		System.out.println("this.x : " + this.x); //자신(Child)을 가리키는 this.
		System.out.println("super.x : " + super.x);//부모(Parent)를 가리키는 super.
	}

/*
결과 : 
x : 20
this.x : 20
super.x : 10
*/

super는 toString()을 오버라이딩 할 때 super.toString() + 자손 클래스의 인스턴스 변수 출력

하는 식으로 써봤던 것 같다. 나중에는 lombok을 쓰니 거의 사용할 일이 없긴 했다.

super()

조상 클래스의 생성자를 호출할 때 쓴다.

생성자 첫 줄에서 사용해야 한다. 이유는 자손클래스의 멤버가 조상클래스 멤버를 사용할 수도 있으므로, 조상클래스의 멤버를 미리 초기화 해두어야 하기 때문이다.

Oject클래스를 제외한 모든 클래스의 생성자 첫 줄에 this() 또는 super()를 호출해야 한다. 그렇지 않으면 컴파일러가 자동으로 생성자 첫 줄에 삽입한다.

인스턴스를 생성할 때는 이 두가지를 고려해야 한다.

  1. 어떤 클래스의 인스턴스를 생성할 것인가?
  2. 해당 클래스의 어떤 생성자를 이용해서 만들 것인가?
public class Point {
	public static void main(String[] args) {
		Point3D p3 = new Point3D();
		System.out.println("p3.x : " + p3.x);
		System.out.println("p3.y : " + p3.y);
		System.out.println("p3.z : " + p3.z);
	}
}

class PointXY {
	int x = 10;
	int y = 20;
	
	PointXY(int x, int y) {
		//super(); == Object()
		this.x = x;
		this.y = y;
	}
}

class Point3D extends PointXY {
	int z = 30;
	
	Point3D() {
		this(100, 200, 300);	//Point3D(int x, int y, int z) 호출
	}
	
	Point3D(int x, int y, int z) {
		super(x, y); //	PointXY(int x, int y) 호출
		this.z = z;
	}
	
}

/*
결과 : 
p3.x : 100
p3.y : 200
p3.z : 300
*/

0개의 댓글