객체지향 프로그래밍 (OOP), Inheritance

Wonkyun Jung·2023년 2월 15일
0

자바기초

목록 보기
2/4
post-thumbnail

1. 상속

객체지향 언어의 특징: OOP is A P.I.E

Abstraction(추상화): 현실의 객체를 추상화 해서 클래스를 구성한다.

Polymorphism(다형성): 하나의 객체를 여러 가지 타입으로 참조할 수 있다.

Inheritance(상속): 부모 클래스의 자산을 물려받아 자식을 정의함으로 코드의 재사용이 가능

Encapsulation(데이터 은닉과 보호): 데이터를 외부에 직접 노출시키지 않고 메서드를 이용해 보호

상속

  • 기존 클래스의 자산을 자식 클래스에서 재사용하기 위한 것 → 부모의 생성자와 초기화 블록은 상속하지 않는다.
  • 기존 클래스의 멤버를 물려 받기 때문에 코드의 절감 → 부모의 코드를 변경하면 모든 자식들에게도 적용 → 유지 보수성 향상
  • 상속의 적용 extends 키워드 사용
public class Person{
	String name;
	void eat(){}
	void jump(){}
}

public class SpiderMan extends Person{
	boolean isSpider;
	void fireWeb(){}
}
  • Object 클래스: 모든 클래스의 조상 클래스
    • 별도의 extends 선언이 없는 클래스들은 extends Object가 생략됨
    • 따라 모든 클래스에는 Object 클래스에 정의된 메서드가 있음 ex) hasCode( ) , equals( ), toString( )

상속의 관계는 is a 관계라고 한다. Person is a Object, SpiderMan is a Person

자바는 단일 상속만 지원한다 → 대신 interface와 포함 관계(has a)로 단점 극복 (아래 코드 예시 참고)

포함 관계 : 상속 이외에 클래스를 재활용 하는 방법

  • 2개 이상의 클래스에서 특성을 가져올 때 하나는 상속, 나머지는 멤버 변수로 처리



2. 메서드 재정의(Overriding)

메서드 오버라이딩( overriding): 조상 클래스에 정의된 메서드를 자식 클래스에서 적합하게 수정하는 것

선조클래스와 후손클래스에 같은 이름의 함수가 존재하는경우
선조클래스로부터 상속받은 메서드의 내용을 변경하는것을 오버라이딩(재정의)이라고함

public class Person {
	void jump(){
		System.out.println("두 다리로 점프");
	}
}
public class Spider{
	void jump(){
		System.out.println("엄청난 점프");
	}
}
public class SpiderMan2 extends Person{
	Spider spider = new Spider(); //포함 관계 Spider 클래스를 멤버변수로 가지고 있는다. 
	boolean isSpider; 
	
	void fireweb(){} 
	void jump(){
		if(isSpider){
			//포함 관계 이용해서 상위 클래스 메서드. 같은 메서드 이름이지만 overriding 된 것
			spider.jump(); 
		}else{
			//System.out.println("두 다리로 점프"); 
      //but 이 코드는 Person에서 정의한 메서드에 이미 있는 내용이다.
			super.jump();  //이렇게 조상이 가지고 있는 메서드를 실행할 수 있다.  
		}
	}
}

Person이 가지고 있는 jump( )은 성능이 좋지 않다 → Spider가 가지고 있는 jump( )를 이용

오버라이딩의 조건

  • 메서드 이름이 같아야 한다.
  • 매개 변수의 개수, 타입, 순서가 같아야 한다.
  • 리턴 타입이 같아야 한다.
  • 접근 제한자는 부모보다 범위가 넓거나 같아야 한다.
  • 조상보다 더 큰 예외를 던질 수 없다.

Overloading vs Overriding

class Test1{
	public void view1() { System.out.println("view1 method"); }
	public void view3() { System.out.println("view3 method"); }
}
class Test2 extends Test1{
	public void view1() { System.out.println("view11 method"); }
	public void view2() { System.out.println("view22 method"); }	
}
public class OverrideEx {
	public static void main(String[] args) {
		//부모 클래스는 자식 클래스를 알지 못한다 -> 메서드 오버라이딩을 통해 알 수 있음 
		Test1 ob=new Test2();  //부모 클래스 참조변수로 자식 객체 생성 
		ob.view1();   // view11    자식도 가지고 있으니 자식 클래스의 메서드를 가져온다
//		ob.view2();   // error
		ob.view3();   // view3     자식이 안 가지고 있으니 자신의 메서드 실행
		
		//자식 클래스는 부모 클래스가 뭔지 아니까 접근해서 가져오기 가능 
		Test2 ob=new Test2();    
		ob.view1();   // view11    
		ob.view2();   // view22
		ob.view3();   // view3     자기가 안 가지고 있으니 부모 클래스에 메서드가 있는지 확인
	}
}

Test1 ob=new Test2( ); 로 쓰는 이유는 부모 클래스에서 자식 클래스에 있는 메서드를 사용하고 싶을 때 사용한다. 코드의 절약 & 다형성 활용할려고 사용

ex) Fruit( )라는 부모 클래스와 Peach, Banana와 같은 자식 클래스가 있을 때

Fruit peach = new Peach( ); Fruit banana = new Banana( ); 와 같이 사용이 가능하다.

