[SIST] Java_days17

2022. 3. 14. 18:53·TIL/Java
728x90
반응형

1. 상속(Inheritance)

클래스들 간의 2가지 관계가 있다.

 

1) has-a 관계 :

     자동차(물건, 객체) 클래스

     클래스는 수십만개의 부품(객체)으로 이루어져있다. -> Car 클래스는 Engine class, Handle class 등

     Car - Engine 클래스들 간의 관계 : Car has Engine (Car가 Engine 클래스를 가진다)

     ex) Car.engine.moreFuel(20);

 

코드) System.out.println();

// has-a 관계
// System.out.println("홍길동");

class System {
	// 필드
	static PrintStream out;
}

class PrintStream {
	void println() {}
}

 

2) is-a 관계(상속)

     상속이란? 기존 클래스를 재사용하여 새로운 클래스를 작성(선언)하는 것

 

     상속의 장점? 코드의 재사용, 코드의 중복제거 -> 생산성이 높아지고 코드의 유지,보수가 용이

 

     상속 선언 형식 : extends 키워드 사용한다.

             class 새로운 클래스명 extends 기존클래스명 {  }

 

     기존클래스 : 부모(parent) 클래스, ***[Super 클래스]***, 기초(base) 클래스, 상위 클래스

     새로운 클래스 : 자식(child) 클래스,   Sub 클래스,       파생 클래스,      하위 클래스

 

    * 생성자와 초기화 블럭은 상속되지 않는다.

 

    * 생성자가 호출되는 순서 이해(암기)
      1) 부모 객체가 먼저 생성되기에 부모의 생성자가 먼저 호출되고  > ex) Employee 생성자 4 호출됨.
      2) 자식 객체가 생성된다.                                                    > ex) Regular 생성자 5 호출됨.


1. has-a 관계

Car 클래스)

package days17;

public class Car {
	
	// 필드
	String name;
	String gearType;
	int door;
	Door[] d = new Door[4];   // 객체 배열
	
	// 클래스타입 객체;
	// Engine engine;
	// 결합력이 높은 코딩 -> 좋은 코딩이 아니다.
	// Engine engine = new Engine(); // 명시적 초기화   -> 좋은 코딩 X   왜? 엔진이 고장나면 자동차(Car 클래스) 전체를 버린다.
	
	private Engine engine = null;
	
	
	// getter
	public Engine getEngine() {
		return engine;
	}

	// setter
	// main() 메서드(외부)에서 engine 인스턴스 생성해서 주입을 받음
	public void setEngine(Engine engine) {
		this.engine = engine;
	}

	
	// 디폴트 생성자 - 생성자 초기화
	Car() {
		this.engine = new Engine(); // 엔진 인스턴스 생성
	}
	
	// main() 메서드(외부)에서 engine 인스턴스 생성한 다음에 주입을 받음
	// 생성자를 통해서 엔진 객체 주입(DI : Dependence Injection) -> 의존성 주입(자체적으로 생성안하고 외부에서 가지고 오는 것)
	// 자체적은 Car 클래스 안에서이고 외부는 main()에서
	Car(Engine engine) {
		this.engine = engine;
	}
	
	// 메서드
	void speedUp(int fuel) { 		 // 엑셀을 밟아서(엔진에 연료를 넣어서) 속도 증가 
		this.engine.moreFuel(fuel); // 에러 라인 : NullPointerException   -> 클래스타입 객체를 인스턴스 생성하지 않아서 발생
	}
	
	void speedDown(int fuel) {  // 브레이크를 밟아서 속도 감소
		this.engine.lessFuel(fuel);
	}
	
	void stop() {   // 속도 멈춤
		this.engine.stop();
	}

} // Car

Engine 클래스)


main() 메서드)

 

