thesunset 2022. 9. 25. 13:57

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

# Tv

package com.kh.chap01_beforeVSafter.before.model.vo;

public class Tv {

private String brand;

private String pCode;

private String pName;

private int price;

private int inch;

//필드를 다 쓴 뒤, alt+ shift + s => o => alt+d => alt+g => 기본생성자

public Tv() {}

//alt+ shift + s => o => alt+g => 매개변수생성자

public Tv(String brand, String pCode, String pName, int price, int inch) {

super();

this.brand = brand;

this.pCode = pCode;

this.pName = pName;

this.price = price;

this.inch = inch;

}

//메소드부

//alt+shift+s => r => alt+a => alt+r

//getter / setter 자동완성

//찾아바꾸기 ctrl + f

public void setBrand(String brand) {

this.brand = brand;

}

public String getBrand() {

return brand;

}

public void setPCode(String pCode) {

this.pCode = pCode;

}

public String getPCode() {

return pCode;

}

public void setPName(String pName) {

this.pName = pName;

}

public String getPName() {

return pName;

}

public void setPrice(int price) {

this.price = price;

}

public int getPrice() {

return price;

}

public void setInch(int inch) {

this.inch = inch;

}

public int getInch() {

return inch;

}

public String information() {

return brand + " " + pCode + " " + pName + " " + price + " " + inch;

}

}


# Desktop

package com.kh.chap01_beforeVSafter.before.model.vo;

public class Desktop {

private String brand;

private String pCode;

private String pName;

private int price;

private boolean allInOne;

public Desktop(){}

public Desktop(String brand, String pCode, String pName, int price, boolean allInOne) {

super();

this.brand = brand;

this.pCode = pCode;

this.pName = pName;

this.price = price;

this.allInOne = allInOne;

}

public void setBrand(String brand) {

this.brand = brand;

}

public String getBrand() {

return brand;

}

public void setPCode(String pCode) {

this.pCode = pCode;

}

public String getpCode() {

return pCode;

}

public void setpName(String pName) {

this.pName = pName;

}

public String getpName() {

return pName;

}

public void setPrice(int price) {

this.price = price;

}

public int getPrice() {

return price;

}

public void setAllInOne(boolean allInOne) {

this.allInOne = allInOne;

}

public boolean getAllInOne() {

return allInOne;

}

public String information() {

return brand + " " + pCode + " " + pName + " " + price + " " + allInOne;

}

}


# SmartPhone

package com.kh.chap01_beforeVSafter.before.model.vo;

public class SmartPhone {

private String brand;

private String pCode;

private String pName;

private int price;

private String mobileAgency;

public SmartPhone() {

}

public SmartPhone(String brand, String pCode, String pName, int price, String mobileAgency) {

super();

this.brand = brand;

this.pCode = pCode;

this.pName = pName;

this.price = price;

this.mobileAgency = mobileAgency;

}

public void setBrand(String brand) {

this.brand = brand;

}

public String getBrand() {

return brand;

}

public void setPCode(String pCode) {

this.pCode = pCode;

}

public String getPCode() {

return pCode;

}

public void setPName(String pName) {

this.pName = pName;

}

public String getPName() {

return pName;

}

public void setPrice(int price) {

this.price = price;

}

public int getPrice() {

return price;

}

public void setMobileAgency(String mobileAgency) {

this.mobileAgency = mobileAgency;

}

public String getMobileAgency() {

return mobileAgency;

}

public String information() {

return brand + " " + pCode + " " + pName + " " + price + " " + mobileAgency;

}

}


# BeforeRun

package com.kh.chap01_beforeVSafter.before.run;

import com.kh.chap01_beforeVSafter.before.model.vo.Desktop;

import com.kh.chap01_beforeVSafter.before.model.vo.SmartPhone;

import com.kh.chap01_beforeVSafter.before.model.vo.Tv;

