본문 바로가기

웹개발 수업/JAVA

[Day +14]상속 / 오버라이딩, 오버로딩, for each문

210712 월

 

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

 

1) 목적

: 클래스의 재사용, 연관된 일련의 클래스에 대한 공통적인 규약 정의
-코드의 양이 줄어들 수 있음.

2) 장점

-보다 적은 양의 코드로 새로운 클래스 작성 가능

-코드를 공통적으로 관리하기 때문에 코드의 추가 및 변경 용이

-중복을 제거하여 프로그램의 생산성과 유지보수에 크게 기여할 수 있다

 

3) 특징

(1) 모든 클래스는 Object 클래스의 후손

-Object클래스가 제공하는 메소드를 오버라이딩하여 메소드 재구현 가능

 

*오버라이딩

: 부모가 가진 기능을 자식이 고쳐서 사용하는 것

ex) java.lang.String 클래스의 equals()와 toString()

 

(2) 부모 클래스의 생성자, 초기화 블록은 상속 안됨

=> 따라서 자식 클래스 생성자 안에서 부모 클래스 생성자 호출을 명시하고 싶으면 super()활용

 

(3) 부모의 private멤버는 상속은 되지만 직접 접근이 불가능하다

=> 따라서 super()을 이용하여 전달받은 부모 필드 값을부모 생성자 쪽으로 넘겨서 생성하거나 setter, getter메소드를 이용하여 접근

 

1> 부모 클래스 - Product

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

public class Product {
	
	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(); 
        //Q. 자동으로 만들어줄 경우 왜 super가 생길까? 
		//A. Object 클래스가 모든 클래스의 부모이므로 Object 클래스의 생성자를 호출한다
		
        //super : 부모를 읽는 키워드, this : 자기 자신의 객체를 읽는 키워드
		
		this.brand = brand;
		this.pCode = pCode;
		this.pName = pName;
		this.price = price;

	}

	public String getBrand() {
		return brand;
	}
	public String getpCode() {
		return pCode;
	}
	public String getpName() {
		return pName;
	}
	public int getPrice() {
		return price;
	}
	
	public void setBrand(String brand) {
		this.brand = brand;
	}
	public void setpCode(String pCode) {
		this.pCode = pCode;
	}
	public void setpName(String pName) {
		this.pName = pName;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	
	
	public String information() {
		return "brand : " + brand + ", pCode : " + pCode + ", pName : " +
				pName + ", price : " + price;
	}
	
	public void print() {
		System.out.println("나 Product 객체야!");
	}
	
}

2-1> 자식 클래스 - Desktop

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

//Product를 상속받는 Desktop 클래스
public class Desktop extends Product{
	//Desktop이 자식, Product가 부모
	//extends : 확장한다는 뜻
	//부모의 것을 물려받고 자신의 것을 추가하여 클래스를 확장한다
	
	private boolean allInOne;
	
	public Desktop() {}
	//super();가 내포되어 있음, 명시적으로 표기하지 않아도 동작한다
	//Product의 기본 생성자가 명시되지 않았을 시 오류가 발생한다
	
	public Desktop(String brand, String pCode, 
    				String pName, int price, boolean allInOne) {
	//Q. 왜 다 써줘? 
    //A. new Desktop하는 순간 내가 전달받은 필드값을 초기화 하려고.
		
	//Q. allInOne을 중간에 넣어줘도 되나? 
    //A. 문제 없음. 근데 순서 바뀜
		
		super(brand, pCode, pName, price); 
        //부모객체가 가진 생성자를 받아오는 것을 의미 / 줄바꾸면 오류남
		//후손 생성자 안에 포함 시키며 반드시 첫 줄에 표기
		
		
		//this.brand = brand; 이건 안됨
		this.allInOne = allInOne; //이건 가능
	}

	public boolean isAllInOne() {
		return allInOne;
	}

	public void setAllInOne(boolean allInOne) {
		this.allInOne = allInOne;
	}
	
