Programming/JAVA

[JAVA] 상속 / 오버라이딩 / 관련 예제

Jayna. 2023. 12. 27. 16:34
728x90

 

상속

매 클래스마다 중복된 필드, 메소드들을 단 한 번 또는 하나의 클래스(부모클래스)로 정의해둔 후 해당클래스의 내용을 가져다 쓰는 개념. 기존의 클래스를 이용해서 새로운 클래스를 만든다.

 

>> 상속의 특징

 - 클래스 간의 다중상속 불가능(단일 상속만 가능)

 - 명시되어 있찌는 않지만 모든 클래스는 object 클래스의 후손이다.

   (모든 클래스란?  내가 만든 클래스, 자바에서 이미 제공하고 있는 클래스)

 

>> 상속의 장점

 - 중복된 코드를 공통적으로 관리할 수 있음

  => 새로운 코드를 작성하하거나 수정할 때 용이

  => 보다 적은 양의 코드로 새로운 클래스를 만들 수 있음

 - 프로그램의 생산성과 가독성을 높이고, 유지보수에 크게 기여함.

 

728x90

 

오버라이딩

 - 상속받고 있는 부모클래스의 메소드를 자식클래스에서 재정의(재작성)하는 것

 - 부모클래스가 제공하고 있는 메소드를 자식이 일부 고쳐서 사용하겠다는 의미

 - 자식클래스의 오버라이드 된 메소드가 우선권을 가져서 호출된다.

 - 성립조건

    * 부모메소드의 메소드명과 동일해야 한다.

    * 매개변수의 자료형, 개수, 순서가 동일해야 한다. 매개변수명과는 무관

    * 반환형이 동일해야 한다.

 

    * 접근 제어자를 조상클래스의 메소드보다 좋은 범위로 변경할 수 없다.

    * 예외는 조상 클래스의 메소드보다 많이 선언할 수 없다.

 

 - @Override

   어노테이션 => 생략 가능. 명시를 하지 않아도 부모메소드의 형태가 같으면 오버라이딩 된 것으로 판단.

 

>> 예제

[ Product.java ]

public class Product {

    // 공통되는 필드 : brand, pCode, pName, price
    // [필드부]
    private String brand;
    private String pCode;
    private String pName;
    private int price;

    // [생성자부]
    public Product() {

    }
    public Product(String brand, String pCode, String pName, int price) {
        this.brand = brand;
        this.pCode = pCode;
        this.pName = pName;
        this.price = price;
    }

    // [메소드부]
    public String getBrand() {
    	return brand;
    }
    public void setBrand(String brand) {
    	this.brand = brand;
    }
    public String getpCode() {
    	return pCode;
    }
    public void setpCode(String pCode) {
    	this.pCode = pCode;
    }
    public String getpName() {
    	return pName;
    }
    public void setpName(String pName) {
    	this.pName = pName;
    }
    public int getPrice() {
    	return price;
    }
    public void setPrice(int price) {
    	this.price = price;
    }

    public String information() {
    	return "brand : " + brand + "\npCode : " + pCode + "\npName : " + pName + 
       	"\nprice : " + price ; }
}

 

[ Desktop.java ] 

//자식클래스 extends 부모클래스이름
public class Desktop extends Product {
    // [필드부]
    // brand, pCode, pName, price, 
    private boolean allInOne;

    // [생성자부]
    public Desktop() {

    }

    // brand, pCode, pName, price : 부모클래스인 Product에 있는 필드에 초기화가 된다.
    public Desktop(String brand, String pCode, String pName, int price, boolean allInOne) {
    // 1. 부모클래스의 필드들의 접근제한자를 private에서 protected로 변경
    // 2. 부모클래스의 setter를 이용해서 PRoduct의 필드를 초기화 시켜주는 방법
    // 3. 부모틀래스의 생성자를 호출하여 Product의 필드를 초기화 시켜주는 방법 => 주로 이 방법을 많이 사용

    // 부모클래스에 있는 녀석들을 가져다 쓰기 위해서는 어떻게 해야 할까?
    // super.로 부모에 접근이 가능
    // 매개변수가 있는 부모클래스의 생성자 호출
    super(brand, pCode, pName, price);
    this.allInOne = allInOne;
    }