public class BeforeRun {

public static void main(String[] args) {

//desktop객체 생성

//brand pCode pName price allInOne

Desktop d = new Desktop("DIY", "p01", "호랑이", 2000000, false);

//SmartPhone 객체를 생성

//brand pCode pName price mobileAgency

SmartPhone s = new SmartPhone("LG", "v-01", "베가", 200000, "LG");

//Tv 객체를 생성

//brand pCode pName price inch

Tv t = new Tv("LG", "n-tv" , "나노셀TV", 8000000, 80);

System.out.println(d.information());

System.out.println(s.information());

System.out.println(t.information());

}

/*

* 매 클래스마다 중복된 코드들을 하나하나 기술하게 되면

* 수정과 같은 유지보수를 할 경우 매 번 하나하나 다 찾아서 수정해야하는 번거로움이 생김

*

* 상속이라는 개념을 적용시켜서

* 매 클래스마다 중복된 필드, 메소드

* 단 하나의 클래스(부모클래스)로 만들어놓고, 정의를 해두고

* 그 해당 클래스의 속성, 행위를 가져다 쓰는 형식으로 진행할 것!!

*

*/


# Product

package com.kh.chap02_beforeVSafer.after.model.vo;

/*

* 상속

* 매 클래스마다, 중복된 필드, 메소드들을 단 한 번의 또 하나의 클래스(부모클래스)로 정의해둔 후

* 해당 클래스의 내용을 가져다쓰는 개념

*

* "기존의 클래스를 이용해서 새로운 클래스를 만든다." == 상속

*

*/

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) {

super();

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 + ", pCode: " + pCode + ", pName: " + pName + ", price: " + price;

}

}


# Tv

package com.kh.chap02_beforeVSafer.after.model.vo;

public class Tv extends Product {

//필드부

private int inch;

//생성자부

public Tv() {

}

//부모에 있는 필드나 메소드에 접근하려고 할 때는 ? super

//super.brand = private이니 접근 불가

//해결방법1. 부모의 private을 protected로 바꿔준다.

//해결방법2. 부모의 setter 메소드를 호출해서 초기화한다. super.set필드이름();

//해결방법3. 부모의 모든 매개변수가 있는 생성자를 호출해서 초기화한다. super(매개변수들);

//2번방법이용

public Tv(String brand, String pCode, String pName, int price, int inch) {

super.setBrand(brand);

super.setpCode(pCode);

super.setpName(pName);

super.setPrice(price);

this.inch = inch;

}

/*

* 여기까지는 필수 작성요소들 모두 작성!

* information() 부모로부터 상속을 받음 => 덮어쓰기를 할 수 있음

* 오버라이딩

*/

public String information() {

return super.information() + ", inch: " + inch;

}

}


# Desktop

package com.kh.chap02_beforeVSafer.after.model.vo;

// 부모클래스 자식클래스

// 조상클래스 후손클래스

// 상위클래스 하위클래스

// 슈퍼클래스 서브클래스

// 확장클래스 파생클래스

//자식클래스 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) {

super(brand, pCode, pName, price);

this.allInOne = allInOne;

}

//메소드부

//오버라이딩이라는 개념을 적용이 가능

//brand, pCode, pName, price // setter,getter 작성하지 않아도 호출 가능 => 상속 받았기 때문

public boolean isAllInOne() {

return allInOne;

}

public void setAllInOne(boolean allInOne) {

this.allInOne = allInOne;

}

public String information() {

return super.information() + ", allInOne: " + allInOne;

}

}


# SmartPhone

package com.kh.chap02_beforeVSafer.after.model.vo;

public class SmartPhone extends Product { // 자식클래스 extends 상속받을부모클래스

//필드부

// brand, pCode, pName, price

private String mobileAgency;

//생성자부

//생성자는 상속을 받을 수 없다.

public SmartPhone() {

} //기본적으로 부모객체 공간 할당 뒤 자식공간이 추가로 만들어짐.

//초기화를 모두 진행할 생성자

public SmartPhone(String brand, String pCode, String pName, int price, String mobileAgency) {

//this.brand = brand;

//this에는 주소값이 들어있음.(SmartPhone의)

//super : 해당 부모의 주소를 담고 있음. (super. 부모에 접근 가능)

//super.brand = brand; => 접근제한자가 private이기 때문에 보이지않음

//해결방법 3가지

//1. 부모클래스의 필드를 자식까지는 접근가능하도록 설정 private => protected로 변경

// => 캡슐화 원칙에 위배됨. 적합한 방법이 x

//2. 부모클래스에 있는 public접근제한자 setter메소드를 호출한다.

/*

super.setBrand(brand);

super.setpCode(pCode);

super.setpName(pName);

super.setPrice(price);

*/

//3. 부모생성자를 호출하기

super(brand, pCode, pName, price);

this.mobileAgency = mobileAgency;

}

//메소드부

public String getMobileAgency() {

return mobileAgency;

}

public void setMobileAgency(String mobileAgency) {

this.mobileAgency = mobileAgency;

}

}


