ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 12. 상속과 오버라이딩
    개발자 수업/Java 2021. 10. 8. 23:22

    1. 상속(inheritance)의 개념
        1) 기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것
        2) 관계없는 두 개 이상의 클래스를 조상(부모), 자손(자식)으로 직접적 관계를 만듦
        3) 자손은 조상의 모든 멤버를 상속받음 (단 생성자, 초기화 블록 제외)
        4) 자손의 멤버 개수가 조상보다 적을 수가 없음 (같거나 많음) => 다형성 개념 적용
        5) is a 관계 : ~은 ~이다 (호랑이는 포유류이다)
        6) 만들어질 클래스에 영향을 가장 많이 주는 클래스는 상속하고
           보조적인 것은 포함으로 구현
        7) 자바는 단일 상속만 허용함
        8) 상속하는 클래스 : parent class, super class
           상속받는 클래스 : child class, sub class

    // 조상 클래스
    public class Bicycle {
    	
    	int id;
    	String brand;
    	String owner;
    	
    	
    }
    
    
    
    
    /*
     * 상속을 하는 이유
     * 	1) 공통된 코드는 조상에서 관리
     * 	2) 개별적인 부분은 자손에게 따로 관리
     * 	3) 코드의 재사용성
     */
    
    public class MountainBicycle extends Bicycle {
    	
    	// 멤버 변수 : 5개
    	String frame;
    	int gear;
    	int price;
    	
    	public void print() {
    		System.out.println("id : " + this.id);
    		System.out.println("brand : " + this.brand);
    		System.out.println("frame : " + this.frame);
    		System.out.println("gear : " + this.gear);
    		System.out.println("price : " + this.price);
    		System.out.println("owner : " + this.owner);
    	}
    	
    	public static void main(String[] args) {
    		MountainBicycle mB = new MountainBicycle();
    		mB.id = 311;
    		mB.brand = "LESPO";
    		mB.frame = "알루미늄";
    		mB.gear = 33;
    		mB.price = 300000;
    		mB.owner ="김광현";
    		
    		mB.print();
    	}
    	
    }



    2. 포함 관계(composite)
        1) 다중 상속을 대체하는 방법
        2) 클래스의 멤버 변수로 다른 클래스를 선언하는 것
        3) 규모가 작은 클래스를 먼저 만들고, 이것을 조합하여 규모가 큰 클래스를 만들어감
        4) has a 관계 : ~은 ~을 가지고 있다 (원은 점을 갖고 있다)

    //조상 클래스
    public class Shape {
    	String color = "black";
    	
    	public void draw() {
    		System.out.println("draw()");
    	}	
    }
    
    
    
    
    
    // 독립된 클래스
    public class Point {
    
    	int x;
    	int y;
    	
    	// 기본 생성자
    	public Point() {
    		this(0, 0);			// 또 다른 생성자 호출
    	}
    	
    	// 매개변수가 있는 생성자
    	public Point(int x, int y) {
    		System.out.println("Point 클래스의 매개변수가 있는 생성자 호출");
    		this.x = x;
    		this.y = y;
    	}
    }
    
    
    
    
    
    
    public class Circle extends Shape {
    	
    	Point center;				// 원점
    	int radius;					// 반지름
    	
    	// 기본 생성자
    	public Circle() {
    		this(new Point(0,0), 100);
    	}
    	
    	public Circle(Point center, int radius) {
    		System.out.println("Circle 클래스의 매개 변수가 있는 생성자 호출");
    		this.center = center;
    		this.radius = radius;
    	}
    	
    	@Override
    	public void draw() {
    		System.out.println("색깔 : " + this.color);
    		System.out.println("원점 : ( x : " + this.center.x + 
    								 ", y : " + this.center.y +
    								 ", 반지름 : " + this.radius + ")");
    	}
    }
    
    
    
    
    
    
    
    public class ShapeTest {
    	public static void main(String[] args) {
    		
    		Circle circle = new Circle();
    		circle.draw();
    		System.out.println();
    		
    		Circle circle2 = new Circle(new Point(150,150), 500);
    		circle2.draw();
    		System.out.println();
    		
    		Triangle triangle = new Triangle();
    		triangle.draw();
    		System.out.println();
    		
    		// 10, 10	80, 100		20, 120
    		Point[] points = new Point[] {
    				new Point(10,10),
    				new Point(80,100),
    				new Point(20,120)
    									};
    		Triangle triangle2 = new Triangle(points);
    		triangle2.draw();
    	}
    }
    
    
    
    
    
    
    
    public class Triangle extends Shape {
    	Point[] point;					// 객체 배열
    	
    	public Triangle() {
    		this(new Point(0, 0), new Point(50, 50), new Point(100, 100));
    	}
    	
    	public Triangle(Point point, Point point2, Point point3) {
    		System.out.println("Triangle의 매개 변수 3개 있는 생성자 호출");
    		this.point = new Point[] {point, point2, point3};
    	}
    	
    	public Triangle(Point[] point) {
    		System.out.println("Triangle의 매개 변수가 point인 생성자 호출");
    		this.point = point;
    	}
    	
    	@Override
    	public void draw() {
    		System.out.println("[point1] : " + this.point[0].x + ", " + this.point[0].y);
    		System.out.println("[point2] : " + this.point[1].x + ", " + this.point[1].y);
    		System.out.println("[point3] : " + this.point[2].x + ", " + this.point[2].y);
    	}
    }



    3. Object 클래스 -- 모든 클래스의 조상
        1) 사용자 정의 클래스는 아무것도 상속을 받지 않더라도 자동으로 Object를 상속 받음

    4. 오버라이딩(Overriding) -- 재정의
        1) 조상 클래스에서 상속받은 메서드를 자손한테 맞게끔 구현부를 수정하는 것
        2) 반드시 메서드 선언부는 동일해야 함(리턴타입, 메서드명, 매개변수)
        3) modify, change의 개념

    /*
     * 	반대되는 단어
     * 	add / remove
     * 	start / stop
     * 	begin / end
     * 	first / last
     * 	top / last
     * 	head / tail
     * 	header / footer
     * 	top / bottom
     * 	up / down
     * 	under / over
     *  previous / next
     *  forward / backward
     *  foreground / background
     *  push / pop
     *  push / pull
     *  enqueue / dequeue
     *  before / after
     *  save / load
     */
    
    public class Car {
    	
    	int speed;
    	
    	public Car() {
    		System.out.println("조상클래스 생성자 호출");
    	}
    	
    	public Car(int speed) {
    		System.out.println("조상클래스 매개변수 있는 생성자 호출");
    		this.speed = speed;
    	}
    
    	/*
    	 * 메서드에 제어자 final을 사용하면 자손에서 오버라이딩을 할 수 없음
    	 */
    	
    	public final void speedUp() {
    		this.speed += 10;
    		System.out.println("차가 " +this.speed+ " 속도로 달립니다.");
    	}
    	
    	public void speedDown() {
    		this.speed -= 10;
    		System.out.println("차가 " +this.speed+ " 속도로 달립니다.");
    	}
    	
    	public void stop() {
    		System.out.println("차가 멈춥니다.");
    	}
    	
    }
    
    
    
    
    
    public class SportsCar extends Car {
    
    	public SportsCar() {}
    	
    	public SportsCar(int speed) {
    		// super();
    		System.out.println("자손클래스 생성자 호출");
    		this.speed = speed;
    	}
    
    	@Override
    	public void stop() {
    		System.out.println("스포츠 차가 멈춥니다.");
    	}
    }
    
    
    
    
    
    public class CarTest {
    	public static void main(String[] args) {
    		
    		Car car = new Car(80);
    		car.speedUp();
    		car.speedDown();
    		car.stop();
    		System.out.println();
    	
    		SportsCar sportsCar = new SportsCar(150);
    		sportsCar.speedUp();
    		sportsCar.speedDown();
    		sportsCar.stop();
    	}	
    }



    5. 오버로딩(Overloading)
        1) 새로운 메서드를 만드는 것 (new의 개념)
        2) 매개변수의 개수, 타입, 순서가 다른 경우임
           매개변수의 이름과 리턴타입은 영향을 주지 않음

    6. this
        1) 인스턴스 자기 자신의 주소를 가지고 있는 참조변수
        2) 지역변수와 인스턴스 멤버변수 구별함 (변수의 모호성 해결)

    7. super 
        1) 근본적으로 this와 같음
        2) 조상 클래스의 참조변수
        3) 조상의 멤버와 자신의 멤버를 구별 지을 때 사용함

    8. super()
        1) 조상 클래스 생성자 호출
        2) 자손 클래스의 인스턴스를 생성하면 자손과 조상의 멤버가 결합된 상태로 메모리에 할당됨
        3) 조상의 멤버들도 반드시 초기화 되어야 하기 때문에 자손 클래스의 생성자에서 첫 문장에 반드시 super()를 작성해서 조상 클래스의 생성자를 호출해야 함
        4) super() 생략하면 컴파일러가 알아서 추가해줌

    9. super(int x) - 매개변수가 있는 조상 클래스의 생성자

    public class Parent {
    	int x = 100;
    	
    //	public Parent() {
    //		System.out.println("조상 클래스 생성자 호출");
    //	}
    	
    	public Parent(int x) {
    		System.out.println("조상 클래스 매개변수가 있는 생성자 호출");
    		this.x = x;
    	}
    }
    
    
    
    
    
    public class Child extends Parent {
    
    	int x = 20;
    	
    	public Child() {
    		/* 
    		 * super() : 조상 클래스의 기본 생성자를 호출
    		 * 조상 클래스의 기본 생성자에 한해서는 생략하더라도 컴파일러가 추가해줌
    		 */
    		super(200);	// 조상 클래스의 매개변수가 있는 생성자를 호출 (조상 클래스가 먼저 만들어져야 하기 때문에)
    					// 생략을 하면 절대 안 됨
    		System.out.println("자손 클래스 생성자 호출");
    	}
    	
    	public void show() {
    		System.out.println("현재 인스턴스의 x = " + x);
    		System.out.println("자손 클래스의 this.x = " + this.x);
    		System.out.println("조상 클래스의 super.x = " + super.x);
    		
    	}
    }
    
    
    
    
    
    
    
    public class SuperTest {
    	public static void main(String[] args) {
    		Child child = new Child();
    		child.show();
    	}
    }

    public class Card {
    
    	static final int KIND_MAX = 4;				// 카드 무늬 개수
    	static final int NUM_MAX = 13;				// 무늬별 카드 수
    	
    	// 무늬를 상수로 지정
    	static final int SPADE = 4;
    	static final int DIAMOND = 3;
    	static final int HEART = 2;
    	static final int CLOVER = 1;
    
    	int kind;
    	int num;
    	
    	// 생성자
    	public Card(int kind, int num) {
    		// super();								// Object 기본 생성자를 호출
    		this.kind = kind;
    		this.num = num;
    	}
    	
    	@Override
    	public String toString() {
    		
    		String kind = "";
    		String num = "";
    		
    		// 무늬 설정
    		switch(this.kind) {
    			case 4:
    				kind = "스페이드";
    				break;
    			case 3:
    				kind = "다이아몬드";
    				break;
    			case 2:
    				kind = "하트";
    				break;
    			case 1:
    				kind = "클로버";
    				break;
    		}
    		
    		switch(this.num) {
    			case 13:
    				num = "K";
    				break;
    			case 12:
    				num = "Q";
    				break;
    			case 11:
    				num = "J";
    				break;
    			default:
    				num = this.num + "";
    				
    		}
    		
    		return "무늬 : " + kind + ", 숫자 : " + num;
    	}
    }
    /*
     * 멤버 변수의 초기화 방법
     * 	1) 명시적 초기화
     * 	2) 생성자(Constructor)
     * 	3) 초기화 블럭(Initialization block)
     * 		- 인스턴스 초기화 블럭 : { }			<== 생성자보다 먼저 실행됨
     * 		- 클래스 초기화 블럭 : static { }
     */
    
    public class Deck {
    
    	final int CARD_NUM = 52;		// 카드의 개수 (13 * 4)
    	
    	// 객체 배열
    	Card[] card = new Card[CARD_NUM];
    	
    	int i = 0;
    	// 인스턴스 초기화 블럭
    	{
    		for(int k=Card.KIND_MAX; k>0; k--) {
    			for(int n=1; n<Card.NUM_MAX+1; n++) {
    				card[i++] = new Card(k,n);
    			}
    		}
    		
    		// 위 초기화 내용을 출력
    		for(int j=0; j<card.length; j++) {
    			System.out.printf("Card[%d]의 무늬 : %d, Card[%d]의 숫자 : %d\n", j, card[j].kind, j, card[j].num);
    		}
    	}
    
    	public Deck() {
    		super();
    		System.out.println("Deck 기본생성자 호출");
    	}
    	
    	public Card pick(int index) {
    		// 예외사항 처리
    		if(index >= 0 && index < CARD_NUM) {
    			return card[index];
    		}
    		else {
    			return pick();			// 위 예외사항 사이의 숫자가 아니라면 
    		}
    	}
    	
    	public Card pick() {
    		int index = (int)(Math.random()*CARD_NUM);
    		System.out.print("임의로 뽑은 카드 => ");
    		System.out.printf("%d번은 : ", index);
    		
    		return pick(index);
    	}
    	
    	// 카드를 섞는 기능
    	public void shuffle() {
    		for(int n=0; n<1000; n++) {
    			// 카드를 무작위로 섞음
    			int i = (int)(Math.random()*CARD_NUM);
    			Card temp = card[0];
    			card[0] = card[i];
    			card[i] = temp;
    		}
    		
    		System.out.println();
    		System.out.println("카드 섞은 후 결과");
    		for(int j=0; j<card.length; j++) {
    			System.out.printf("Card[%d]의 무늬 : %d, Card[%d]의 숫자 : %d\n", j, card[j].kind, j, card[j].num);
    		}
    		
    	}
    }
    public class DeckTest {
    	public static void main(String[] args) {
    		
    		Deck deck = new Deck();
    		
    		Card card = deck.pick(0);
    		System.out.print("카드 섞기 전에 맨 위에 있는 카드 => ");
    		System.out.println(card.toString());
    		
    		card = deck.pick(51);
    		System.out.print("카드 섞기 전에 맨 아래에 있는 카드 => ");
    		System.out.println(card.toString());
    		
    		card = deck.pick(33);
    		System.out.print("카드 섞기 전에 33번째에 있는 카드 => ");
    		System.out.println(card.toString());
    		
    		deck.shuffle();
    		
    		card = deck.pick(0);
    		System.out.print("카드 섞은 후에 맨 위에 있는 카드 => ");
    		System.out.println(card.toString());
    		
    		card = deck.pick(51);
    		System.out.print("카드 섞은 후에 맨 아래에 있는 카드 => ");
    		System.out.println(card.toString());
    		
    		card = deck.pick(33);
    		System.out.print("카드 섞은 후에 33번째에 있는 카드 => ");
    		System.out.println(card.toString());
    		
    		
    	}
    }

     

    '개발자 수업 > Java' 카테고리의 다른 글

    14. 다형성  (0) 2021.10.11
    13. Review  (0) 2021.10.11
    과제1 - TwoDArrayTest03  (0) 2021.10.08
    11. 컬렉션 프레임워크  (0) 2021.10.07
    10. 배열  (0) 2021.10.06

    댓글