상속 - super(), 오버라이딩, Object 클래스, final (23.05.03)

·2023년 5월 3일
0

Java

목록 보기
21/35
post-thumbnail

📝 상속 (Inheritance)


다른 클래스가 가지고 있는 멤버(필드, 메소드)들을 새로 작성할 클래스에서 직접 만들지 않고
상속을 받음으로써 새 클래스가 자신의 멤버처럼 사용할 수 있는 기능
-> extends : 확장하다, 연장하다

💡 작성 방법

[접근제한자] class 클래스명 extends 클래스명 {}
	public class Student extends Person {}

-> Student 클래스에 Person 클래스 내용을 연장한다.
== Student 클래스에 Person 클래스 내용(필드, 메소드)을 추가하여 확장한다.

✏️ 상속의 목적

클래스의 재사용, 연관된 일련의 클래스들에 대한 공통적인 규약 정의

✏️ 상속의 장점

  1. 보다 적은 양의 코드로 새로운 클래스 작성 가능
  2. 코드를 공통적으로 관리하기 때문에 코드의 추가 및 변경 용이
  3. 코드의 중복을 제거하여 프로그램의 생산성과 유지보수에 크게 기여

💡 단일 상속

  • 클래스간의 관계가 다중 상속보다 명확하고 신뢰성 있는 코드 작성
  • 자바에서는 다중 상속 미지원 → 단일상속만 지원

✏️ 상속의 특징

  1. 모든 클래스는 Object클래스의 후손
  2. 부모클래스의 생성자, 초기화 블록은 상속 안 됨
  3. 부모의 private멤버는 상속은 되지만 직접 접근 불가

✏️ 예시 - 상속

  • vo 패키지 - Person 클래스
package edu.kh.inheritance.model.vo;

public class Person {

	// 필드
	private String name;
	private int age;
	private String nationality; // 국적
	
	// 생성자
	// 기본 생성자
	public Person() {}
	
	// 매개변수 생성자
	public Person(String name, int age, String nationality) {
		this.name = name;
		this.age = age;
		this.nationality = nationality;
	}
	
	// 메소드
	// getter / setter
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public int getAge() {
		return age;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	
	public String getNationality() {
		return nationality;
	}
	
	public void setNationality(String nationality) {
		this.nationality = nationality;
	}
	
	
	// 상속의 특징 : 코드 추가 및 수정에 용이함
	// (새로운 메소드를 Person에 추가하였을 때
	// 	Student, Employee가 사용 가능한지 확인)
	public void breath() {
		System.out.println("사람은 코나 입으로 숨을 쉰다.");
	}
    	
	public void move() {
		System.out.println("사람은 움직일 수 있다.");
	}

}
  • vo 패키지 - Employee 클래스
package edu.kh.inheritance.model.vo;

public class Employee extends Person {
	
	// 필드
	private String company;
	
	// 기본 생성자 : Ctrl + Space - Constructor
	public Employee() {}

	// 매개변수 생성자 : Alt + Shift + s - Generate Constructor using Fields
	public Employee(String name, int age, String nationality, String company) {
		this.company = company;
	}

	// 메소드
	public String getCompany() {
		return company;
	}

	public void setCompany(String company) {
		this.company = company;
	}
	
}
  • vo 패키지 - Student 클래스
package edu.kh.inheritance.model.vo;

public class Student extends Person {
	// Student 클래스에 Person 클래스 내용을 연장한다.
	// == Student 클래스에 Person 클래스 내용(필드, 메소드)을 추가하여 확장한다.
	
	// *** 상속 ***
	// extends : 확장하다, 연장하다+
	
	// 필드
	private int grade; // 학년
	private int classRoom; // 반
	
	// 생성자
	public Student() {} // 기본 생성자
	
	// 매개변수 생성자
	public Student(String name, int age, String nationality, int grade, int classRoom) {
		this.grade = grade;
		this.classRoom = classRoom;
	}

	// 메소드
	public int getGrade() {
		return grade;
	}

	public void setGrade(int grade) {
		this.grade = grade;
	}

	public int getClassRoom() {
		return classRoom;
	}

