갈림길 이정표

[7. 상속] 본문

7.0 포함관계 (has a)

package pack1;

public class PohamHandle {
	//자체적으로는 의미 없음 (부품), 다른 클래스의 멤버로 사용할 목적
	int quantity; //회전량 +오른쪽, -왼쪽, 0 직진
	
	public PohamHandle() {
		quantity = 0;
	}
	String leftTurn(int q) { //지역변수
		quantity = q;
		return "좌회전";
	}
	
	String rightTurn(int q) {
		quantity = q;
		return "우회전";
	}
	
	String straight(int q) {
		quantity = q;
		return "직진";
	}
	
//	따로 만든 이유 PohamHandle class를 다른 class에도 활용하고 싶어서 (재활용)

}
package pack1;

public class PohamCar {			//완성차 class
	int speed = 0;
	String ownerName, turnShow; //모두 PohamCar의 멤버
	//기본값 = null
	PohamHandle handle;		
	//외부 클래스를 멤버필드로 사용: 클래스의 포함관계(has a)
	//객체 선언 안한 상태라 주소 없음
	
	public PohamCar() {
		
	}
	
	public PohamCar(String name) {
		ownerName = name;			//외부 값으로 받을 수 있음
		handle = new PohamHandle(); // new class를 class 안에서 선언 (instance)
	}
	
	void turnHandle(int q) { //회전량을 인수로 받을 거임 //마치 자신의 멤버인냥 불러옴
		if(q > 0) turnShow = handle.rightTurn(q); //객체 생성하는 데 PohamHandle class에서 rightTurn멤버 부르고 
		if(q < 0) turnShow = handle.leftTurn(q);  //int q값을 받으면 String으로 받아들이기 때문에 "우회전"을 받아들여  
		if(q == 0) turnShow = handle.straight(q); //String 데이터 타입(기본값 null) turnShow 에 치환
		//PohamCar 가 아닌 PohamHandle값 참조
		
		
	}
	

}
package pack1;

public class PohamCarMain {

	public static void main(String[] args) {
		//class의 포함관계 연습
		PohamCar tom = new PohamCar("톰");     //PohamHandle 은 필요없음
		tom.turnHandle(20);
		System.out.println(tom.ownerName + "의 회전량은 " + tom.turnShow + " " + tom.handle.quantity); //tom.quantity 바로 갈 수 없음

		tom.turnHandle(-10);
		System.out.println(tom.ownerName + "의 회전량은 " + tom.turnShow + " " + tom.handle.quantity); //tom.quantity 바로 갈 수 없음
		
		tom.turnHandle(0);
		System.out.println(tom.ownerName + "의 회전량은 " + tom.turnShow + " " + tom.handle.quantity); //tom.quantity 바로 갈 수 없음

		System.out.println();
		PohamCar kildong =  new PohamCar("길동"); //또다른 instance 선언
		kildong.turnHandle(0);
		System.out.println(kildong.ownerName + "의 회전량은 " + kildong.turnShow + " " + kildong.handle.quantity);
		//구두점(.)이 두 개면 포함 관계구나라고 알면 됨
		//out은 파란 기울임체 = static
		
		//API(Application Programming Interface) document: 전문가와 개발자(사용자) 사이 소통을 위한 설명 문서
		//https://docs.oracle.com/en/java/javase/14/docs/api/index.html
		//https://docs.oracle.com/javase/8/docs/api/
		
		
	}

}

 

 

7.1 상속개념 (is a) .......................................................................................................................
7.2 클래스 상속.....................................................................................................................
7.3 부모 생성자호출 '
7.4 메소드 재정의...............
7.5 final 클래스와 final 메소드 ........................................................................................
7.6 protected 접근 제한자 ...........................................................................................
7.7 타입 변환과 다형성.........................................................................................................
7.8 추상클래스.....................................................................................................................

 

package pack2;

public class GrandFa {
	private int nai = 80;
	public String gabo = "상감청자";
	protected String gahun = "착하게 살자"; //자식class의 존재를 암시
	
	public GrandFa() {				//class[대문자]명 () 는 생성자
		System.out.println("할아버지 생성자");
	}
	
	public GrandFa(int nai) {			//public: 다른 package 내 호출 가능
		this(); 			//자신의 또 다른 생성자를 호출 (다른 statement 보다 먼저 적기)
		this.nai = nai;		//자기 멤버 호출	// overloading 생성
		//생성자 호출 방법: ①new ②다른 생성자로 호출

	}
	
	protected String say() {		//변수[소문자]()는 메소드
										//protected: 다른 package 내에선 자식 class이라면 호출 가능! 
		return "할아버지 말씀: 자바에 미쳐라";
	}
	
	void eat() {						//defualt: 같은 package 내 호출 가능
		System.out.println("밥은 맛있게...");
	}
	
