• Home
  • About
    • 2daistheday's Tech Blog photo

      2dayistheday

      Today is the day.

    • Learn More
    • Email
    • Facebook
    • LinkedIn
    • Instagram
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

상속

16 Aug 2017

Reading time ~4 minutes

JAVA

  1. 상속
    재활용 + 알파

  • 상속의 기본적인 특성

    public class Man {
    	public String name;
    	public void tellYourName(){
    		System.out.println("My name is "+name);
    	}
    }
    
    class BusinessMan extends Man{
    	public String company;
    	public String position;
    	public void tellyourInfo(){
    		System.out.println("My company is "+ company);
    		System.out.println("My position is "+ position);
    		tellYourName(); //Man 클래스의 메서드
    	}
    }
    

Man : 상위 클래스(super class) or 기초클래스

BusinessMan : 하위 클래스(sub class) or 유도 클래스(derived class)

  • 상속과 생성자

    public class Man {
    	private String name;
    	public Man(String name){
    		this.name = name;
    	}
    	public void tellYourName(){
    		System.out.println("My name is "+name);
    	}
    }
    
    class BusinessMan extends Man{
    	private String company;
    	private String position;
    	public BusinessMan(String name, String company, String position){
    		super(name); //상위 클래스의 생성자 호출
    		this.company = company;
    		this.position = position;
    	}
    	public void tellyourInfo(){
    		System.out.println("My company is "+ company);
    		System.out.println("My position is "+ position);
    		tellYourName();
    	}
    }
    

하위 클래스의 생성자에서는 제일 먼저 상위 클래스의 생성자를 호출해야 한다. 하지만 상위 클래스의 생성자가 디폴트인 경우는 super();문이 자동으로 하위 클래스의 생성자에 삽입되기 때문에 컴파일은 정상적으로 이뤄진다.

  • 상속과 접근제어 지시자

    지시자 클래스 내부 동일 패키지 상속받은 클래스 이외의 영역
    private o x x x
    default o o x x
    protected o o o x
    public o o o o
  • static 변수(메소드)의 상속과 생성자의 상속에 대한 논의

    static 변수는 생성되는 인스턴스마다 독립적으로 존재하는 멤버가 아니고, 생성되는 인스턴스가 함께 공유하는 변수 및 메소드이다.

    class Adder{
    	public static int val = 0;
    	public void add(int num){
    		val+=num;
    	}
    }
    
    class AdderFriend extends Adder{
    	public void friendAdd(int num){
    		val+=num;
    	}
    	public void showVal(){
    		System.out.println(val);
    	}
    }
    
    public class StaticInheritance{
    	public static void main(String[] args){
    		Adder ad = new Adder();
    		AdderFriend af = new AdderFriend();
    		ad.add(1);
    		af.friendAdd(3);
    		AdderFriend.val+=5;
    		af.showVal();
    	}
    }
    

상위 클래스에 정의된 static 변수는 하위 클래스에서도 이름만으로 접근이 가능하다. 그게 아니라면 클래스의 이름으로 접근할 수 있다.

  • 생성자도 상속이 되나요?
    안됩니다. 하지만 AAA(int n) { num = n;} 은 AAA를 상속받는 생성자에서 BBB(int n) {num = n;}인 것과 같다.
  • 상속을 위한 기본 조건 IS-A 관계
    무선 전화기는 전화기이다. 처럼 ~IS A. 여기서 A가 상위 클래스 ~가 하위 클래스가 된다.
  • HAS-A 관계도 상속의 조건은 되지만 복합 관계로 이를 대신하는 것이 일반적이다.
    Gun 클래스를 Police가 상속받을 수도 있지만 Police의 멤버변수로 Gun을 가지고 있는 관계가 유연성이 좋다.
  • 하위 클래스에서 메소드를 다시 정의하면?

    class Speaker
    {
    	private int volumeRate;
    	public void showCurrentState(){
    		System.out.println("볼륨 크기: "+ volumeRate);
    	}
    	public void setVolume(int vol){
    		volumeRate=vol;
    	}
    }
    
    class BaseEnSpeaker extends Speaker{
    	private int baseRate;
    	public void showCurrentState(){
    		super.showCurrentState(); //필수 아님. 상위의 같은 이름 메소드를 부르기 위함
    		System.out.println("베이스 크리 : "+baseRate);
    	}
    	public void setBaseRate(int base){
    		baseRate= base;
    	}
    }
    
    class Overriding{
    	public static void main(String[] args){
    		BaseEnSpeaker bs = new BaseEnSpeaker();
    		bs.setVolume(10);
    		bs.setBaseRate(20);
    		bs.showCurrentState();
    	}
    }
    
  • 상위 클래스의 참조변수로도 하위 클래스의 인스턴스를 얼마든지 참조 가능
    중 저음 보강 스피커(BaseEnSpeaker)는 (일종의)스피커다. (O) -> Speaker sp = new BaseEnSpeaker(); Speaker의 참조변수로 BaseEnSpeaker() 인스턴스를 참조하고 있다.
    Speaker bs = new BaseEnSpeaker();
    		bs.setVolume(10);
    		bs.setBaseRate(20); //컴파일 에러!
    
  • 문제: 해당 상황에서 오버라이딩 된 메소드를 호출하면 누가 호출되는

    package i_didnt_study_java;
    
    class AAA
    {
    	public void rideMethod(){
    		System.out.println("AAA's Method");
    	}
    	public void loadMethod(){
    		System.out.println("void Method");
    	}
    }
    class BBB extends AAA
    {
    	public void rideMethod(){
    		System.out.println("BBB's Method");
    	}
    	public void loadMethod(int num){
    		System.out.println("int Method");
    	}
    }
    class CCC extends BBB
    {
    	public void rideMethod(){
    		System.out.println("CCC's Method");
    	}
    	public void loadMethod(double num){
    		System.out.println("double Method");
    	}
    }
    class RideAndLoad
    {
    	public static void main(String[] args){
    		AAA ref1 = new CCC();
    		BBB ref2 = new CCC();
    		CCC ref3 = new CCC();
      		
    		ref1.rideMethod();
    		ref2.rideMethod();
    		ref3.rideMethod();
      		
    		ref3.loadMethod();
    		ref3.loadMethod(1);
    		ref3.loadMethod(1.2);
    	}
    }
    