# AfterRun

package com.kh.chap02_beforeVSafer.after.run;

import com.kh.chap02_beforeVSafer.after.model.vo.Desktop;

import com.kh.chap02_beforeVSafer.after.model.vo.SmartPhone;

import com.kh.chap02_beforeVSafer.after.model.vo.Tv;

public class AfterRun {

public static void main(String[] args) {

//Product p = new Product();

//무조건 부모생성자를 호출하는 부분이 생략되어있음, 따라서 부모생성자의 공간만큼 만든 뒤 확장해 자식이 들어가는 것.

SmartPhone sp = new SmartPhone("LG", "v-01", "베가", 100000, "LG");

//sp.setBrand("LG");

System.out.println(sp.information()); //먼저 우선순위가 자식클래스, 자식클래스에서 먼저 찾고 없으면 부모클래스에서 찾음

//내가 호출하고자하는 메소드가 해당 클래스에 존재하지 않는다면

//자동으로 해당클래스의 부모클래스에 있는 메소드로 호출됨.

Tv t = new Tv("엘지", "tv01", "티비는 엘지지", 8000000, 100);

System.out.println(t.information());

Desktop d = new Desktop("애플", "ml01", "Mac", 3000000, true);

System.out.println(d.information());

//자식클래스에 오버라이딩(부모클래스의 메소드를 다시 씀)을 했을 경우

//자식클래스에 오버라이딩된 메소드가 우선권을 가져서 호출

/*

* 상속의 장점

*

* - 중복된 코드를 공통으로 관리

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

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

*

* - 프로그램의 생산성과 가독성과 유지보수에 크게 기여

*

* 최근 트렌드는 상속을 최대한 줄이고 연관관계로 바꾸는 편

*

* 하지만, 상속이없으면 다형성이라는 개념을 사용할 수 없기에 공부해야 함.

*

* 상속의 특징

*

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

*

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

*

* 기본적으로 public class A extends Object

*

* => object클래스에 있는 메소드를 호출해 쓸 수 있음. **중요

* (모든클래스: 내가 만든 클래스, 자바에서 이미 제공하는 클래스)

* => object클래스에 있는 메소드가 맘에 안들면 오버라이딩을 통해 재정의 가능

*/

}

}


# Vehicle - 부모

package com.kh.chap03_inherit.model.vo;

