[Java] 상속👪

jy9922·2022년 7월 13일
0

Java

목록 보기
3/13
post-thumbnail

Inheritance (상속)

부모 class가 가지는 내용을 확장해서 자식 class를 만드는 방식을 말한다.
기존 class를 확장해서 새로운 class를 정의하는 것이다.

ex. 학사시스템
아래와 같은 3개의 class가 있다.

  • class Teacher
  • class Student
  • class Staff
package lecture0712;
class Person{
	String name; 	// 이름
	String mobile; 	// 전화번호
}
//tigthly coupled
class Student extends Person{
	String dept; 	// 학과
}
class Teacher extends Person{
	String subject; // 담당과목
}
class Staff extends Person{
	int salary; 	// 월급
}

  • extends 키워드로 상속을 구현한다.
    ( 같은 종류 간의 상속을 의미한다 )
  • 최상위 클래스는 Object 클래스다.
  • Java는 단일상속만 지원한다.
    다중상속 X - 모호성 배재를 위해서
    상속의 상속은 가능하다!
class Student extends Person, Human {
	// Java는 다중상속 X
}
  • 상속은 항상 좋은가? 좋아요!😀
    but, class가 tightly coupled 되어서 재사용에 문제가 발생한다.
    (해결방안이 있지만 나중에 이야기해보는걸루...🙄)
  • 자바의 모든 class의 최상위 class는 Object class다.
    1 ) Java의 모든 class는 특정 package 안에 포함되어 있어야 한다.
    2 ) 즉, Object class는 java.lang.object 패키지에 묶여있다.
    3 ) 코드의 최상단에 javac compiler에 의해 import java.lang.* 이 생략되어 제공된다.

❌Java에서 상속되지 않아요!❌

  • constructor는 상속되지 않는다.
  • 접근제어자 private로 지정된 field, method도 상속되지 않는다.
    (해당 클래스 내에서만 사용 가능)
package lecture0712;
// Java에선 Object class가 최상위(Object 생략가능)
class Person extends Object{
	String name; 	// 이름
	String mobile; 	// 전화번호
}
class Student extends Person{
	String dept; 	// 학과
}

public class Main {
	public static void main(String[] args) {
		Student s = new Student();
	}
}

  1. 인스턴스 생성을 하면 heap에 저장된다.
  2. 제일 먼저 생성하려는 instance의 class가 상속 관계에 있는지 없는지 확인한다.
  3. 상속 관계가 있다면 상위 클래스로 이동하여 다시 상속관계를 확인한다.
    • Person으로 간다.
  4. Java의 모든 클래스는 Object 클래스를 반드시 상속하고 있으며, extends Object가 생략되어 있다.
    • Person이 상속하는 Object로 간다.
  5. Object의 constructor을 호출되어 Object 클래스의 인스턴스가 우선 생성된다.
  6. Object의 객체가 heap에 생성된다.
  7. 이후 이미 생성된 instance를 포함하면서 하위 클래스의 instance를 생성한다.
    • Object 클래스의 instance를 감싸는 Person class의 instance가 생성된다.
    • Object 클래스의 instance를 감싸는 student class의 instance가 생성된다.

다형성❗

public class Main {
	public static void main(String[] args) {
//		Person p = new Person();
//		Student s = new Student();
//		Person s = new Student();
//		Object s = new Student();
		// is-a relationship
		// subclass is a superclass
	}
}
  • data type을 변경하면서 객체를 여러 형태로 사용할 수 있는 것을 말한다.
  • 하위 class의 기본 생성자에는 super( )가 숨겨져 있고, 이를 이용하여 상위 생성자를 호출할 수 있다.
    (super( )을 호출할 때에는 명시적으로 인자값을 제공해야 한다)

  • 변수 s가 student를 포인팅하게 된다. ( s의 타입이 Student이기 때문 )
  • Person s = new Student( ); 도 가능해진다.
    왜? is-a relationship, subclass is a superclass
  • class로부터 파생된 instance의 data type은 상위 type으로 사용할 수 있다.
  • 상위 타입을 캐스팅할 수 있다.
  • 내가 가지고 있는 객체를 여러가지 형태로 사용할 수 있다.

constructor가 상속에서는 어떻게 동작하나요?

/* super을 이용해서 상위 constructor을 호출한다 */
package lecture0712;
// Java에선 Object class가 최상위(Object 생략가능)
class Person extends Object{
	public Person(){
    	super();
    }
	String name; 	// 이름
	String mobile; 	// 전화번호
}
class Student extends Person{
	public Student() {
		super(); 	// 상위 클래스의 생성자 호출 (자동으로 삽입됨)
	}
	String dept; 	// 학과
}