	public void setClassRoom(int classRoom) {
		this.classRoom = classRoom;
	}
	
}
  • service 패키지 - InheritanceService 클래스
package edu.kh.inheritance.model.service;

import edu.kh.inheritance.model.vo.Employee;
import edu.kh.inheritance.model.vo.Person;
import edu.kh.inheritance.model.vo.Student;

public class InheritanceService {

	public void ex1() {
		// 상속 확인
		// - Person을 상속받은 Student가 Person의 필드, 메소드를 사용할 수 있는가?
		
		Person p = new Person();
		
		// p.name = "홍길동"; // private 때문에 직접 접근 불가
		
		p.setName("홍길동");
		p.setAge(25);
		p.setNationality("대한민국");
		
		System.out.println(p.getName());
		System.out.println(p.getAge());
		System.out.println(p.getNationality());
		
		System.out.println("--------------------------------");
		
		// Student 객체 생성
		
		Student std = new Student();
		
		// Student만의 고유한 메소드
		std.setGrade(3);
		std.setClassRoom(5);
		
		// Person 클래스로부터 상속받은 메소드
		std.setName("고아라");
		std.setAge(19);
		std.setNationality("대한민국");
		
		System.out.println(std.getGrade());
		System.out.println(std.getClassRoom());
		
		// Student가 Person의 메소드뿐만 아니라 필드도 상속받았는지 확인
		System.out.println(std.getName());
		System.out.println(std.getAge());
		System.out.println(std.getNationality());
		
		System.out.println("--------------------------------");
		
		Employee emp = new Employee();
		
		// Employee만의 고유 메소드
		emp.setCompany("KH정보교육원");
		
		// Person 클래스로부터 상속받은 메소드
		emp.setName("다나카");
		emp.setAge(35);
		emp.setNationality("일본");
		
		System.out.println(emp.getCompany());
		System.out.println(emp.getName());
		System.out.println(emp.getAge());
		System.out.println(emp.getNationality());
		
		System.out.println("--------------------------------");
		
		// 추가된 breath() 메소드 확인하기
		p.breath();
		std.breath();
		emp.breath();
	}
}
  • run 패키지 - InheritanceRun 클래스
package edu.kh.inheritance.run;

import edu.kh.inheritance.model.service.InheritanceService;

public class InheritanceRun {

	public static void main(String[] args) {
		InheritanceService service = new InheritanceService();
		
		service.ex1();
	}

}
  • 출력 화면


Person()을 상속받아 그 속성과 기능을 사용 가능한 모습을 볼 수 있다.

  • Person()을 상속받은 Student() 객체의 메모리 구조


💡 super() 생성자

부모의 생성자를 호출하는 코드
super : 상위 <-> sub : 하위

  • 반드시 자식 생성자 최 상단에 작성되어야 함
  • super() 생성자 때문에 자식 객체 내부에 부모 객체가 생성됨
  • super() 생성자 미작성 시 컴파일러가 컴파일 단계에서 자동으로 추가해 줌

💡 super.

  • 상속을 통한 자식 클래스 정의 시 해당 자식 클래스의 부모 객체를 가리키는 참조변수
  • 자식 클래스 내에서 부모 클래스 객체에 접근하여 필드나 메소드 호출 시 사용

✏️ 예시 - super() 생성자 사용 방법

  • run 패키지 - Student 클래스 내용 중 일부
public class Student extends Person {
	// Student 클래스에 Person 클래스 내용을 연장한다.
	// == Student 클래스에 Person 클래스 내용(필드, 메소드)을 추가하여 확장한다.
	
	// *** 상속 ***
	// extends : 확장하다, 연장하다+
	
	// 필드
	private int grade; // 학년
	private int classRoom; // 반
	
	// 생성자
	public Student() {			
		
		// Student() 객체 생성 시 
		// 내부에 상속받은 Person 객체를 생성하기 위한
		// Person 생성자 호출 코드가 필요하다!
		
		// super : 상위 <-> sub : 하위
		// super == Person
		
		super(); // super() 생성자
		// 부모의 생성자를 호출하는 코드
		// 반드시 자식 생성자 최 상단에 작성되어야 한다!
		
	} // 기본 생성자
	
