[객체지향][상속] 오버라이딩

포키·2022년 10월 25일
0

국비과정

목록 보기
23/73
  • this의 의미 재확인
    this는 객체 자신을 가리킨다
class C {
	public void call() {
		this.todo();
	}
	public void todo() {
		System.out.println("C");
	}
}
class D extends C {	
	@Override
	public void todo() {
		System.out.println("D");
	}
}
class Ex5 {
	public static void main(String[] args)	{
		D d = new D();
		d.call();
	}
}

예문에서 부모클래스 C(의 call()메서드)에 존재하는 this는 생성된 객체 d를 가리킨다.
따라서 this.todo()는 D 객체의 메서드 todo()를 가리키게 된다.

C c = new C();

생성된 객체가 부모클래스 C의 c일 경우, this는 객체 c를 가리켰을 것이다.


메소드 오버라이딩 (method overriding)

정의

: 자식 클래스가 부모 클래스의 메서드를 필요에 맞추어 재정의하는 것

  1. 메서드 header(이름, 패러미터, return)를 변경할 수 없다.
  2. 접근제한자는 변경 가능하지만, 더 넓은 범위로만 가능. (하위클래스가 더 넓어야 함.)
    (private -> 생략 -> protected -> public 방향)
  3. 상속 관계가 전제된다.
  4. what은 유지, how가 변경.

= 다 내버려두고 내용만 바꾸는데, 접근은 같거나 더 공개적이고, 상속 관계에서만 가능.

Override vs. Overload

  • overloading : (같은 이름이되) 물리적으로 완전히 다른 메서드를 만드는 것 - 중복정의
  • overriding : 물리적으로 완전히 같은 메서드를 만드는 것 (덮어씌우기) - 재정의
    '물리적으로' 다른 메서드 정의 vs '물리적으로' 같은 메서드 정의
    한 클래스 내부 vs 상속을 전제
class Mother {
	public void eat() {
		// 엄마는 오른손잡이라 '오른손으로 밥 먹는다'
		System.out.println("오른손으로 밥 먹는다.");
	}
}
// 딸이 왼손잡이라면?
class Daughter extends Mother {
	public void eat() {
		// '왼손으로 밥 먹는다'로 overriding
		System.out.println("왼손으로 밥 먹는다.");
	}
}
class Ex1 {
	public static void main(String[] args) {
		Daughter d = new Daughter();
		d.eat();
	}
}
  • 메소드 오버라이딩의 대표 예시 - Object 객체의 toString() 메서드
class Some {
	public String toString() {
    	return "I'm a Some.";
    }
}
class Ex2 {
	public static void main(String[] args) {
    	Some s = new Some();
        String str = s.toString();
        System.out.println(str);
    }
}
// Some에서 toString이 재정의되지 않으면 (override하지 않으면) Object에서 정의된 대로 주소값 반환
// Some에서 재정의되었으므로 실제론 'I'm a Some.'이 출력

@Override

오버라이드하기 전 입력하여 메서드가 오버라이딩됨을 알려주는 표시 (annotation의 하나)
1. 컴파일 과정에서 에러 메시지를 출력해주어 쉽게 확인 가능 = 오류 확인 빠름
2. 오버라이딩 전에 표시해주므로 오버라이딩 사용 여부 한 눈에 확인 가능 = 코드 가독성 높아짐

annotation : 코드 안에서 주석처럼 쓰이나, 일반 주석과 달리 코드 진행에 영향을 줄 수 있다.
상속 실수를 막기 위해 JDK1.5부터 생긴 기능.

class A {
	public void todo(int n, String str) {
		System.out.println("A");	
	}
}

아래처럼 이름을 실수하거나

class B extends A {
	public void tood(int n, String str) {
		System.out.println("B");
	}
}

패러미터를 실수하더라도

class B extends A {
	public void todo(String str, int n) {
		System.out.println("B");
	}
}

새로운 메서드로 처리되거나, 오버로딩으로 처리되기 때문에,
컴파일 과정에서 에러 메시지가 뜨지 않는다!