public class Main {
	public static void main(String[] args) {
//		Person p = new Person();
		Student s = new Student();
//		Person s = new Student();
//		Object s = new Student();
		// is-a relationship
		// subclass is a superclass
	}
}

/* super를 호출할 땐 형태를 일치시켜줘야 한다 */
class Person extends Object{
	public Person(String name) {
		this.name = name;
	}
	String name; 	// 이름
	String mobile; 	// 전화번호
}
class Student extends Person{
	public Student() {
		super("홍길동"); 	// 상위 클래스의 생성자 호출, 형태를 맞춰줘야한다.
	}
	String dept; 	// 학과
}
  • 상위 클래스의 생성자를 호출하기 위해서 자동으로 super( )이 삽입된다.
    직접 명시하지 않아도 알아서 생성된다.
    ( 단, 인자가 없는 형태의 super( )만 자동 삽입 )
  • instance가 만들어지려면 상속에서의 constructor는 연속 호출과 연관이 있다.
  • 상위 클래스의 constructor의 인자를 맞춰서 super을 호출해줘야 한다.

method Overriding (매소드 재정의)

  • 상속관계에 있는 부모 클래스의 메서드와 형태가 똑같은 메서드를 하위 클래스에서 재정의하는 것을 말한다.
  • 하위 클래스에서 상위 클래스를 재정의하는 것이다.
  • 메서드가 영역을 나눠서 재정의되고 있다.
  • 클래스 영역을 달리해서 동일한 메서드를 재정의해서 사용할 수 있다.
  • 오버라이딩은 메서드에 국한되어서 사용한다.(하위 클래스에서 상위 클래스의 필드를 재정의하는 것은 권장하지 않음)
package lecture0712;
// Java에선 Object class가 최상위(Object 생략가능)
class Person extends Object{
	String name; 	// 이름
	String mobile; 	// 전화번호
	public void printAll() {
		System.out.println("모두 출력!!");
	}
}
class Student extends Person{
	String name; 	// 필드 재정의 (오버라이딩X) - 일반적이지 않아요!(권장X)
	String dept; 	// 학과
	public void printAll() {
		System.out.println("오버라이딩");
	}
}

public class Main {
	public static void main(String[] args) {
		Student s = new Student();
	}
}
  • this -> 현재 사용하는 객체의 reference
  • super -> 현재 사용하는 객체의 reference -> Type이 상위 Type
  • super( ) -> 상위 클래스의 생성자 호츨
  • this( ) -> 자기 자신의 class가 가진 다른 생성자를 호출
class Student extends Person{
	String dept; 	// 학과
	// default constructor
	public Student() {
		this("홍길동"); // 현재 자신이 가지고 있는 생성자의 다른 생성자 호출
	}
	public Student(String name) { 
		this.name = name; // 여기 안으로 들어감
	}
}

Dynamic binding

객체에 대한 type이 상위 타입이라 할지라도
만약 오버라이딩된 메소드가 하위에 존재한다면
메소드는 오버라이딩된 메소드를 사용한다.

package lecture0712;

class Superclass{
	// static method
	static int staticCall(String msg) {
		System.out.println(msg);
		return 100;
	}
	
	//fields
	int a = staticCall("1번입니다.");
	static int b = staticCall("2번입니다.");
	
	//constructors
	public Superclass() {
		staticCall("3번입니다.");
	}
	public Superclass(int i) {
		this();
		staticCall("4번입니다.");
	}
	// method
	public void myFunc() {
		System.out.println("5번입니다.");
	}
}
public class InheritanceTest extends Superclass{
	// fields
	int c = staticCall("6번입니다.");
	static int d = staticCall("7번입니다.");
	
	// constructor
	public InheritanceTest() {
		super(100);
		staticCall("8번입니다.");
		super.myFunc();
	}
	
	@Override
	public void myFunc() {
		System.out.println("9번입니다.");
	}
	public static void main(String[] args) {
		System.out.println("10번입니다.");
		Superclass obj = new InheritanceTest();
		obj.myFunc();
        // 객체에 대한 type이 상위 타입이라 할지라도 
        // 만약 오버라이딩된 메소드가 하위에 존재한다면
        // 메소드는 오버라이딩된 메소드를 사용한다
        // 동적 바인딩 (dynamic binding)
	}
}