참조변수의 자료형에 상관없이 마지막으로 오버라이딩을 한 메소드만 호출된다. loadMethod를 보면 오버로딩의 관계를 구성하는 것을 알 수 있다.

+이것을 통한 활용+
상위 클래스의 참조변수는 하위 클래스의 인스턴스를 참조할 수 있다. 오버라이딩 된 상위 클래스의 메소드는 오버라이딩을 한 하위 클래스의 메소드에 의해 가리워진다. 즉 외부에서는 참조변수를 통해 오버라이딩 된 상위 클래스의 메소드를 호출할 수 없다.
  • 하지만 인스턴스 변수는 참조변수의 자료형에 따라 접근이 차이가 있다.

  • 참조변수의 인스턴스 참조와 instanceof 연산자

    public static void wrapBox(Box box){
      if(box instanceof GoldPaperBox){
        ((GoldPaperBox)box).goldWrap();
      }else if(box instanceof PaperBox){
        ((PaperBox)box).paperWrap();
      }else{
        box.simpleWrap();
      }
    }
    

    :상속을 바탕으로 형변환이 가능한지 묻는 연산자(true와 false 반환)

  • instanceof를 쓰지 않고 해결하는 방법

    class Box{
    	public void simpleWrap(){
    		System.out.println("simple wrap");
    	}
    	public void wrap(){}
    }
    
    class PaperBox extends Box{
    	public void paperWrap(){
    		System.out.println("paper wrap");
    	}
      	
    }
    
    class GoldPaperBox extends PaperBox{
    	public void goldWrap(){
    		System.out.println("gold wrap");
    	}
    	public void wrap(){
            
    	}
    }
    
    class InstanceOf{
    	public static void wrapBox(Box box){
     	Box.wrap();
    }
      	
    	public static void main(String[] args){
    		Box box1 = new Box();
    		PaperBox box2 = new PaperBox();
    		GoldPaperBox box3 = new GoldPaperBox();
      		
    		wrapBox(box1);
    		wrapBox(box2);
    		wrapBox(box3);
    	}
    }
    
  • 모든 클래스가 상속하는 Object 클래스
    class MyClass{ ~~ }는 class MyClass extends Object{ ~~ }와 같다. (다른 클래스 상속시 제외)
    Object obj1 = new MyClass();
    Object obj2 = new int[5];
    

    +참고: class MyClass extends YourClass라고 해도 YourClass는 Object클래스를 상속받으므로, 간접상속이 이뤄진다. toString()을 오버라이딩함으로 원래의 ‘인스턴스 정보를 문자열로 반환’을 적절히 바꾼다.

  • final class MyClass : 상속을 허용하지 않음. (String 클래스가 대표적인 final선언 클래스)

  • final void yourFunc(int n) : 이 메소드의 오버라이딩을 허용하지 않겠다. (wait, notify, notifyall 메소드가 예)

  • abstract 클래스
    상속의 관계를 형성하기 위한 상위 클래스, 인스턴스화 시키기 위해서 정의한 클래스가 아닌 경우
    public abstract class Friend {
    	public void showData(){
    		System.out.println("데이터 보여주기");
      		
    	}
    	public abstract void showBasicInfo();
    }
    

    추상 클래스를 상속하는 하위 클래스에서는 추상 메소드를 오버라이딩해야 한다.



JAVA상속class추상클래스 Share Tweet +1