	@Override //이걸 붙이면 오버라이드가 명확해짐, 왼쪽의 초록색은 오버라이드라는 뜻
	public String information() {
		return super.information() + ", allInOne : " + allInOne;
			
		}
	
	//Product 클래스의 print 메소드 오버라이딩
	//위에 @Override를 기록해주면 상속이 명확해진다.
	public void print() {
		System.out.println("나 Desktop 객체야!");
	}
	
	}

2-2> 자식 클래스 - Smartphone

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

public class SmartPhone extends Product {

	 private String mobileAgency;
	 
	 public SmartPhone() {}
	 
	 public SmartPhone(String brand, String pCode, 
     					String pName, int price, String mobileAgency) {
		 
		 super(brand, pCode, pName, price);
		 this.mobileAgency = mobileAgency;
	 }

	public String getMobileAgency() {
		return mobileAgency;
	}

	public void setMobileAgency(String mobileAgency) {
		this.mobileAgency = mobileAgency;
	}
	
	@Override
	public String information() {
		return super.information() + ", mobileAgency : " + mobileAgency;
	
}
	//Product 클래스의 print 메소드 오버라이딩
	public void print() {
		System.out.println("나 SmartPhone 객체야!");
	}
}

2-3> 자식 클래스 - Tv

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

public class Tv extends Product{
	
	private int inch;
	
	public Tv() {}
	
	public Tv(String brand, String pCode, String pName, int price, int inch) {
		super(brand, pCode, pName, price);
		this.inch = inch;
		}

	public int getInch() {
		return inch;
	}

	public void setInch(int inch) {
		this.inch = inch;
	}
	@Override
	public String information(){
		return super.information() + ", inch : " + inch;
		
	}
	//Product 클래스의 print 메소드 오버라이딩
		public void print() {
			System.out.println("나 Tv 객체야!");
		}
}

 

<실행>

package com.kh.chap01_inherit.after.run;

import com.kh.chap01_inherit.after.model.vo.Desktop;
import com.kh.chap01_inherit.after.model.vo.SmartPhone;
import com.kh.chap01_inherit.after.model.vo.Tv;

public class Run {

	public static void main(String[] args) {
		
		//해당 클래스를 객체(인스턴스)화 시켜준다.
		
		//Desktop 객체 생성
		Desktop d = new Desktop("삼성", " d-01", "짱짱데스크탑", 20000000, true);
		//기본 생성자로 만들지 않고 매개변수 생성자로 만들어 준다
		
		//SmartPhone 객체 생성
		SmartPhone s = new SmartPhone("사과", "s-01", "아이폰", 1500000, "Kr");

		//Tv 객체 생성
		Tv t = new Tv("LG", "t-01", "겁나 얇은 티비", 3500000, 46);
		
		
		System.out.println(d.information());
		System.out.println(s.information());
		System.out.println(t.information());
		
		
	//오버라이딩 테스트
	//부모 클래스의 메소드를 자식 클래스에서 재정의
	//오버라이딩 규칙을 잘 지켜서 작성했을 경우 @Override 어노테이션 없이 적용되지만
	//@Override 어노테이션 작성 시 컴파일러가 체크해주기 때문에 명시 권장
		d.print();
		s.print();
		t.print();
		
	}

}

 

 

 

4) 방법

extends 사용

 

5) 표현식

[접근제한자] class 클래스명 extends 클래스명 {}

public class 자식 extends 부모{}

 

6) 단일 상속과 다중 상속

(1) 단일상속

=> 자바에서는 단일 상속만 가능하다

예) extends A, B, C 불가능

(2) 다중상속

=> A 클래스와 B클래스에 똑같은 기능이 있을 때 C가 누구의 것을 가져오는지 모호하기 때문에 자바에서는 단일 상속만 허락한다

 