☞ 참고

 - DI : Dependence Injection -> 의존성 주입

   의존성 주입을 하는 이유?

     Engine engine = new Engine(); // 명시적 초기화   -> 좋은 코딩 X

     why? 엔진이 고장나면 자동차(Car 클래스) 전체를 버려야하기 때문에 외부에서 객체를 주입한다.

 

2. is-a 관계(상속) : extends 키워드 사용

student 클래스) 부모 클래스

 

childStudent 클래스) 자식클래스

 

코드 예시)

public class Ex06 {

	public static void main(String[] args) {
		// 객체(클래스) 배열 초기화
		Point[] p = {
				new Point(1,1),
				new Point(10, 100),
				new Point(120, 15)
		};
		
		//                생성자 DI(생성자를 통해서 객체 주입)
		Triangle t = new Triangle(p);

	} // main

} // class


// 삼각형, 사각형, 원, 마름모 등등
class Shape {
	// 필드
	String color = "black";
	
	// 메서드
	void draw() {
		System.out.printf("[Color = %s]\n", this.color);
	}
} // Shape class


// 좌표 클래스
class Point {
	// 필드
	int x;
	int y;
	
	// 디폴트 생성자
	Point() {
		this(0, 0);  // this의 두번째 용도 : 생성자에서 또 다른 생성자를 호출할 때의 this
	}
	
	// 생성자
	Point(int x, int y){
		this.x = x; // this의 첫번째 용도 : 멤버(필드, 메서드)를 가리킬 때의 this
		this.y = y;
	}
	
	// 메서드
	String getXY() {
		return String.format("(%d, %d)", x, y);
	}
} // Point class


// 원 클래스
// > 자바는 다중상속을 할 수 없다(부모 클래스는 딱 한 개여야 된다)
// 		class Circle extends Shape extends Point{ // 문법 에러
// 		class Circle extends Shape, Point{ // 문법 에러
class Circle extends Shape{
	// 원점 (어쩔 수 없이 has-a 관계를 가질 수 밖에 없음)
	Point center;                   // Point center = new Point(); // 좋은 코딩은 아님
	int r; // 반지름
	
	// 디폴트 생성자 DI
	Circle() {
		this(new Point(0,0) , 100);
	}
	
	// 생성자 DI
	Circle(Point center, int r) {
		this.center = center;
		this.r = r;
	}
} // Circle class


// 삼각형 클래스
class Triangle extends Shape{
	// 점3
	Point[] p = new Point[3];  // 객체 배열 선언 코딩 -> main() 메서드에서 인스턴스 생성
	
	public Triangle(Point[] p) {
		this.p = p;
	}
} // Triangle class


// 사각형 클래스
class Rectangle extends Shape{
	// 점4
	Point[] p = new Point[4];
	
	public Rectangle(Point[] p) {
		this.p = p;
	}
} // Rectangle class

 

상속 이해 예제) MyApplication

> 리스너, 어댑터, 인터페이스(implements 키워드)에 대해서는 다시 설명해 주실 예정이므로 코드 한 번 훑고 암기하기

 

main() 메서드)

 

MyApplication 클래스)

package days17;

import java.awt.Frame;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

// MyApplication 클래스가 윈도우 리스너 역할까지 하도록 코딩
// this의 3번째용도 - 인자 설명
//                                  top-level window(윈도우, 창)
public class MyApplication extends Frame implements WindowListener{
	// 필드 선언 x
	// 메서드 선언 x
	
	// 디폴트 생성자
	public MyApplication() {
		System.out.println("> MyApplication 디폴트 생성자 호출");
		
		this.setTitle("새로운 창");
		this.setSize(400, 400);
		// this.addWindowListener(new MyAppWindowListener()); // 객체를 생성해야하니까 안에 new 연산자로 객체를 생성..
		this.addWindowListener(this);  // MyApplication 자기 자신이 리스너 역할을 한다. / this의 3번째 용도
		this.setVisible(true); // 보이도록 설정
		
	}