class A {
	public void todo(int n, String str) {
		System.out.println("A");	
	}
}
class B extends A {
	@Override
	public void tood(String str, int n) {
		System.out.println("B");
	}
}

class B가 부모클래스 A의 메서드를 제대로 오버라이딩하지 못했을 때
아래와 같은 에러 메시지를 출력한다.

또한 @Override (annotation 기능) 은 이 메서드가 override되었다는 표식이 되기도 한다.
그러므로 코드 가독성이 높아진다.

class Shape {
	public void draw() {
		System.out.println("Shape");
	}
}
class Circle extends Shape {
	@Override
	public void draw() {
		System.out.println("Circle을 그립니다.");
	}
}
class Rectangle extends Shape {
	@Override
	public void draw() {
		System.out.println("Rectangle을 그립니다.");
	}
}
class Triangle extends Shape {
	@Override
	public void draw() {
		System.out.println("Triangle을 그립니다.");
	}
}
class ShapeTest {
	public static void main(String[] args) {
		Rectangle s = new Rectangle();
		s.draw();
		Circle c = new Circle();
		c.draw();
		Triangle t = new Triangle();
		t.draw();
		Shape sh = new Shape();
		sh.draw();
	}
}

super 참조변수

this와 같은 쓰임새이나 자기 자신이 아니라 부모 객체를 부른다.

class Human {
	private String name;
	private int age;

	public Human(String name, int age) {
		setName(name);
		setAge(age);
	}
	public String getName() {
		return name;
	}
	public int getAge() {
		return age;
	}
	public void setName(String name)	{
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return name + "(" + age + ")";
	}
}
class Student extends Human {
	private int grade;

	public Student(String name, int age, int grade) {
		super(name, age);
		setGrade(grade);
	}
	public int getGrade() {
		return grade;
	}
	public void setGrade(int grade) {
		this.grade = grade;
	}
	public String toString() {
		// 부모의 toString 호출
		return super.toString() + grade + "학년";
	}
}
class Ex4 {
	public static void main(String[] args) {
		Student s = new Student("A", 13, 6);
		System.out.println(s);
	}
}
  • 오버라이딩은 사실 완전히 새로 정의하기보다 super.를 사용하여 부모객체의 매서드를 실행 후 추가 부분을 작성하는 식으로 정의하는 경우가 많다.
  • 멤버변수는 재정의 기능이 없다 - (대입으로) 값 바꿀 수 잇으니까
  • 메서드는 재정의가 가능하다 (override) - 메서드를 바꿀 수 없으니까
  • super로 접근 가능한 것은 바로 위 객체 (부모객체)까지만!
super.num 			// 바로 위 객체 (부모객체) 접근 가능
super.super.num;	// 위의 위 객체는 바로 접근 불가

위로 가려면 부모 객체 안에서 super를 한 번 더 사용하여 나아가는 수 밖에 없다.

class A {
	public void grandma() {
    	System.out.println("Hello, This is grandma!");
    }
}
class B extends A {
	public void callMom() {
    	System.out.println("Hello, mommy. This is mother.");
    	super.grandma();
    }
}
class C extends B {
	@Override
	public void callMom() {
    	System.out.println("Hello, mommy. This is daughter.");
    	super.callMom();
    }
}

다형성 - 함수형 언어에서 사용. 자바는 함수형 언어가 아니므로(함수형같은 형태를 사용하는 경우는 있더라도) 오버라이드가 다형성과 관련된 것은 아니다.

정적 메서드 오버라이딩 (p.243)

  • 오버라이딩 전제조건 = '상속 관계'
    그러나 정적 메서드는 객체에 속하지 않음, 상속 관계도 가질 수 없음
  • 실제로 @Override를 사용하면 컴파일 과정에서 'Override 되지 않았다'는 에러 메시지를 출력한다.
    (243쪽 코드 - a와 dog는 같은 객체 (Dog 객체) 를 가리키지만, a는 Animal 참조변수, dog는 Dog 참조변수. 그래서 실행되는 메서드도 다른듯????)
profile
welcome

0개의 댓글