Annotation: 사전적 의미 주석, 컴파일러,JVM,프레임워크 등이 보는 주석

  • 소스 코드에 붙여 놓은 라벨
  • 코드에 대한 정보 추가 → 소스 코드의 구조 변경, 환경 설정 정보 추가 등의 작업 진행

ex) @Deprecated, @Override, @SuppressWarinings


object 클래스 예시

toString 메서드: 객체를 문자열로 변경하는 메서드

public String toString(){
	return getClass().getName() + "@: + Integer.toHexString(hashcode());
}

사실 필요한 건 주소값이 아니라 안에 있는 내용이다. 

@Override
public String toString(){
	return "SpiderMan [isSpider=" +isSpider + ", name="+name+"]";
}

이런 식으로 오버라이드해서 메서드 재정의 

equals 메서드: 두 객체가 같은지를 비교하는 메서드

public boolean equals(Object obj){
	return(this == obj);
}

기본적으론 객체의 주소값이 같은지 비교하는 대상이 같은 객체인지 확인하는 메서드 
-> 보통 equals는 값이 같은지 다른지 비교하는 경우가 많다 -> override필요 

public boolean equals(Object obj){
	return(this.phone_number == obj.phone_nuber);
}

super 키워드 : this를 통해 멤버에 접근했듯이 super 를 통해 조상 클래스 멤버 접근

  • super. 을 이용해 조상의 메서드 호출로 조상의 코드 재사용
  • 사용된 위치에서 점점 확장해 가며 처음 만난 선언부에 연결됨
  • method 내부 → 해당 클래스 멤버 변수 → 조상 클래스 멤버 변수
class Parent{
	String x = "parent";
}

class Child extends Parent{
	String x = "child";
	void method(){
		String x = "method";
		System.out.println("x: "+x);
		System.out.println("this.x: "+this.x);
		System.out.println("super.x: "+super.x);
	}
		
	1. 현재상태: method ,child, parent
    2. method의 x 주석처리: child, child, parent
	3. child의 x 주석처리: parent, parent, parent
}

1. **this( )가 해당 클래스의 다른 생성자를 호출하듯 super( )는 조상 클래스의 생성자 호출** - 조상 클래스에 선언된 멤버들은 조상 클래스의 생성자에서 초기화가 이뤄진다. - 자식 클래스에 선언된 멤버들만 자식 클래스의 생성자에서 초기화

  1. super( )는 자식 클래스 생성자의 맨 첫 줄에서만 호출가능 ( this( )와 동일하다)
  2. 명시적으로 this( ) 또는 super ( )를 호출하지 않는 경우 컴파일러가 super( ) 삽입
  • 결론적으로 맨 상위의 Object까지 객체가 다 만들어지는 구조


    예제 code
class Branch {
	public Branch() {
		System.out.println("Default Branch Constructor");	
	}
	
	public Branch(String str, int n) {
		this();
		System.out.println(str+" "+ n +" "+ "Constructor");
	}
}

class Leaf extends Branch{	
	public Leaf() {
		this("ABC");
		System.out.println("Default Leaf Constructor");	
	}
	
	public Leaf(String str) {
		super(str,10);
		System.out.println(str+ " Leaf Constructor");	
	}
}

public class InheritanceEX3 {
	public static void main(String[] args) {
		new Leaf();
	}
}

실행값 

default Branch Constructor //부모 객체 먼저 생성된다
ABC 10 Branch Constructor
ABC Leaf Constructor
default Leaf Constructor

추가예제
################ Emp.java  ################

//default, 인자 2개, toString
public class Emp {
	private String name;
	private String phone;
	
	public Emp() {}

	public Emp(String name, String phone) {
		this.name = name;
		this.phone = phone;
	}

	@Override
	public String toString() {
		return "나의 이름은 " + name + "이고 연락처는 " + 
					phone + "입니다";
	}	
}

################ EmpScore.java  ################

public class EmpScore extends Emp {
	private double score;
	private char grade;
	
	public EmpScore() {
		super();
	}
	public EmpScore(String name, String phone, double score,char grade) {
		super(name, phone); //2개는 부모만 처리할 수 있으니까 부모 생성자로 보낸다
		this.score = score; //나머지는 자식 생성자에서 처리
		this.grade = grade;
	}
	@Override
	public String toString() {
		return super.toString() + "\n나의 점수는 " + score 
			+ "점이고 학점은 " + grade + "입니다";
	}
}

################ EmpMain.java  ################

public class EmpMain {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		 Emp ob1 = new Emp("이순신","010-1111-1111");
		 System.out.println(ob1);
		 EmpScore ob2 = new EmpScore("이순신","010-1111-1111",75.3,'C');
		 System.out.println(ob2);
	}

}

출력 값

나의 이름은 이순신이고 연락처는 010-1111-1111입니다
나의 이름은 이순신이고 연락처는 010-1111-1111입니다
나의 점수는 75.3점이고 학점은 C입니다

Static method는 상속이 될까? ⇒ X

class Parent2{
	static void method(){
		System.out.println("parent mode")
	}
}

class Child2 extends Parent2{
	static void method(){
		System.out.println("parent mode")
	}
}

@Override
class Child2 extends Parent2{
	static void method(){           //hiding => static method는 상속되지 않는다. 
		System.out.println("parent mode")
	}
}

0개의 댓글