	@Override
	public void windowActivated(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowClosed(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowClosing(WindowEvent e) {
		System.out.println("프로그램 종료됩니다");
		System.exit(-1);
	}

	@Override
	public void windowDeactivated(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowDeiconified(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowIconified(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowOpened(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

} // MyApplication


/*
// [인터페이스 개념] implements 키워드 설명 -> 나중에 상세히 설명 예정 이거 다 암기 내용
// 리스너(청취자) 선언 : 윈도우 관련 이벤트(X 닫기 버튼 클릭)를 처리하는 리스너
class MyAppWindowListener implements WindowListener{

	@Override
	public void windowActivated(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowClosed(WindowEvent arg0) {
		// 닫히고 난 후에 작업
		
	}

	// 이벤트 핸들러
	// 메서드는 메서드인데 이벤트가 발생하면 호출되는 메서드
	@Override
	public void windowClosing(WindowEvent e) {
		// 닫히기 전에 물어보는 작업 등
		System.out.println("프로그램 종료됩니다");
		System.exit(-1);
		
	}

	@Override
	public void windowDeactivated(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowDeiconified(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowIconified(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowOpened(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}
	
 } // MyAppWindowListener
*/

has-a(포함관계)와 is-a(상속) 코드 예시)

// 원 클래스 is-a 관계(상속)
class Circle extends Point{
	// [필드]
	// 원점
	// int x;
	// int y;

	// 반지름
	int r;

} // Circle

// 원 클래스 has-a 관계(포함관계)
// Circle 클래스는 Point 클래스를 가지고 있다.
class Circle{
	// [필드]
	// 원점
	// int x;
	// int y;
	Point 원점 = null;
	// 반지름
	int r;
	
	Circle() {
		원점 = new Point();
	}
	
	Circle(Point p){
		this.원점 = p;
	}
	
	//
} // Circle

// 좌표점 클래스
class Point{
	// 필드
	int x;
	int y;

	// 디폴트 생성자
	Point() {
		this(0, 0);  // this의 두번째 용도 : 생성자에서 또 다른 생성자를 호출할 때의 this
	}
	
	// 생성자
	Point(int x, int y){
		this.x = x; // this의 첫번째 용도 : 멤버(필드, 메서드)를 가리킬 때의 this
		this.y = y;
	}
	
	// 메서드
	String getXY() {
		return String.format("(%d, %d)", x, y);
	}
	
} // Point

> 원점이 has-a 관계를 가질수 밖에 없는 이유 : 다중상속을 할 수 없기 때문에

> 자바는 다중상속을 지원하지않는다.

다중상속을 지원하지 않는 이유 설명

 

2. Object 클래스

- 모든 클래스의 최상위 부모(super) 클래스는 Object 클래스이다.

  > 모든 클래스는 java.lang.Object 클래스를 상속받기 때문에 컴파일할 때 자동으로 extends.java.lang.Object로 처리

 

 

 

3. super 키워드

- super() == 조상 클래스의 생성자

- super 키워드 정의와 3가지용도? =this의 3가지 용도와 비슷함
- 정의 : 클래스 자기 자신의 부모 주소값을 갖는 참조변수 == super 키워드(예약어)
- 다른 코딩보다 항상 첫번째 라인에 있어야 한다.

 

두번째 용도) 생성자에서 또 다른 부모 생성자를 호출할 때의 super();

Regular 클래스

첫번째 용도) 부모 멤버를 가르킬 때의 super

Regular 클래스

 

4. 업캐스팅(upcasting) / 다운캐스팅(downcasting)

- 업캐스팅(upcasting) : 자식 객체를 생성해서 부모 객체에 참조시키는 것(자동형변환 가능)

 

- 다운캐스팅(downcasting) : 부모 객체를 다시 자식 객체에 참조시키는 것(자동형변환X, 강제형변환)

 

- 형변환 조건 : 상속관계

 

- 부모객체 생성 -> 자식객체로 다운캐스팅(형변환)할 때 에러 발생하는 이유

 > 업캐스팅을 한 객체를 다운캐스팅 가능(부모가 자식이 될 수 없음)

  ex)


코드)


5. 오버로딩과 [오버라이딩(overriding)]

- 오버로딩 : 중복된 함수명을 사용하고 매개변수의 타입,갯수가 다른 것

- 오버라이딩 : 부모의 메서드를 재정의하는 것

> 자바는 모든 부모 클래스의 인스턴스 메서드를 자식 클래스에서 재정의(오버라이딩) 할 수 있다.

