• 자식(하위, 파생) 클래스가 부모(상위) 클래스의 멤버를 물려받는 것
• 자식이 부모를 선택해 물려받음
• 상속 대상: 부모의 필드와 메소드
클래스의 갂결화
• 멤버의 중복 작성 불필요
클래스 관리 용이
• 클래스들의 계층적 분류
소프트웨어의 생산성 향상
• 부모 클래스 재사용해 자식 클래스 개발 속도 빠름
• 클래스 재사용으로 반복된 코드 중복 줄이고, 새로운 클래스 확장 용이
• 유지 보수 편리성 제공
상속 대상 제한
• 부모 클래스의 private 접근 갖는 필드와 메소드 제외
• 부모 클래스가 다른 패키지에 있을 경우, default 접근 갖는 필드와 메소드도 제외
- 자식 클래스가 상속할 부모 클래스를 지정하는 키워드
상속 횟수 무제한
상속의 최상위 조상 클래스는 java.lang.Object 클래스
• 모든 클래스는 자동으로 java.lang.Object를 상속받음
• 자바 컴파일러에 의해 자동으로 이루어짐
public class Point {
int x,y;
public Point() {
}
public void set(int x, int y) {
this.x = x;
this.y = y;
}
public void showPoint() {
System.out.println("(" + x + "," + y + ")");
}
}
public class ColorPoint extends Point{
private String color;
public void setColor(String color) {
this.color = color;
}
public void setColorAndPoint(String color, int x,int y) {
this.color = color;
// 자식 class에서 부모 class field 사용 가능
this.x = x;
this.y = y;
}
public void showColorPoint() {
System.out.print("Color = " + color +"," );
// 자식 class에서 부모 class의 method 사용 가능
showPoint();
}
}
-명시적인 부모 생성자 호출
-부모 객체 생성할 때, 부모 생성자 선택해 호출
• super(매개값,…)
– 매개값과 동일한 타입, 개수, 순서 맞는 부모 생성자 호출
• 부모 생성자 없다면 컴파일 오류 발생
• 반드시 자식 생성자의 첫 줄에 위치
• 부모 클래스에 기본(매개변수 없는) 생성자가 없다면 필수 작성
- super : heap memory 에 있는 Parent class의 instance
- this : heap memory에 있는 자기 자신의 instance
- 2.super(homePhoneNumber);
-부모 생성자 호출(본인의 다른 생성자 this(...);)
public class Parent {
int homePhoneNumber;
String name;
int age;
public Parent() {
System.out.println("Parent - default constructor호출");
}
public Parent(int homePhoneNumber) {
this.homePhoneNumber = homePhoneNumber;
System.out.println("Parent - (int homePhoneNumber) constructor호출");
}
}
public class Child extends Parent {
public Child() {
System.out.println("Child - default constructor호출");
}
public Child(int homePhoneNumber) {
super(homePhoneNumber);
System.out.println("Child - Child(int homePhoneNumber) constructor호출");
}
public void printParentInformation() {
super.name = "홍아버지";
super.age = 55;
System.out.println("Parent 이름 : " + super.name + ", 나이 : " + super.age );
}
}
• 메소드 재정의(@Override)
-부모 클래스의 상속 메소드 수정해 자식 클래스에서 재정의하는 것
• 메소드 재정의 조건
-부모 클래스의 메소드와 동일한 시그니처 가져야한다
• 접근 제한을 더 강하게 오버라이딩 불가
– public을 default나 private으로 수정 불가
– 반대로 default는 public 으로 수정 가능
• 새로운 예외(Exception) throws 불가(추후 예외처리에서 더 자세 다룸)
• @Override 어노테이션
-컴파일러에게 부모 클래스의 메소드 선언부와 동일한지 검사 지시
-정확한 메소드 재정의 위해 붙여주면 OK
• 메소드 재정의 효과
-부모 메소드는 숨겨지는 효과 발생
-재정의된 자식 메소드 실행
public class Shape {
public void paint() {
draw();
}
public void draw() {
System.out.println("Shape class draw");
}
}
public class Circle extends Shape {
@Override //annotation
public void draw() {
System.out.println("Circle class - draw()");
}
}
public class Line extends Shape {
@Override //annotation
public void draw() {
System.out.println("Line class - draw()");
}
}
public class Rect extends Shape{
@Override //annotation
public void draw() {
System.out.println("Rect class - draw()");
}
}
/*
* Method Overrides
* 1.부모 클래스의 메소드와 자식 클래스의 메소드의 시그니쳐가 동일한 경우만 해당
* 2.정의 : 부모에서 정의된 메소드가 있는데 자식이 동일한 메소드 시그니쳐를 만들어 정의하면
* 부모 클래스의 매소드를 호출하는 것이 아니라 자식 메소드를 호출하는 것을 뜻함
*/
public class MethodOverrideEx2 {
public static void main(String[] args) {
Shape shape = new Shape();
shape.draw();
Line line = new Line();
line.draw();
Rect rect = new Rect();
rect.draw();
Circle circle = new Circle();
circle.draw();
}
}
• final 키워드의 용도
-final 필드: 수정 불가 필드
-final 클래스: 부모로 사용 불가한 클래스
-final 메소드: 자식이 재정의할 수 없는 메소드
• 상속할 수 없는 final 클래스
-자식 클래스 만들지 못하도록 final 클래스로 생성
• 오버라이딩 불가한 final 메소드
-자식 클래스가 재정의 못하도록 부모 클래스의 메소드를 final로 생성
public class A {
protected String field;
protected A() {
}
protected void method() {
System.out.println("A class method");
}
}
/*
* A와 같은 package 내에 있는 Bclass 내에서는
* Aclass에서 protected로 선언된 field, constructor,method 사용 가능
*/
public class B {
public void method() {
A a = new A();
a.field = "newValue";
a.method();
}
}
import protected_access_modifier.pkg1.A;
/*
* A class와 상속 관계가 아닌 다른 package의 C class에서는
* A class에서 protected로 선언된 field, construct,method 사용불가
*/
public class C {
public void method() {
// A a = new A();
// a.field = "newValue";
// a.method();
}
}
import protected_access_modifier.pkg1.A;
/*
* 1. 부모 constructor가 protected로 선언된 경우는 자식 class에서 new로 instance 생성불가
* => 대신에 super()를 통해 부모 생성자 호출 가능
* 2. protected로 선언되 field, method는 자식 class에서 사용가능
*/
public class D extends A {
public D() {
super(); //부모인 A protected constructor 호출
this.field = "newValue";
this.method();
}
public void method() {
// A a = new A();
// a.field = "newValue";
// a.method();
}
}
- 부모와 자식 class간에서만 발생
- 자식 인스턴스를 부모 데이터 타입으로 넘길때 발생되는 현상 => Parent p = new Child();
- 힙메모리 사용 관점에서 보면 ,promotion 은 자식 인스턴스가 생성한 자식과 부모 인스턴스
2개 중 부모 인스턴스만 사용하겠다는 의미- 자식 인스턴스를 부모인스턴스로 promotion,하면 부모 class에서 선언된 field, method만 사용 가능
public class Person {
String name;
String id;
public Person(String name) {
this.name = name;
}
public void printPersinInformation() {
System.out.println("Person class - method 실행");
}
}
public class Student extends Person {
String grade;
String dept;
public Student(String name) {
super(name);
}
public void printStudentInformation() {
System.out.println("Student class - method 실행");
}
}
public class Main {
public static void main(String[] args) {
Person p = null;
Student s = new Student("홍길동");
s.printPersinInformation();
s.printStudentInformation();
p = s; //promotion 발생(자식 class인스턴스를 부모 class 인스턴스로 자동 형변환)
// p = new Student("자바");
p.printPersinInformation();
// p.printStudentInformation(); //p에서는 자식 인스턴스의 method사용 불가
}
}
- 부모와 자식 클래스간에만 사용 가능
- 자식 classtype 변수이름(인스턴스 명) = (자식클래스 타입) 부모인스턴스;
-예 : Student s = (Student) p;- 힙 메모리 관점에서 보면,
-p는 힙메모리에 원래 자식 인스턴스와 부모 인스턴스가 존재 하는데, promotion에 해서 부모 인스턴스만 사용하는 경우
-p를 s로 casting(강제형변환)하면, 부모 인스턴스 뿐만이아니라, 힙메모리에 있는 자식 인스턴스도 원래대로 사용하겠다는 의미- Casting의 필요성
• 자식 타입이 부모 타입으로 자동 변홖
– 부모 타입에 선언된 필드와 메소드만 사용 가능
• 자식 타입에 선언된 필드와 메소드를 다시 사용해야 할 경우
public class Person {
String name;
String id;
public Person(String name) {
this.name = name;
}
public void printPersinInformation() {
System.out.println("Person class - method 실행");
}
}
public class Student extends Person {
String grade;
String dept;
public Student(String name) {
super(name);
}
public void printStudentInformation() {
System.out.println("Student class - method 실행");
}
}
public class Main {
public static void main(String[] args) {
Person p = null;
Student s = new Student("홍길동");
s.printPersinInformation();
s.printStudentInformation();
p = s; //promotion 발생(자식 class인스턴스를 부모 class 인스턴스로 자동 형변환)
// p = new Student("자바");
p.printPersinInformation();
Student s1 = null;
s1 = (Student) p; //casting
s1.printPersinInformation();
s1.printStudentInformation();
Person p1 = new Person("홍길동");
s = (Student) p1; //casting
s.printPersinInformation();
s.printStudentInformation(); //runtime error(Exception) 발생
}
}