프로그래밍 언어응용-상속
상속 : 다른 클래스가 가지고 있는 멤버(필드, 메소드)들을 새로 작성할 클래스에서 직접 만들지 않고 상속을 받음으로써 새 클래스가 자신의 멤버처럼 사용할 수 있는 기능
# 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붙여줌 => 주소
}
}