   (단, final 키워드가 붙으면 오버라이딩 할 수 없음)

main() 메서드

 

Regular 클래스

 

6. final이 붙는 경우 3가지

1) final 클래스 선언 => 자식클래스(subclass)를 가질 수 없는 최종 클래스 ex.SalesMan 클래스
2) final 변수 선언 => 상수 : final은 상수 -> 한번 초기화하면 값을 바꿀 수 없음
3) final 메서드 선언 => 자식클래스(subclass)에서 오버라이딩 할 수 없다.

 

* final 변수는 꼭 초기화 값을 할당해 주어야한다.

 

> 에러메시지 : The type XXX cannot subclass the final class SalesMan
> 해석 : SalesMan은 최종 클래스이기 때문에 자식 클래스를 가질 수 없다.

      public final class SalesMan extends Regular { }     

        class XXX extends SalesMan{ }


3,4,5,6 관련 코드 예제)

1. Employee 클래스 - 사원이라면 공통적으로 가지고 있어야할 멤버(속성==필드, 기능==메서드)
2. Employee 클래스를 상속받은 Regular 정규직 사원 클래스 - 정규직이라면 가지고 있어야할 멤버
3. Regular  클래스를 상속받은 SelesMan 영업직 사원 클래스 - 영업직이라면 가지고 있어야할 멤버
4. Employee 클래스를 상속받은 Temp 임시직 사원 클래스 - 임시직(일용직, 계약직)

 

Employee 클래스)

package days17;

// 사원 클래스 - 사원이라면 공통적으로 가지고 있어야할 멤버(필드, 메서드)를 구현한 클래스
public class Employee { // extends Object 라는 코딩이 되어있지만 안보이는 상태
	
	// [필드]
	private String name; // 사원명
	private String addr; // 사원주소
	private String tel;  // 연락처
	private String hiredate; // 입사일자
	
	// [getter, setter]
	public String getName() {
		return name;
	}

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

	public String getAddr() {
		return addr;
	}

	public void setAddr(String addr) {
		this.addr = addr;
	}

	public String getTel() {
		return tel;
	}

	public void setTel(String tel) {
		this.tel = tel;
	}

	public String getHiredate() {
		return hiredate;
	}

	public void setHiredate(String hiredate) {
		this.hiredate = hiredate;
	}

	// [생성자]
	// 디폴트 생성자
	public Employee() {
		System.out.println("> Employee 디폴트 생성자 호출됨.");
	}

	// 생성자 4
	public Employee(String name, String addr, String tel, String hiredate) {
		// super();
		this.name = name;
		this.addr = addr;
		this.tel = tel;
		this.hiredate = hiredate;
		System.out.println("> Employee 생성자 4 호출됨.");
	}
	
	// [메서드]
	// 1. 사원 정보를 출력하는 메서드(인스턴스 메서드)
	public void dispEmpInfo() {
		System.out.printf("사원명 : %s, 사원주소 : %s, 연락처 : %s, 입사일자 : %s\n", this.name, this.addr, this.tel, this.hiredate);
	}

} // Employee class

Regular 클래스) Employee 상속

package days17;

// 정규직 사원 클래스
public class Regular extends Employee {

	// [필드] - Employee - name, addr, tel, hiredate 상속됨.
	private int pay; // 기본급
	