	public int getNai() { 	//final 붙이면 Father class의 getNai가 
		return nai;			//왜냐면 override 불가이기 때문 (수정불가)
	}
}
package pack2;

public class Father extends GrandFa{
	//extend = (단일)상속: private 멤버를 제외한 나머지 자원을 자기자식에게 제공!(자원의 재활용)
	private int nai = 55;		//캡슐화 (private 으로 데이터 숨김)
	public String gabo = "꽃병";	//부모 (GrandFa) class 멤버와 같은 멤버 필드 (은닉화: 자식에 의해 부모의 멤버가 숨어버림) = 덮어쓰기(?)
	private final int house = 1;		//Father class 고유 멤버 (final = 수정 불가)
	//부모보다는 자식이 멤버 수가 더 많음
	//멤버 가짓 수는 자식이 많지만 상속 개념에서 큰 것은 부모
	
	public Father() {
		super();	//this:자신의 생성자 호출, super: 부모 생성자 호출, 생략 가능
		// 항상 먼저    //생성자 overloading 한 상태에서는 생략 불가 (그냥 습관적으로 적어라!)
		System.out.println("아버지 생성자~~~~~");
	}
	
	public Father(int n) {		//생성자를 여러개 만드는 행위 overloading
		//괄호안은 argument
		super(n); //부모class 생성자 (argument) 중 데이터 타입이 같은 int nai 를 호출
		System.out.println("아버지 생성자~~~~~");
	}
	
		
	@Override		//annotation(주석) - 밑에 있는 정보가 override 된 것임을 알림 (가독성 위해: 개발자 간 소통)
	public int getNai() {	//method override(재정의) -> 다형성 (내용 다름)
//	public int getNa() { -> 한 글자만 차이나도 자식 고유 메소드로 되버림
		System.out.println("자식이 부모 메소드를 재정의 함");
		return nai;			//부모와 자식이 똑같은 메소드를 가지고 있는 것 (내용은 달라도 메소드명은 같아야 됨)
	}
	
	public int getHouse() { //getH까지만 쓰고 ctrl+space bar 눌러도 자동 생성
		return house;
	}
	
	public void showData() {
		String gabo = "컴퓨터"; //찾는 순서: showData 안의 gabo -> (없으면) Father class 의 gabo -> (없으면) GrandFa class의 gabo
		System.out.println("가보: " + gabo);//찾는 순서: showData 안의 gabo -> (없으면) Father class 의 gabo -> (없으면) GrandFa class의 gabo
		System.out.println("가보: " + this.gabo);//찾는 순서: Father class 의 gabo -> (없으면) GrandFa class의 gabo
		System.out.println("가보: " + super.gabo);//찾는 순서: GrandFa class의 gabo
//		super가 가장 상위, 그외 부모 class 위 class를 바로 호출 불가!
		getNai();
		this.getNai();
		super.getNai();
	}
}
package pack2;

public class Me extends Father {
	public Me() {
		System.out.println("재생성자임을 선언 하노라");
	}
	
	@Override
	public void showData() {
		System.out.println("Me의 showData");
	}
	
	
}


//final class(상속 불가[subclass의 작성 불가)
//final method(오버라이딩 불가)
//final 멤버 변수 (값 변경 불가)
package pack2;

public class MyFamily {
	public static void main(String[] args) {
		//상속 (is a 관계)
		GrandFa gr = new GrandFa(); 	//new class[대문자](): 객체(instance) 생성
										//기본 나이값 80
		//생성자 호출 방법: ①new ②다른 생성자로 호출
		System.out.println("가보: " + gr.gabo);
		System.out.println("가훈: " + gr.gahun);
//		System.out.println("나이: " + gr.nai);
		System.out.println(gr.say());
		gr.eat();
		System.out.println("할아버지 나이: " + gr.getNai());//public: 다른 package 내 호출 가능
		
		System.out.println("------------");
		GrandFa gr2 = new GrandFa(82);	//나이값이 있는 또다른 gr2
		System.out.println(gr2.say());
		gr2.eat();
		System.out.println("할아버지2 나이: " + gr2.getNai());
	
		System.out.println("\nFather------------");
		Father fa = new Father();
//		fa. 그냥 ctrl + space bar 하면 superclass(java.Object)만 나옴
		//extend 부모class한 후면 상속됨(private 멤버 빼고 복제)
		System.out.println("가보: " + fa.gabo); //Father class에서 찾아 (지역) 없으면 GrandFa class에서 찾아 (상위 개념)
		System.out.println("가훈: " + fa.gahun);
		System.out.println(fa.say());
		fa.eat();
		System.out.println("아버지 나이 : " + fa.getNai());
		System.out.println("집은 " + fa.getHouse());
		fa.showData();		//찾는 순서: showData 안의 gabo -> (없으면) Father class 의 gabo -> (없으면) GrandFa class의 gabo
		
//		System.out.println();
//		Father fa2 = new Father(77);
//		System.out.println("아버지2 나이 : " + fa2.getNai());
		
		System.out.println("\nMe------------");
		Me me = new Me();
//		할아버지 생성자
//		아버지 생성자~~~~~
//		재생성자임을 선언 하노라
		System.out.println("가보: " + me.gabo); //Father class에서 찾아 (지역) 없으면 GrandFa class에서 찾아 (상위 개념)
//		가보: 꽃병(Father class)
		System.out.println("가훈: " + me.gahun);
//		가훈: 착하게 살자(GrandFa class)		->Father class를 통해 상속 가능
		System.out.println(me.say());
//		할아버지 말씀: 자바에 미쳐라
		System.out.println(me.getHouse());		
//		1(Father class)
		me.eat();		
//		밥은 맛있게...(GrandFa class)
		
	}

}
package pack2;