	// 매개변수 생성자
	public Student(String name, int age, String nationality, int grade, int classRoom) {
		
		// 전달받은 값 중 name, age, nationality
		// 부모 필드에 세팅하기
		
		// this.name = name; // (X)
		// 상속받은 부모의 필드(name)를
		// 자식의 필드처럼 사용하려 했으나 오류 발생
		
		// 왜? 부모의 필드에 private 접근 제한자가 있어서
		// 아무리 물려받은 자식이라도 다른 객체이기 때문에 직접 접근 불가
		// -> 간접 접근 방법을 사용
		
		// setName(name);
		// setAge(age);
		// setNationality(nationality);
		// 부모의 setter를 이용하면 되지만 비효율적임
		
		super(name, age, nationality); // 부모 매개변수 생성자 호출
		
		this.grade = grade;
		this.classRoom = classRoom;
	}
  • service 패키지 - InheritanceService 클래스 내용 중 일부
public void ex2() {
		
		// super() 생성자 사용 방법
		
		// Student 매개변수 5개 짜리 생성자
		Student std = new Student("공유", 35, "한국", 1, 3);
		
		System.out.println(std.getName()); // 공유
		System.out.println(std.getAge()); // 안 나옴
		System.out.println(std.getNationality()); // 한국
		System.out.println(std.getGrade()); // 1
		System.out.println(std.getClassRoom()); // 3
	}
  • 출력 화면

💡 오버라이딩(Overriding)

자식 클래스가 상속 받은 부모 메소드를 재작성 하는 것

  • 부모가 제공하는 기능을 후손이 일부 고쳐 사용하겠다는 의미로
    자식 객체를 통한 실행 시 후손 것이 우선권을 가짐
  • 어노테이션(Annotation) : 컴파일러에게 알려 주기 위한 코드 (컴파일러 인식용 주석)

  • @Override 어노테이션 : 해당 메소드가 오버라이딩 되었음을 컴파일러에게 알려 주는 역할

✏️ 오버라이딩 성립 조건

  1. 메소드 이름 동일
  2. 반환형 동일
  3. 매개변수 동일
  4. 접근 제한자 같거나 더 넓은 범위
    ex) (부) protected -> (자) protected 또는 public
  5. 예외처리 범위는 같거나 더 좁게
  6. 부모의 private 메소드는 오버라이딩 불가
    -> 왜? 자식이 접근할 수 없기 때문에

✏️ 예시 - 오버라이딩 확인

  • vo 패키지 - Employee 클래스 내용 중 일부
	// Person으로부터 상속받은 메소드 중
	// move() 메소드를 Employee에 맞게 재정의(== 오버라이딩)
	
	// @Override 어노테이션 : 해당 메소드가 오버라이딩 되었음을
	//						컴파일러에게 알려 주는 역할
	
	@Override // 오버라이딩 시 작성해 주는 것이 좋다.
	public void move() {
		
		// 기존 부모 코드 삭제 후 자식이 새롭게 재정의
		System.out.println("오버라이딩된 move() 메소드");
		System.out.println("효율적으로 빨리 일처리하고 야근을 하지 않는다.");
	}
  • service 패키지 - InheritanceService 클래스 내용 중 일부
	public void ex3() {
		// 오버라이딩 확인 예제
		
		Student std = new Student();
		Employee emp = new Employee();
		
		std.move(); // 오버라이딩 X // Person의 메소드 수행
		
		emp.move(); // 오버라이딩 O // Employee 메소드 수행
	}
  • 출력 화면

오버라이딩 된 메소드가 출력된 것을 볼 수 있다.


💡 Object 클래스

모든 클래스는 Object 클래스의 후손
== 모든 클래스의 최상의 부모는 Object

✏️ 예시 1 - Object 상속

  • vo 패키지 - Person 클래스 내용 중 일부
public class Person extends Object {
	// class명에 상속 구문이 없다면
	// 컴파일러가 자동으로 extends Object 구문을 추가해 줌

.
.
.