*super()와 super
1> super()
부모 객체의 생성자
2> super. 
상속을 통한 자식 클래스 정의 시 해당 자식 클래스의 부모 객체를 가리키는 참조 변수

 

 

7) 오버라이딩

: 자식 클래스가 부모 메소드를 재작성하는 것

-후손이 부모를 일부 고쳐서 사용하겠다는 것

-자식 객체를 통한 실행 시 후손 것이 우선권을 가짐

(1) 특징

-메소드 헤드라인 위에는 반드시 Annotation, @Override 표시

-접근 제어자를 부모 것보다 같거나 넓은 범위로 변경 가능, But 좁은 범위로 변경하는 것은 불가능하다

(2) 성립 조건

=> 부모 클래스의 메소드와 자식 클래스의 메소드 비교

-메소드 이름 동일

-매개변수의 개수, 타입 동일

-리턴 타입 동일

-private 메소드는 오버라이딩이 불가능하다

 

*오버로딩
: 한 클래스 내에서 같은 이름의 메소드를 여러 개 정의하는 것
(이름이 헷갈릴 수 있으니, 면접에서 물어보는 경우가 왕왕 있다)


<성립 조건>
-같은 메소드 이름
-다른 매개변수 선언부(매개변수 타입, 개수, 순서)

 

오버라이딩 vs 오버로딩

1> 조상 - Vehicle

package com.kh.chap01_inherit.model.vo;

	//조상 클래스로 선언하자
	public /*final*/ class Vehicle { 
	//final을 붙여줄 경우 상속관련한 문제가 생긴다
	
	private String name; 	//이름
	private double mileage; //연비
	private String kind;	//종류
	
	public Vehicle() {}
	
	
	//3개의 필드값을 매개변수로 받는 매개변수 생성자
	public Vehicle(String name, double mileage, String kind) {
		super();//Object의 
		this.name = name;
		this.mileage = mileage;
		this.kind = kind;
	}


	public String getName() {
		return name;
	}


	public double getMileage() {
		return mileage;
	}


	public String getKind() {
		return kind;
	}


	public void setName(String name) {
		this.name = name;
	}


	public void setMileage(double mileage) {
		this.mileage = mileage;
	}


	public void setKind(String kind) {
		this.kind = kind;
	}
	
	public String information() {
		return "name=" + name + ", mileage=" + mileage + ", kind=" + kind;
	}
	
	public void howToMove() {
		System.out.println("이렇게 움직이면 되지");
	}

	/*public final void howToMove() { => 이렇게 만들면 override 할수 없다
		System.out.println("이렇게 움직이면 되지");
		
		// 따라서 오버라이딩을 막고 싶으면 final을 쓰면 됨
	}*/
}

2-1> 후손 - Airplane

package com.kh.chap01_inherit.model.vo;

public class Airplane extends Vehicle{

	private int tire;
	private int wing;
	
	public Airplane() {}

	public Airplane(String name, double mileage, 
    				String kind, int tire, int wing) {
	//this.name = name;//(O) protected String name;로 바꿀 경우의 예시
	//super.name = name;//(O)
	//this.kind = kind;//(X)
		
		super(name, mileage, kind); //부모쪽에서 초기화할 값은 해주고
		this.tire = tire; //자손에서 해줘야 할 부분은 따로 해준다
		this.wing = wing;
	}

	public int getTire() {
		return tire;
	}

	public int getWing() {
		return wing;
	}

	public void setTire(int tire) {
		this.tire = tire;
	}

	public void setWing(int wing) {
		this.wing = wing;
	}
	
	@Override
	public String information() {
		return "Airplane [" + super.information() + ", tire=" + tire + ", "
				+ "wing=" + wing + "]";
	}
	
	@Override
	public void howToMove() {
		System.out.println("나는 뱅기");
	}	
}

2-2> 후손 - Car

package com.kh.chap01_inherit.model.vo;

public class Car extends Vehicle {
	
	private int tire;
	
	public Car() {}
	