    // [메소드부]
    // 오버라이딩이라는 개념이 적용가능
    // brand, pCode, pName,price에 대한 setter/getter는 작성하지 않아도 호출이 가능 => 상속받았으니까
    // allInOne에 대한 setter/getter 작성

    public boolean isAllInOne() {
    return allInOne;
    }

    public void setAllInOne(boolean allInOne) {
    this.allInOne = allInOne;
    }

    public String information() {
    return super.information() + "\nallInOne : "+ allInOne;
    }
}
[ SmartPhone.java ]

//자식클래스이름 extends 부모클래스이름
public class SmartPhone extends Product {    // extends 

    // [필드부]
    public String mobileAgency;
    // + brand, pCode, pName, price => Product클래스에게 상속받음

    // [생성자부]
    // 생성자는 상속받을 수 없다.
    public SmartPhone() {

    }
    // 초기화를 모두 진행할 생성자
    public SmartPhone(String brand,String pCode, String pName, int price, String mobileAgency) {
    /*
     super : 해당 부모의 주소를 담고 있다. (즉, super. 부모에 접근가능)
     단, 접근하고자하는 그 어떤 것이 private일 경우 외부에서는 접근이 불가능하다(자식클래스도 접근불가)

     super.brand = brand;  => 불가능. 접근제한자가 private이기 때문
     필드를 찾을 수 없음 
     해결방법 1. 부모클래스의 필드를 자식까지는 접근 가능하도록 설정(private => protected) 
                => 캡슐화 원칙X (적잡한 방법은 아님)
     해결방법 2. 부모클래스에 있는 public 접근제한자인 setter메소드를 호출한다
    super.setBrand(brand);
    super.setpCode(pCo de);
    super.setpName(pName);
    super.setPrice(price);
    this.mobileAgency = mobileAgency;
         해결방법 3. 부모 생성자 호출
            super(brand, pCode, pName, price);
    */
    super(brand, pCode, pName, price);
    	this.mobileAgency = mobileAgency;
    }

    // [메소드부]
    // mobileAgency에 대한 getter/setter
    public String getMobileAgency() {
    	return mobileAgency;
    }
    public void setMobileAgency(String mobileAgency) {
    	this.mobileAgency = mobileAgency;
    }
}
[ TV.java ] 

public class TV extends Product {
    // [필드부]
    // brand, pCode, pName, price, inch
    private int inch;

    // [생성자부]
    // 기본생성자
    public TV() {

    }
    // 모든 필드에 대해 매개변수가 있는 생성자
    public TV(String brand, String pCode, String pName, int price, int inch) {
        // 부모에 있는 필드나 메소드에 접근하고자 할때는?
        // super.brand =    // 해당 필드가 private 이므로 접근 불가

        // 해결방법1. 부모의 private을 protected로 바꾼다.
        // 해결방법2. 부모의 setter 메소드를 호출해서 초기화한다. super.set필드이름();
        // 해결방법3. 부모의 모든 매개변수가 있는 생성자를 호출해서 초기화한다. super(매개변수들);

        //2번 방법 이용
        super.setBrand(brand);
        super.setpCode(pCode);
        super.setpName(pName);
        super.setPrice(price);
        this.inch = inch;
    }

    // [메소드부]
    public int getInch() {
    	return inch;
    }
    public void setInch(int inch) {
    	this.inch = inch;
    }
    public String information() {
    	return super.information() + "\ninch : " + inch;
    }
}

 

[ Run.java }

public class afterRun {

    public static void main(String[] args) {

    SmartPhone s = new SmartPhone("애플","app13","아이폰14", 1000000,"SKT");
    System.out.println(s.information());

    System.out.println();

    Desktop d = new Desktop("애플","d01","앱플데스트톱",5000000,true);
    System.out.println(d.information());

    System.out.println();

    TV t = new TV("엘지","tv01","엘지티비",8000000,70);
    System.out.println(t.information());

}
728x90