[Java]Inheritance(1)

박진우·2022년 9월 11일
0

[Java]자바의 기초

목록 보기
10/16

상속(Inheritance)이란

• 자식(하위, 파생) 클래스가 부모(상위) 클래스의 멤버를 물려받는 것
• 자식이 부모를 선택해 물려받음
• 상속 대상: 부모의 필드와 메소드

상속의 사례

상속의 효과

클래스의 갂결화
• 멤버의 중복 작성 불필요
클래스 관리 용이
• 클래스들의 계층적 분류
소프트웨어의 생산성 향상
• 부모 클래스 재사용해 자식 클래스 개발 속도 빠름
• 클래스 재사용으로 반복된 코드 중복 줄이고, 새로운 클래스 확장 용이
• 유지 보수 편리성 제공
상속 대상 제한
• 부모 클래스의 private 접근 갖는 필드와 메소드 제외
• 부모 클래스가 다른 패키지에 있을 경우, default 접근 갖는 필드와 메소드도 제외

extends

  • 자식 클래스가 상속할 부모 클래스를 지정하는 키워드

자바 상속 특징

상속 횟수 무제한
상속의 최상위 조상 클래스는 java.lang.Object 클래스
• 모든 클래스는 자동으로 java.lang.Object를 상속받음
• 자바 컴파일러에 의해 자동으로 이루어짐

상속의 예제(Point,ColorPoint)

point

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 + ")");
	}
}

ColorPoint

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(매개값,…)
– 매개값과 동일한 타입, 개수, 순서 맞는 부모 생성자 호출
• 부모 생성자 없다면 컴파일 오류 발생
• 반드시 자식 생성자의 첫 줄에 위치
• 부모 클래스에 기본(매개변수 없는) 생성자가 없다면 필수 작성

super와 this

  • super : heap memory 에 있는 Parent class의 instance
  • this : heap memory에 있는 자기 자신의 instance
  • 2.super(homePhoneNumber);
    -부모 생성자 호출(본인의 다른 생성자 this(...);)

Parent

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호출");
	}
}

Child


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)

• 메소드 재정의(@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 메소드
-자식 클래스가 재정의 못하도록 부모 클래스의 메소드를 final로 생성

protected 접근 제한자

같은 패키지

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();
	}
}

자동 타입 변환(Promotion)과 강제 타입 변환(Casting)

promotion

  1. 부모와 자식 class간에서만 발생
  2. 자식 인스턴스를 부모 데이터 타입으로 넘길때 발생되는 현상 => Parent p = new Child();
  3. 힙메모리 사용 관점에서 보면 ,promotion 은 자식 인스턴스가 생성한 자식과 부모 인스턴스
    2개 중 부모 인스턴스만 사용하겠다는 의미
  4. 자식 인스턴스를 부모인스턴스로 promotion,하면 부모 class에서 선언된 field, method만 사용 가능

Promotion 예제(Persont, Student)

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 실행");
	}
	
}

Main

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사용 불가
	}
}

Casting

  1. 부모와 자식 클래스간에만 사용 가능
  2. 자식 classtype 변수이름(인스턴스 명) = (자식클래스 타입) 부모인스턴스;
    -예 : Student s = (Student) p;
  3. 힙 메모리 관점에서 보면,
    -p는 힙메모리에 원래 자식 인스턴스와 부모 인스턴스가 존재 하는데, promotion에 해서 부모 인스턴스만 사용하는 경우
    -p를 s로 casting(강제형변환)하면, 부모 인스턴스 뿐만이아니라, 힙메모리에 있는 자식 인스턴스도 원래대로 사용하겠다는 의미
  4. Casting의 필요성
    • 자식 타입이 부모 타입으로 자동 변홖
    – 부모 타입에 선언된 필드와 메소드만 사용 가능
    • 자식 타입에 선언된 필드와 메소드를 다시 사용해야 할 경우

Casting 예제(Persont, Student)

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 실행");
	}
	
}

Main

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) 발생
		
	}
}
profile
개발자를 꿈꾸는 사람입니다

0개의 댓글