순서 : 2 -> 7 -> 10 -> 1 -> 3 -> 4 -> 6 -> 8 -> 5 -> 9
1. public class인 inheritance class를 먼저 시작
2. inheritance class를 method area에 올리기 전에 Superclass가 먼저 method area에 올라가게 된다.
3. static으로 지정된 b가 method area에 공간이 만들어진다.
4. staticCall이 호출되면서 "2번입니다." 출력
5. inheritance에 대한 정보를 method area에 올린다.
6. static으로 지정된 d의 공간이 생기면서 "7번입니다." 출력
7. main method부터 시작된다.
8. "10번입니다." 출력
9. 인자가 없는 생성자를 호출하게 된다.
10. super의 constructor에 인자를 받는 부분을 호출한다.
11. this(); 내가 가지고 있는 다른 constructor 호출한다.
11. 생성자 부분을 호출하기 직전에 인스턴스 variable 객체가 먼저 생성되어야 한다. "1번입니다." 출력
12. 생성자에 대한 초기화 "3번입니다."
13. "4번입니다." 출력
14. IneritanceTest() 생성 전에 필드 호출 "6번입니다."
15. "8번입니다." 출력
16. super.myFunc() "5번입니다." 출력
17. myFunc() "9번입니다." 출력

final

  • final이 변수 앞에 붙으면 상수처리 된다.
final int k = 100;
  • class 앞에 붙을 수 있다.
    상속이 안된다는 의미를 가진다.
final class A {}
  • method 앞에 final이 붙을 수 있다.
    해당 method가 마지막을 의미한다. ( overriding 금지 )
final void kk(){}

추상 클래스

  • 추상 class -> abstract class를 의미한다.
  • abstract method가 단 1개라도 class 내부에 존재하면 해당 클래스는 추상클래스다.
    🔎 abstract method : method의 선언만 있고 정의가 없으며, method가 하는 일이 정해지지 않은 method를 칭한다.
  • 추상 클래스는 instance를 생성할 수 없다.
  • 추상 클래스를 상속하는 하위 클래스에서 오버라이딩하여 추상 메서드를 완전하게 만들어줘야만 하위 클래스가 완전한 클래스가 될 수 있다.
  • 클래스를 파생시켜 사용할 수 있다. ( 해당 메소드를 오버라이딩 )

추상 클래스를 왜 사용할까?😦

기능적인 이름을 통일하기 위해서 사용한다.
기능적으로 추상메서드로 통일하고 하위 클래스에서 메소드를 재정의한다.

package lecture0712;

// 추상클래스(abstract class)
public abstract class UpperClass {
	// fields
	String name;
	int age;
	
	// method
	public abstract void printAll(); // abstract method (해당 메소드 앞에 abstract 키워드 붙임)
}

class subClass extends UpperClass{
	// 추상 메소드를 사용하기 위해서 재정의하면 된다(오버라이딩)
	@Override
	public void printAll() {
		// TODO Auto-generated method stub
		
	}
}

Interface

추상 class의 아주 특별한 형태를 말한다.

  • 모든 method가 추상method다.
  • 모든 field는 public static final로 구성되어 있다.
    안에 들어간 field는 전부 상수이다.
  • 인터페이스는 다중구현이 가능하다.

class 👉 interface

  • 객체를 만들어낼 수 없다.
  • is-a 관계가 성립된다.
package lecture0712;

interface myInterface{
	// fields
	// public static final은 자동적으로 설정(안써줘도 자동설정)
	int kk = 0;
	String aa = "Hello";
	
	// methods
	public abstract void printAll();
	
	public abstract void myPrint();
}

// 인터페이스를 구현해서 MyClass2를 정의한다는 뜻 (상위 클래스 개념으로 사용함)
// 내가 구현할 해당 인터페이스들을 모두 오버라이딩 해줘야 한다.
public class MyClass2 implements myInterface {

	@Override
	public void printAll() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void myPrint() {
		// TODO Auto-generated method stub
		
	}
	
}
package lecture0713;

class Human{
		
}
interface MyInterface{
	
}
interface Animal{
	int weight = 10; // public static final 생략됨
	public static final int age = 20;
	
	public void printName(); // abstract 안붙여도 알아서 붙여줌
	public abstract void printAge();
}

// abstract MyClass implements Animal{ // 오버라이딩하지 않으면 이 class 또한 추상화된다
// }

//Human 클래스에서 상속받고, Animal 인터페이스를 구현
// 클래스는 단일 상속만 가능하고, 인터페이스는 다중 구현이 가능
class MyClass extends Human implements Animal, MyInterface { 

	@Override
	public void printName() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void printAge() {
		// TODO Auto-generated method stub
		
	} 
	
}
public class Main {

}

0개의 댓글