	public void ex3() {
	// Object.toString() 메소드 오버라이딩
	// - toString() 메소드는 객체가 가지고 있는 모든 값(필드)을
	//	 하나의 문자열로 반환하는 용도의 메소드
	
	@Override
	public String toString() {
		return name + " / " + age + " / " + nationality;
				// 김철수 / 15 / 대한민국
	}
  • service 패키지 - InheritanceService 클래스 내용 중 일부
	public void ex4() {
		
		// 모든 클래스는 Object 클래스의 후손
		// == 모든 클래스의 최상의 부모는 Object
		
		// 1) Object 상속 여부 확인
		Person p = new Person(); // Object를 상속받은 Person 객체 생성
		
		Student std = new Student(); // Person을 상속받은 Student 객체 생성
		// Object - Person - Student
		
		Scanner sc = new Scanner(System.in);
		
		String str = "abc";
		
		
		// ** Object 상속과 단계적인 상속 확인
		
		System.out.println(p.hashCode()); // Object에서 물려받은 hashCode()
		
		System.out.println(std.getAge()); // Person에서 물려받은 getAge()
		
		System.out.println(std.hashCode());
		// Person이 Object에서 물려받은 hashCode()를
		// Student가 또 물려받아 사용
		
		// -> 상속의 상속의 상속의 .... 상속 가능
		
		// * Object가 모든 클래스의 최상위 부모인지 확인
		System.out.println( sc.hashCode() );
		// Object - haseCode()
		
		System.out.println( str.hashCode() );
		// String - hashCode()
		// -> String이 Object에게 물려받은 hashCode를 오버라이딩
		
	}
  • 출력 화면



✏️ 예시 2 - 오버라이딩 연습

  • vo 패키지 - Student 클래스 내용 중 일부
	// toString() 오버라이딩
	@Override
	public String toString() {
		
		// super 참조 변수
		return super.toString() + grade + " / " + classRoom;
  • vo 패키지 - Employee 클래스 내용 중 일부
    	// toString() 오버라이딩
	@Override
	public String toString() {
		return super.toString() + " / " + company;
	}
  • service 패키지 - InheritanceService 클래스 내용 중 일부
	public void ex5() {
		
		Person p = new Person("이동휘", 28, "한국");
		
		System.out.println( p.toString() ); // 이동휘 / 28 / 한국
		System.out.println( p ); // 이동휘 / 28 / 한국
		
		// print 구문 수행 시 참조 변수명을 작성하면
		// 자동으로 toString() 메소드를 호출해서 출력한다!
		
		System.out.println("-------------------------------------");
		
		Student std = new Student("윈터", 27, "미국", 2, 6);
		
		System.out.println(std.toString());
		// 1) Student 클래스 toString() 오버라이딩 전
		// Person으로부터 상속받은 오버라이딩된 toString() 수행
	
		// 2) Student 클래스 toString 오버라이딩 후
		// Student의 toString() 수행
	
		Employee emp = new Employee("김근로", 26, "한국", "OO증권");
		
		System.out.println(emp.toString());
	}
  • 출력 화면


💡 final

마지막 클래스라는 의미로 "더 이상 상속 불가"를 뜻함

✏️ 예시 - final 알아보기

  • Parent 클래스
package edu.kh.inheritance.model.vo;

public /*final*/ class Parent { // 부모 클래스
	// Object 상속 중
	
	// ** final 클래스 **
	// -> 마지막 클래스라는 의미로
	// 	  "더 이상 상속 불가"를 뜻함
	
	public /*final*/ void method() {
		
		System.out.println("테스트용 메소드");
	}

}
  • Child 클래스
package edu.kh.inheritance.model.vo;

public class Child extends Parent { // 자식 클래스
	// Parent 상속 중
	
	//The type Child cannot subclass
	// the final class Parent
	// (final 클래스인 Parent는
	// Child 클래스를 자식으로 가질 수 없다.)
	
	
	@Override
	public void method() {
		System.out.println("오버라이딩 성공!!");

	// Cannot override
	// the final method from Parent
		
	}

}
profile
풀스택 개발자 기록집 📁

0개의 댓글