	public Car(String name , double mileage, String kind, int tire) {
		
		super(name, mileage, kind);
		this.tire = tire;
		
	}

	public int getTire() {
		return tire;
	}

	public void setTire(int tire) {
		this.tire = tire;
	}
	
	@Override
	public String information() {
		return "Airplane [" + super.information() + ", tire=" + tire + "]";
	}
	
	@Override
	public void howToMove() {
		System.out.println("나 카야");
	}
}

2-3> 후손 - Ship

package com.kh.chap01_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;
	}
	
	@Override
	public String information() {
		return "Airplane [" + super.information() + ", propeller=" + propeller + "]";
	}
	
	@Override
	public void howToMove() {
		System.out.println("나 쉽이거든?");
	}
}

<실행>

package com.kh.chap01_inherit.run;

import com.kh.chap01_inherit.model.vo.Airplane;
import com.kh.chap01_inherit.model.vo.Car;
import com.kh.chap01_inherit.model.vo.Ship;

public class Run {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Airplane airplane = new Airplane("비행기1", 0.021, "제트기", 16, 5);
		Car car = new Car("BMW", 12.5, "세단", 4);
		Ship ship = new Ship("낚시배", 3, "어선", 1);
		
		//information도 Override된 메소드
		System.out.println(airplane.information());
		System.out.println(car.information());
		System.out.println(ship.information());
		
		//Vehicle 클래스 - public void howToMove() 메소드 만들고
		//나머지 클래서에서 오버라이딩해서 어떻게 움직이는지 출력문 각자 알맞게 작성하기

		airplane.howToMove();
		car.howToMove();
		ship.howToMove();
		

}

 

 

8) 예약어 - final

(1) final 클래스

: 상속이 불가능한 클래스 

public final class FinalClass{}

 

(2) final 메소드

: 상속시 오버라이딩이 불가능한 메소드

public final void method(){}

예)

final int NUM = 10;

=> 변할 수 없는 값

public static final double PI = 3.141592....;

 

 

9) 제어자, 예약어

-지역 변수 : 지역변수 앞에 쓸 수 있는 예약어는 final

-변수(필드부의 멤버 변수를 의미) : 모든 접근 제한자, final, static

-메소드 : 모든 접근 제한자, final, abstract, static 

-클래스 : public, default, final, abstract

 

*abstract는 다형성에서 배울 것이다.

 

<유의사항>

 

-abstract는 미완성이라는 의미. <=> final과 반대. 

-static은 할당의 의미, abstract은 미완성의 의미이므로 나를 상속받아서 완성시켜달라는 뜻을 내포하므로 동시에 사용 불가능. (대척점에 있으므로)

 

 

10) for each문

	// 향상 된 for문, for each 배우기
	//1. 배열의 경우
	double[] arr = {0.1, 0.2, 0.3, 0.4, 0.5};
		
	for(int i = 0 ; i < arr.length ; i++) {
	System.out.print(arr[i]);
	}
	System.out.println();
	for(double num :arr) {
	System.out.print(num);
	}
	System.out.println();
		
    //2. 객체 배열의 경우
	Airplane[] list = { new Airplane("p=01", 0.03, "여객기", 16 , 5),
						new Airplane("p=02", 0.03, "여객기", 16 , 5),
						new Airplane("p=03", 0.03, "여객기", 16 , 5)};
		
	for(int i = 0 ; i < list.length ; i++) {
		System.out.print(list[i].information());
		System.out.println();
		}
	
		
	for(Airplane ap:list) {
		System.out.print(ap.getName());
		}
}

 

 



0.10.20.30.40.5
0.10.20.30.40.5
Airplane [name=p=01, mileage=0.03, kind=여객기, tire=16, wing=5]
Airplane [name=p=02, mileage=0.03, kind=여객기, tire=16, wing=5]
Airplane [name=p=03, mileage=0.03, kind=여객기, tire=16, wing=5]
p=01p=02p=03