//import java.lang.Object; (모든 클래스 기본)

public class MyObj { // extends Objects (모든 클래스 기본)
	
	public MyObj() {
		
		System.out.println("MyObj");
	}
	
	@Override
		public String toString() { 			//toString의 기능 바꿈 (다형성)
			return "자격증만세";
		}
	

	public static void main(String[] args) {
		MyObj obj = new MyObj();
		System.out.println(obj);			//-> 주소가 찍히도록 기본 세팅
		System.out.println(obj.toString()); //-> 주소가 찍히도록 기본 세팅 (생략)
	}

}

package pack2;

public class Dog {		//개과의 파생 클래스(sub class)를 위한 super class
	private String name = "댕댕이";
	
	public Dog() {
		// TODO Auto-generated constructor stub
	}

	public Dog(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public String callName() {
		return "종류: " + name;
	}
	
	public void print() {
		System.out.println(name + " : 땅 위에 산다");
	}
	

	
}
package pack2;

public class DogMain {

	public static void main(String[] args) {
		Dog dog = new Dog();
		dog.print();
		System.out.println(dog.callName());
		
		System.out.println("---------------");
		HouseDog hd = new HouseDog("집개");
		hd.print();
		hd.show();
		System.out.println(hd.callName());
		
		System.out.println("---------------");
		WolfDog wd = new WolfDog("늑대");
		wd.print();
		System.out.println(wd.callName());
		wd.display();
		
		System.out.println("^^^^^^^^^^^^^^^");
		WolfDog bushdog = wd;	//(WolfDog타입) bushdog (wd주소 참조) = 값이 같다
		bushdog.print();
		
		System.out.println();
		Dog dog2 = hd;			//subclass 객체(wd = Dog 의 subclass)주소를 superclass에 치환할 수 있다 (Promotion)
		//자식객체의 주소를 부모 개체에 치환 (Promotion)
		dog2.print();			
//		dog2.display();			//superclass 타입 변수를 subclass 주소 참조하여 치환
								//err. 불간섭의 원칙(overriding 된 메소드만 가능)(고유메소드는 부를 수 없음)
		
		System.out.println();
		dog2 = wd;
		dog2.print();			//동일한 statement로 다양한 결과를 얻을 수 있음 (다형성 polymorphism)
		
		
		System.out.println();
//		WolfDog bushdog2 = dog2;//err.부모 객체의 주소를 자식 개체에 치환은 불가 (원래 부모의 성격을 가졌기 때문?)
		WolfDog bushdog2 = (WolfDog)dog2; //Casting (자식의 주소를 가질 수 있다면 가능)
		bushdog2.print();
//		자주쓰는 기능
		
		System.out.println("%%%%%%%%%%%%%%%%%");
		Dog coyote = new Dog("코요테");
		coyote.print();
		
		System.out.println();
		coyote = bushdog;
		coyote.print();
		
		System.out.println();
		coyote = hd;
		coyote.print();
		
	}
	

}
package pack2;

public class HouseDog extends Dog{
	private String where = "집";
	
	public HouseDog(String name) {
		super(name);
		
	}
	
	public void show() {
		System.out.println("어디 사니?" + where);
	}

	@Override
	public void print() {
		System.out.println("...");
		System.out.println(getName() + " : " + where + "에 산다");
		System.out.println("~~~");
	}
}
package pack2;

public class WolfDog extends Dog{
	private String where = "산";
	
	public WolfDog(String name) {
		super(name);
	}
	
	public WolfDog(String name, String where) {	//어디 변수에 값을 대입
		super(name);
		this.where = where;
	}
	
	@Override
	public void print() {						//변수에 값 대입 없이 그냥 메소드 실행
		System.out.println("늑대 만세!~~~");
		System.out.println(getName() + " : " + where + "에 산다");

	}
	