public class Vehicle {

//탈것의 이름, 거리, 종류

private String name;

private double mileage;

private String kind;

public Vehicle() {

}

public Vehicle(String name, double mileage, String kind) {

this.name = name;

this.mileage = mileage;

this.kind = kind;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public double getMileage() {

return mileage;

}

public void setMileage(double mileage) {

this.mileage = mileage;

}

public String getKind() {

return kind;

}

public void setKind(String kind) {

this.kind = kind;

}

public void howTiMove() {

System.out.println("움직인다");

}

//마지막으로 information을 선언했다.

//object클래스에 기존에 있던 메소드를 오버라이딩(재정의)해서 쓸 것

//information대신 toString을 오버라이딩해서 쓸 것.

public String toString() {

return " name: " + name + ", mileage: " + mileage + " kind: " + kind;

}

}


# Horse

package com.kh.chap03_inherit.model.vo;

public class Horse extends Vehicle {

private int winCount;

public Horse() {

}

public Horse(String name, double mileage, String kind, int winCount) {

super(name, mileage, kind);

this.winCount = winCount;

}

public int getWinCount() {

return winCount;

}

public void setWinCount(int winCount) {

this.winCount = winCount;

}

public void howToMove() {

System.out.println("휘항찬란하게 움직인다.");

} //메소드 오버라이딩

public String toString() {

return super.toString() + ", winCount: " + winCount;

}

}


# Autocycle

package com.kh.chap03_inherit.model.vo;

public class AutoCycle extends Vehicle {

private double cc;

public AutoCycle() {}

public AutoCycle(String name, double mileage, String kind, double cc) {

super(name, mileage, kind);

this.cc = cc;

}

public double getCc() {

return cc;

}

public void setCc(double cc) {

this.cc = cc;

}

public void howToMove() {

System.out.println("부릉부릉하며 움직인다.");

}

public String toString() {

return super.toString() + ", cc: " + cc;

}

}


# Ship

package com.kh.chap03_inherit.model.vo;

public class Ship extends Vehicle {

private int propeller;

public Ship() {

}

public Ship(String name, double mileage, String kind, int propeller) {

super(name, mileage, kind);

this.propeller = propeller;

}

public int getPropeller() {

return propeller;

}

public void setPropeller(int propeller) {

this.propeller = propeller;

}

public void howToMove() {

System.out.println(" 프로펠라 돌려서 움직인다. ");

}

public String toString() {

return super.toString() + ", toString: " + propeller;

}

}


# Run

package com.kh.chap03_inherit.run;

import com.kh.chap03_inherit.model.vo.AutoCycle;

import com.kh.chap03_inherit.model.vo.Horse;

import com.kh.chap03_inherit.model.vo.Ship;

import com.kh.chap03_inherit.model.vo.Vehicle;

public class Run {

public static void main(String[] args) {

//이름, 연비, 종류, 우승횟수

Horse h = new Horse("적토마", 10.0, "동물", 10);

AutoCycle a = new AutoCycle("부가티", 15.0, "이륜자동차", 800 );

Ship s = new Ship("새우잡이배", 3.0, "어선", 15);

Vehicle v = new Vehicle("탈것,", 1, "ㅇㅇ");

// 기본적으로 객체 이름으로 정한 변수는 출력문 안에 들어가면 자동으로 뒤에 .toString이 붙음 = Object의 것이기때문(부모클래스)

System.out.println(h/*.toString*/); //항상 toString가 붙어있는 값이 인출되었기 때문에 주소값이 출력되었기때문

// toString() : 해당 객체의 풀클래스명 + @ + 해당 객체의 주소값(16진수형태) 형태로 반환 : 문자열형

// 앞으로 Object클래스의 toString이라는 메소드를 오버라이딩(주소값이었던 형태를 부모클래스에서 지정한 형태로 덮어씀) 해서 사용할 것!

System.out.println(a);

System.out.println(s);

h.howToMove();

a.howToMove();

s.howToMove();

}

}


# Book

package com.kh.chap04_override.model.vo;

public class Book /*extends Object 생략 */{

//모든 클래스의 최상위 부모클래스는 object => 생략가능

//필드

//제목, 가격

private String title;

private int price;

public Book() {

}

public Book(String title, int price) {

this.title = title;

this.price = price;

}

public String getTitle() {

return title;

}

public void setTitle(String title) {

this.title = title;

}

public int getPrice() {

return price;

}

public void setPrice(int price) {

this.price = price;

}

//toString도 자동완성기능

//shift + alt + s => s

@Override

public String toString() {// 내 마음대로 덮어쓰기 (재정의)

return "Book [title=" + title + ", price=" + price + "]";

}

/*

* 오버라이딩(Overriding)

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

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

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

*

* 오버라이딩의 성립조건

* 1. 부모메서드의 메서드명과 동일

* 2. 매개변수의 자료형, 갯수, 순서가 동일(매개변수명과는 무관)

* 3. 반환형이 동일

*

* => 규약의 개념

* 4. 부모메서드의 접근제한자보다 같거나 공유범위가 넓어야 함

*

* @Override

* 어노테이션(annotation)

* 일종의 주석

* - 생략 가능

* => 명시를 안해도 부모메서드와 형태가 같으면 오버라이딩 된 것으로 판단

*

* - 어노테이션을 붙이는 이유

* => 실수를 줄이기 위해

* => 누가봐도 오버라이딩

*

* 개발자들끼리의 약속

* 생략은 가능하지만 작성하는 습관을 들이자!

*

*/

}


# Run

package com.kh.chap04_override.run;

import com.kh.chap04_override.model.vo.Book;

public class Run {

public static void main(String[] args) {

Book b = new Book("자바의 정석", 10000);

System.out.println(b.toString());//오브젝트에 가서 호출 => 주소 -> toString 함수 입력 후에는 입력한 값 출력

System.out.println(b);//자동으로 toString붙여줌 => 주소

}

}