	// [생성자 오버로딩(overloading) == 중복함수]
	// 생성자, 초기화 블럭은 상속되지 않는다.
	public Regular() {
		System.out.println("> Regular 디폴트 생성자 호출됨.");
	}
	
	public Regular(String name, String addr, String tel, String hiredate, int pay) {
		// 각각의 필드 초기화
		// 에러메시지 : The field Employee.name [is not visible] -> 멤버 변수 접근지정자 문제(private 선언했기때문에) -> getter,setter 생성
		// this.name = name;
		// ㄱ. 해결 : getter, setter 생성
		/*
		this.setName(name); // Ex08에서 이름이 나옴
		this.setAddr(addr);
		this.setTel(tel);
		this.setHiredate(hiredate);
		*/
		
		// ㄴ. 해결 : p332 super() - 조상 클래스의 생성자
		// 		super 키워드 정의와 3가지용도?
		// 		정의 : 클래스 자기 자신의 부모 주소값을 갖는 참조변수 == super 키워드(예약어)
		// 		2번째 용도 : 생성자에서 또 다른 부모 생성자를 호출할 때의 super();
		// 		다른 코딩보다 항상 첫번째 라인에 있어야 한다.
		super(name, addr, tel, hiredate); // this() 코딩처럼 자식의 생성자에서 부모의 4개짜리 생성자를 호출하는 코딩(Regular에서 Employee)
		
		this.pay = pay;
		System.out.println("> Regular 생성자 5 호출됨.");
	}
	
	// [Ex08_03 final 설명]
	// public final void dispEmpInfo() {
	// Employee 클래스에서 메서드에 final을 붙이면 아래와 같은 에러메시지 발생
	// 에러메시지 : Cannot override the final method from Employee
	// 해석 : Employee에 있는 final 메서드는 재정의 할 수 없다.
	
	// [메서드] - Employee - dispEmpInfo() 상속됨.
	// 오버라이딩(overriding) == 부모의 메서드 재정의 
	@Override // 어노테이션(Annotation) : 부모의 것을 물려받아 재정의 했다라는 뜻
	public void dispEmpInfo() {
		// 사용 못함 : this.name, this.addr, this.tel, this.hiredate);
		// 이유 : private 멤버(필드)이기 때문에 접근(Access) 못한다.
		super.dispEmpInfo(); // name, arrd, tel, hire 출력 -> super 첫번째 용도 : 부모의 멤버를 가리킬 때의 super
		System.out.printf("기본급 : %d\n", this.pay);
	}
	
	/*
	// 오버로딩 문제점 - 매개변수 갯수, 타입이 달라야 된다.
	// 쓸데없이 매개변수를 줄수는 없이 오버로딩은 하지않겠다.
	public void dispEmpInfo() {
		System.out.printf("사원명 : %s, 사원주소 : %s, 연락처 : %s, 입사일자 : %s\n", this.name, this.addr, this.tel, this.hiredate);
	}
	*/

	// 급여 계산하는 메서드
	public int getPay() {
		return this.pay; // 정규직 사원은 기본급(pay)
	}
	
} // Regular class

SalesMan 클래스) final 클래스 +  Regular 클래스 상속

package days17;

// 영업직 사원 클래스
// 자식클래스를 가질 수 없는 최종(마지막) 클래스 입니다라고 선언할 때 final 키워드를 클래스 선언 부분 앞에 붙인다.
public final class SalesMan extends Regular {
	
	// [필드] - E(n,a,t,h) / R(p) 상속되어짐
	private int sales;  // 판매량
	private int comm; 	// 커미션
	
	// [생성자]
	// 디폴트 생성자
	public SalesMan() {
		System.out.println("> SalesMan 디폴트 생성자 호출됨.");
	}
	
	// 생성자 7
	public SalesMan(String name, String addr, String tel, String hiredate, int pay, int sales, int comm) {
		super(name, addr, tel, hiredate, pay);
		this.sales = sales;
		this.comm = comm;
		System.out.println("> SalesMan 생성자 7 호출됨.");
	}

