1. 상속이란? ★ → 다형성 쓰려고 상속함
기존에 존재하는 클래스로부터 필드와 메소드를 이어받고, 필요한 기능을 추가할 수 있는 기법 * 다중 상속(여러개의 클래스로부터 상속받는 것)을 지원하지 않는다.
1-1. 왜 쓰나?
2. 상속 예시
<기존에 존재하는 클래스 Animal>
Animal의 필드와 메소드를 Dog 클래스에 적지 않아도 '상속' 받으면 나온다.
위와 같이 Animal은 new하지 않고, Dog만 new 했는데도 Animal의 필드, 메소드를 쓸 수 있음 (= eat은 원래 Dog클래스에 없는데도 호출 할 수 있음)
3. Super (this랑 비슷? 상속에서 쓰는 this?)
상속 관계에서 자식 클래스는 부모 클래스한테 접근할 때 super를 사용. > super덕에 부모 클래스의 생성자, 메서드, 인스턴스 변수에 접근 가능 부모 클래스의 멤버를 호출하거나 재정의하기 위함!
부모 클래스의 메소드를 완전히 대치하는 경우보단 내용을 추가하는 경우에 super 사용.
즉, 부모 클래스 메소드 먼저 출력 > 자식 클래스 메소드 출력하는 경우 사용 (예시 참조)
<super 예시 보기>
package ex06; class Shape { int x, y; public Shape() { System.out.println("Shape 생성됨"); } } class Circle extends Shape { //Circle은 Shape의 자식 int radius; //반지름 public Circle(int radius) { // Circle class의 super(); 생략. 부모클래스의 기본 생성자를 호출하는 역할 System.out.println("Circle 생성됨"); this.radius = radius; System.out.println("1"); super.x = 0; //자식은 부모 필드?한테 접근할 때 super를 씀 super.y = 0; } double getArea() { return 3.14 * radius * radius; } } public class CircleTest { public static void main(String[] args) { Circle circle = new Circle(10); // Circle 클래스의 생성자를 호출하는 코드 // circle.getArea(); > 해당코드는 출력 불가능 System.out.println(circle.getArea()); } }
- Circle을 new하면 heap에 원래 Circle만 뜬다.
- 하지만 부모를 상속 받으면 부모의 생성자를 먼저 호출 (super) 하기 때문에 shape를 heap에 먼저 띄움.
- shape 생성자가 다 뜨면, Circle의 매개변수 값이 들어오면서 15번 라인(System.out.println("Circle 생성됨");) 부터 쭉 실행됨.
- 이렇게 해야만 (부모 클래스 Shape가 (super) 메모리에 먼저 생성) x랑y 값을 넣을 수 있음.
<생성자 호출 순서>
부모 클래스의 생성자 → 자식 클래스의 생성자
* 왜 그러나? 부모 클래스에서 상속된 부분을 먼저 초기화하기 위함!
디폴트 생성자와 생성자 두개가 있을때 new를 하면 부모의 디폴트 생성자를 호출함!!
4. super 호출
원래 extends 되어있을 때는 super가 생략되어있음
명시적인 호출 (=무엇을 명확하게 표현하거나 밝히는 것)
개발자가 코드 상에서 명시적으로 super()를 작성하여 부모 클래스의 생성자를 호출하는 것
class Parent { public Parent() { System.out.println("Parent의 기본 생성자"); } public Parent(int value) { System.out.println("Parent의 매개변수가 있는 생성자: " + value); } } class Child extends Parent { public Child() { super(); // 명시적으로 부모 클래스의 기본 생성자 호출 System.out.println("Child의 기본 생성자"); } public Child(int value) { super(value); // 명시적으로 부모 클래스의 매개변수가 있는 생성자 호출 System.out.println("Child의 매개변수가 있는 생성자: " + value); } } public class Main { public static void main(String[] args) { Child child1 = new Child(); // Child의 기본 생성자 호출 System.out.println("------"); Child child2 = new Child(10); // Child의 매개변수가 있는 생성자 호출 } }
자식 클래스에서
super(value);
라고 쓴 것은
부모 클래스의 매개변수 이름이 value
이기 때문이렇게 부모 클래스에 2개의 생성자가 정의되어 있으면 (기본생성자, 생성자)
자식 클래스에서 명시적으로 super(); 나 super(value); 중 선택해서 호출할 수 있다.
묵시적인 호출 (=부모 클래스의 기본 생성자를 호출하는 경우)
자식 클래스의 객체가 생성될 때, 자동으로 부모 클래스의 기본 생성자가 호출 됨. 자바에서 생성자를 호출할 때, 부모 클래스의 기본 생성자를 호출하는 경우에는 명시적으로 super()를 작성하지 않아도 자동으로 부모 클래스의 기본 생성자가 호출
class Parent { public Parent() { System.out.println("Parent의 기본 생성자"); } } class Child extends Parent { public Child() { //super(); 생략 System.out.println("Child의 기본 생성자"); } } public class Main { public static void main(String[] args) { Child child = new Child(); // Child의 기본 생성자 호출 } }
//결과
호출 시, 에러 발생 예시
묵시적인 부모 클래스 생성자 호출을 사용하려면 부모 클래스에 기본 생성자가 반드시!! 정의되어 있어야 한다. 만약 기본 생성자가 정의되어있지 않으면 오류 발생!! > 생성자에서 배웠던 것처럼, 매개변수 생성자가 있다면 자동으로 기본 생성자를 만들지 않는다. 즉, super();도 자동으로 생성되지 않는 것!
부모 클래스에 기본 생성자가 존재하지 않아서 에러 발생!
기본 클래스를 만들어주니 정상 작동!
5. 예문
상속과 생성자 예문
package ex06; class Person { String name; //기본 생성자 public Person() { } //생성자 public Person(String theName) { this.name = theName; } } class Employee extends Person { String id; //기본 생성자의 명시적 호출 public Employee() { super(); } //생성자의 명시적 호출 public Employee(String name) { super(name); } //생성자의 명시적 호출2 public Employee(String name, String id) { super(name); //부모 클래스의 name을 쓰겠다고 선언했잖아 ㅠ (super(name); == this.name = theName;) this.id = id; } @Override public String toString() { return "Employee{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; } } public class EmployeeTest { public static void main(String[] args) { Employee e = new Employee("Kim", "20210001"); System.out.println(e); } }
* super(name); 라고 해서
public Person(String theName) {
this.name = theName;
}
생성자가 호출된 것. super(name, id)라고 했으면 호출 할 부모 생성자가 없어서 에러!
ChatGPT
같은 결과값 코드 (theName 삭제)
package test; class Person { String name; public Person() { } public Person(String theName) { // this.name = theName; } } class Employee extends Person { String id; public Employee() { super(); } public Employee(String name) { super(name); } public Employee(String name, String id) { this.name = name; this.id = id; } @Override public String toString() { return "Employee{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; } } public class EmployeeTest { public static void main(String[] args) { Employee e = new Employee("Kim", "20210001"); System.out.println(e); } }
+ 추가
package test; class Person { String name; public Person() { } public Person(String theName) { this.name = theName; System.out.println("나다"); } } class Employee extends Person { String id; public Employee() { super(); } public Employee(String name) { super(name); } public Employee(String name, String id) { super(name); this.id = id; } @Override public String toString() { return "Employee{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; } } public class EmployeeTest { public static void main(String[] args) { Employee e = new Employee("Kim", "20210001"); System.out.println(e); } }
6. super 와 this
super는 상속. 부모를 가리킴 this는 같은 클래스 내, 메서드의 매개변수와 필드 변수명이 같을 때, 필드(heap, 자기자신)라고 표시
자식 클래스의 메소드는 부모 클래스의 메소드보다 더 제한적일 수 없다!
부모의 접근지정자가 public 이면 자식도 public 이어야 함.
[ final ] 로 선언된 클래스는 부모 클래스가 될 수 없다.
final 키워드는 클래스, 메서드 또는 변수에 사용될 수 있으며,
해당 요소를 상속하거나 오버라이딩할 수 없음을 나타냅니다.
Share article