	public void display() {
		print();			//늑대 만세!~~~ \n	늑대 : 산에 산다
		this.print();
		super.print();
	}

}

package pack2;

//다형성(Polymorphism) 연습
public class PolyCar {	
	protected int speed = 30; //  protected : 자식이 있어
	
	public PolyCar() {
		System.out.println("난 자동차야!~~~");
	}
	
	public void dispData() {
		System.out.println("속도: " + speed);
	}
	
	public int getSpeed() {
		return speed;
	}
	
	
	
}
package pack2;

public class PolyBus extends PolyCar{
	private int passenger = 10;
	
	public void show() {				//부모 객체 변수 이름으로 호출 당할 수 없음
		System.out.println("버스 show");	//PolyBus 의 고유 메소드
	}
	
	@Override							//부모 객체 변수 이름으로 호출 당할 수 있음
	public void dispData() {
		System.out.println("버스 승객은 " + passenger);
		System.out.println("버스 속도은 " + speed); //super. 또는 this. 쓰지마
	}

}
package pack2;

public class PolyTaxi extends PolyCar{
	private int passenger = 2;
	
	public PolyTaxi() { 	
		System.out.println("난 택시라고 해");
	}
	
	@Override				//부모 객체 변수 이름으로 호출 당할 수 있음
	public void dispData() {
		System.out.println("택시를 이용하고 있는 인원 수 " + passenger);
	}

}
package pack2;

public class PolyMain {

	public static void main(String[] args) {
		//다형성 연습
		PolyCar car1 = new PolyCar();		//난 자동차야!~~~
		PolyBus bus1 = new PolyBus();		//난 자동차야!~~~
		PolyTaxi taxi1 = new PolyTaxi();	//난 자동차야!~~~ \n 난 택시라고 해
		
		car1.dispData();					//속도: 30
		System.out.println(car1.getSpeed());//30
		
		System.out.println("======");
		bus1.dispData();					//버스 승객은 10 \n 버스 속도은 30
		bus1.show();						//버스 show
		System.out.println(bus1.getSpeed());//30	(superclass참조)
		
		System.out.println("======");
		taxi1.dispData();					//택시를 이용하고 있는 인원 수 2
		System.out.println(taxi1.getSpeed());//30	(superclass참조)
		
		System.out.println("\n************************");
		PolyCar car2 = new PolyBus();		//[Promotion] subclass를 superclass에 치환
											//난 자동차야!~~~
		car2.dispData();					//버스 승객은 10 \n 버스 속도은 30	(PolyCar 아닌 PolyBus 참조!!!)
//		car2.show();		//[불간섭의 원칙] subclass 고유메소드이므로 에러
		System.out.println(car2.getSpeed());//30 (PolyBus에 메소드 없음-> PolyCar 참조)
		
		PolyCar car3 = taxi1;				//[Promotion] subclass를 superclass에 치환
		car3.dispData();					//택시를 이용하고 있는 인원 수 2
		System.out.println(car3.getSpeed());//30
		
		System.out.println("@@@@@@@@@@@@@@@@");
//		PolyBus bus2 = new PolyCar();		//[err]superclass 타입 subclass로 치환 불가능
//		PolyBus bus2 = new car2;			//[err]superclass 타입 "
		PolyBus bus2 = (PolyBus)car2;		//[Casting]
		bus2.dispData();					//버스 승객은 10 \n 버스 속도은 30
		bus2.show();						//버스 show
		System.out.println(bus2.getSpeed());//30
		
		System.out.println();
//		PolyTaxi taxi2 = new PolyCar();
		PolyTaxi taxi2 = (PolyTaxi)car3;
		taxi2.dispData();
//		PolyTaxi taxi3 = (PolyTaxi)car1;	//[syntax err 없음][Runtime err(실행 오류).] ClassCastException
		
		System.out.println("\n\n#######################");
		PolyCar p[] = new PolyCar[3]; 		//[배열 선언] 배열변수는 성격이 같은 애들끼리만 들어올 수 있음 (subclass도 가능)
		p[0] = car1;
		p[1] = bus1;
		p[2] = taxi1;
		
		System.out.println("p.length : " + p.length);//p.length : 3
		for(int a = 0; a < p.length; a++) {	//속도: 30(car1)
			p[a].dispData();				//버스 승객은 10 \n 버스 속도은 30
		}									//택시를 이용하고 있는 인원 수 2
		
		
		System.out.println("\n여기까지 -------------------\n");
		//향상된 for -> 참조형 변수에서만 가능
		for(PolyCar hi:p) {					//속도: 30(car1) \n
			hi.dispData();					//버스 승객은 10 \n 버스 속도은 30 \n
			System.out.println();			//택시를 이용하고 있는 인원 수 2 
			
		}
//		statement 는 똑같은 데 결과는 다양하게 나온다 = [다형성]
		
	}

}
Comments