	// [메서드] - E(dispEI()) / R(dispEI(재정의), getPay()) / getter,setter 상속되어짐
	// Employee의 dispEmpInfo()   ->       Regular의 dispEmpInfo() + 기본급 재정의   ->     SalesMan의 dispEmpInfo() + 판매량, 커미션 재정의
	@Override
	public void dispEmpInfo() {
		// TODO Auto-generated method stub
		super.dispEmpInfo(); // Regular의 dispEmpInfo()의 함수(기본급까지 출력하는)
		System.out.printf("판매량 : %d, 커미션 : %d\n", this.sales, this.comm);
	}

	@Override // 영업직의 급여 계산
	public int getPay() {
		return super.getPay() + this.comm * this.sales; // getPay()는 기본급
	}
	
} // SalesMan class

Temp 클래스)

package days17;

// 임시직 사원 클래스
public class Temp extends Employee{
	
	// [필드] - E(n,a,t,h)상속되어짐
	private int days; // 근무일수
	private int payOfDay; // 하루 일당
	
	// [생성자]
	// 디폴트 생성자
	public Temp() {
		System.out.println("> Temp 디폴트 생성자 호출됨.");
	}
	
	// 생성자 6
	public Temp(String name, String addr, String tel, String hiredate, int days, int payOfDay) {
		super(name, addr, tel, hiredate); 
		
		this.days = days;
		this.payOfDay = payOfDay;
		System.out.println("> Temp 생성자 6 호출됨.");
	}
	
	// [메서드] - E(dispEI()) 상속되어짐
	@Override
	public void dispEmpInfo() {
		super.dispEmpInfo();
		System.out.printf("근무일수 : %d, 하루일당 : %d\n", this.days, this.payOfDay);
	}
	
	public int getPay() {
		return this.days * this.payOfDay; // 임시직 급여 = 근무일수 * 하루일당
	}

} // Temp class

 

main() 메서드)

728x90
반응형

'TIL > Java' 카테고리의 다른 글

[SIST] Java_days19  (0) 2022.03.16
[SIST] Java_days18_OOP관련  (0) 2022.03.15
[SIST] Java_days16  (0) 2022.03.11
[SIST] Java_days15  (0) 2022.03.10
[SIST] Java_days14  (0) 2022.03.08
'TIL/Java' 카테고리의 다른 글
  • [SIST] Java_days19
  • [SIST] Java_days18_OOP관련
  • [SIST] Java_days16
  • [SIST] Java_days15
야리니
야리니
오늘보다 내일 더 성장하는 개발자가 되기 위한 야리니 블로그입니다 :)
    반응형
    250x250
  • 야리니
    야리니의 step by step
    야리니
  • 링크

    • GitHub
    • Linkedin
  • 전체
    오늘
    어제
    • 분류 전체보기 (478)
      • TIL (379)
        • Java (97)
        • Kotlin (28)
        • JPA (16)
        • Spring (37)
        • Oracle (22)
        • JDBC (7)
        • Web(HTML, CSS, JS, jQuery) (90)
        • View Template (31)
        • AWS (7)
        • HTTP (7)
        • CS (5)
        • Linux, Unix (2)
        • Python (20)
      • Trouble Shooting(Error) (37)
      • Algorithm (15)
      • Git,GitHub (8)
      • Diary (24)
      • 독서 (9)
      • Etc (6)
        • Mac (1)
        • 학원준비과정 (2)
  • 블로그 메뉴

    • 방명록
    • 태그
  • 공지사항

    • 안녕하세요 :)
  • 인기 글

  • 태그

    CSS
    java기초
    국비지원학원
    HTML
    oracle
    java
    백엔드 개발자
    쌍용교육센터
    코틀린
    Kotlin
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
야리니
[SIST] Java_days17
상단으로

티스토리툴바