객체 관계 (상속)

woom·2022년 11월 13일
0

JAVA

목록 보기
8/18
post-thumbnail

🌼 객체 관계

  • 클래스와 클래스의 관계
  • UML(Unified Modeling Language) : 표준화된 객체 모델링 언어를 사용하여 클래스 다이어그램(Class Diagram)으로 표현
  1. 일반화 관계(Generalization) : 상속 관계(is a 관계)로 클래스 선언시 기존 클래스를 상속받아 작성

    • 자식이 부모것을 상속받아 사용
    • 사원클래스와 관리자클래스 - 관리자는 사원이다.(O) 사원은 관리자이다(X)
      (사원을 거쳐 관리자가 된다 but 모든 사원이 관리자가 될수는 없음)
    • 코드의 재사용으로 유지보수율 높여
  2. 실체화 관계(Realization) : 상속 관계(is a 관계)로 추상적인 개념을 실체화/구체화해서 만들어줌

    • 클래스 선언시 인터페이스(클래스보다 추상적으로 표현된 자료형/실체가 없음)를 상속받아 작성
  3. 연관관계(Association) 또는 직접연관관계(Direct Association) : 포함 관계(has a 관계) ~은 ~의 것(도구)이다

    • 클래스 선언시 필드를 참조변수로 선언하여 객체를 저장한 관계
    • 연관관계 : 의사와 환자
    • 직접연관관계 : 한쪽 방향으로만 관계를 맺고 메소드 호출
      (Computer <--- CPU + MainBoard + Memory )
      컴퓨터가 CPU, MainBoard, Memory를(도구로 사용) 필드로 제공받아 관계를 맺음
  4. 집합연관관계(Aggregation) : 포함관계의 객체간의 생명주기(생성과 소멸)가 다른 경우

    • Computer, Printer : 컴퓨터가 보내온 문서를 프린터가 출력하지만 컴퓨터 고장났다고 프린터 바꾸지 않음 즉, 하나의 객체가 없어지더라도 다른 하나의 객체가 소멸되지 않는 것
  5. 복합연관관계(Composition) : 포함관계의 객체간의 생명주기(생성과 소멸)가 같은 경우

    • Game, Character : 게임이 종료되면 캐릭터도 소멸됨
  6. 의존관계(Dependency) : 포함관계 - 참조필드에 저장된 객체가 변경될 수 있는 관계

    • TV, RemoteControl : tv를 사면 리모콘을 주지만 리모콘을 바꿔도 상관 없어


💡 포함관계 (직접연관관계)

  1. 자동차 클래스
  • 자동차정보(모델명, 생산년도, 엔진)를 저장하기 위한 클래스
    (카클래스 만들기 위해서는 엔진클래스 필요)

🐣 예제1

public class Car {
	private String modelName; //필드 선언
	private int productionYear;
    
	//엔진정보(Engine 객체)를 저장하기 위한 참조필드(포함관계 : Direct Association)
	// → 포함관계가 성립되기 위해서는 반드시 생성자 또는 Setter 메소드를 이용하여
    //참조필드에 객체가 저장되도록 설정
	private Engine carEngine;//Engine클래스를 자료형으로
	
	public Car() {	}//기본생성자

	public Car(String modelName, int productionYear, Engine carEngine) {
   		 //생성자 초기화
		super();
		this.modelName = modelName;
		this.productionYear = productionYear;
		this.carEngine = carEngine;
	}
	public String getModelName() {	//getter, setter 메소드 생성
		return modelName;
	}
	public void setModelName(String modelName) {
		this.modelName = modelName;
	}
	public int getProductionYear() {
		return productionYear;
	}
	public void setProductionYear(int productionYear) {
		this.productionYear = productionYear;
	}
	public Engine getCarEngine() {
		return carEngine;
	}
	public void setCarEngine(Engine carEngine) {
		this.carEngine = carEngine;
	}
    
	//필드값(자동차정보)을 출력하는 메소드
	public void displayCar() {
		System.out.println("모델명 = "+modelName);
		System.out.println("생산년도 = "+productionYear);
		//System.out.println("엔진 = "+carEngine);  
        // 객체의 메모리 주소 저장한 것이므로 의미 없음
		
		//참조필드에 저장된 객체를 사용하여 메소드 호출
		// → 참조필드에 객체가 저장되어 있지 않은 경우 메소드를 호출하면 NullPointerException 발생
		// → 포함관계로 설정된 객체의 메소드 호출 가능
		//System.out.println("연료타입 = "+carEngine.getFualType());
		//System.out.println("배기량 = "+carEngine.getDisplacement());
		
		carEngine.displayEngine(); }}





  1. 엔진 클래스
  • 엔진정보(연료타입, 배기량)를 저장하기 위한 클래스
    • 엔진클래스 만들었다고 바로 포함관계 되지 않음

🐣 예제2

public class Engine {
	private String fualType;//필드 선언
	private int displacement;
	
	public Engine() { }	//기본 생성자
	
	public Engine(String fualType, int displacement) {//생성자 초기화
		super();
		this.fualType = fualType;
		this.displacement = displacement;
	}
	public String getFualType() {//getter, setter 메소드 선언
		return fualType;
	}
	public void setFualType(String fualType) {
		this.fualType = fualType;
	}
	public int getDisplacement() {
		return displacement;
	}
	public void setDisplacement(int displacement) {
		this.displacement = displacement;
	}
	//필드값(엔진정보)를 출력하는 메소드
	public void displayEngine() {
		System.out.println("엔진타입 = "+fualType);
		System.out.println("배기량 = "+displacement); }}





  1. 카 실행

🐣 예제3

public class CarApp {
	public static void main(String[] args) 
		Engine engine=new Engine();//엔진 생성
		//engine.displayEngine();//기본 초기값 :엔진타임은 null, 배기량은 0
		engine.setFualType("경유");
		engine.setDisplacement(2000);
		
		Car carOne=new Car();//자동차 생성
		
		carOne.setModelName("쏘렌토");
		carOne.setProductionYear(2018);
		//자동차에 엔진 포함(Setter 메소드를 이용하여 참조필드에 객체 저장:포함 관계 성립)
		carOne.setCarEngine(engine);
		
		carOne.displayCar();
        //모델명 = 쏘렌토, 생산년도 = 2018, 엔진타입 = 경유, 배기량 = 2000
        
        System.out.println(carOne.getModelName()+"의 엔진정보 >> ");
		engine.displayEngine();

		//엔진 포함한 자동차 생성(생성자를 이용하여 참조필드에 객체 저장:포함 관계 성립)
		//Car와 엔진은 생명주기 동일 (Car 가 없어지면 엔진정보도 없어지기 때문)
		Car carTwo=new Car("싼타페", 2022, new Engine("휘발유", 3000));
		carTwo.displayCar();
		
		System.out.println(carTwo.getModelName()+"의 엔진정보 >> ");
		//자동차(Car 객체)에서 엔진정보(Engine 객체)를 반환받아 메소드 호출 
		carTwo.getCarEngine().displayEngine(); }}  
        // getCarEngine() : 엔진정보를 반환하는 객체





🌼 상속 관계

  • 상속(Inheritance) 관계 : 클래스 작성시 다른 클래스를 물려받아 사용하는 기능
  • 기존 클래스를 재활용하여 보다 빠르고 쉽게 새로운 클래스 작성함으로서 프로그램 생산성, 유지보수 효율성 증가

  • 공통적인 속성과 행위를 가진 다수 클래스 작성시 공통적인 속성과 행위가 선언된 클래스를 상속받아 사용

      1. 물려주는 클래스 : 부모클래스, 선조클래스, 기본클래스, 슈퍼클래스(Super Class)
      1. 물려받는 클래스 : 자식클래스, 후손클래스, 파생클래스, 서브클래스(Sub Class)
  • 형식) public class 자식클래스 extends 부모클래스 { }

    • 자식클래스에서는 부모클래스의 필드 또는 메소드 사용 가능
  • 부모클래스의 생성자는 자식클래스에게 상속되지 않으며 부모클래스의 은닉화 선언된 필드 또는 메소드는 자식클래스에서 접근 불가

  • 자식클래스의 생성자로 객체를 생성할 경우 부모클래스의 생성자가 먼저 호출되어 부모클래스의 객체 생성 후 자식클래스의 객체 생성 → 객체간의 상속관계가 자동으로 성립


🐣 예제1 (부모클래스)

  1. 회원정보(아이디, 이름)를 저장하기 위한 클래스
public class Member {
	private String id;	//필드 선언
	private String name;
	
	public Member() {}//기본 생성자

	public Member(String id, String name) {	//생성자 초기화
		super();
		this.id = id;
		this.name = name;
	}
	public String getId() {	//getter, setter 메소드
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void display() {	//display 메소드 선언
		System.out.println("아이디 = "+id);
		System.out.println("이름 = "+name); }}




📌 super 키워드

  • 자식클래스의 메소드에서 this 키워드로 자식클래스 객체의 필드 또는 메소드를 참조하고 없는 경우 자동으로 super 키워드로 부모클래스 객체의 필드 또는 메소드 참조
    • this: 내가 가지고 있는 객체 저장 / super: 부모클래스가 가지고 있는 객체 저장
    • super 키워드 : 자식클래스의 메소드에서 부모클래스의 객체를 저장하기 위해 숨겨진 매개변수
    • super 키워드로 자식클래스의 메소드에서 부모클래스 객체의 필드 또는 메소드에 접근
    • super 키워드를 사용하지 않아도 자식클래스의 메소드에서는 부모클래스 객체의 필드 또는 메소드 사용 가능
  • super 키워드를 사용하는 경우
  1. 자식클래스의 생성자에서 부모클래스의 생성자를 호출하기 위해 super 키워드 사용
    • 형식) super(값,값,...);
    • 부모클래스의 생성자를 호출하는 명령 전에 다른 명령을 작성하면 에러 발생
  2. 자식클래스의 메소드에서 부모클래스의 숨겨진 메소드를 호출하기 위해 super 키워드 사용
    • 형식) super.메소드명(값,값,...);

📙 메소드 오버라이드

  • Method Override : 상속 관계에서 부모클래스의 메소드를 자식클래스에서 재선언하는 기능
    • 부모클래스의 메소드를 자식클래스의 객체가 사용하기 부적절한 경우 부모클래스의 메소드를 자식클래스에서 재선언하여 사용
  • Method Override 작성규칙
    • 부모클래스의 메소드와 같은 접근제한자, 반환형, 메소드명, 매개변수, 예외 전달을 사용하여 메소드 작성
    • 부모클래스의 메소드는 숨겨지고 자식클래스의 메소드에만 접근 가능
  • 이클립스에서는 부모클래스의 메소드를 자식클래스에서 오버라이드 선언되도록 자동 완성하는 기능 제공
    • 오버라이드 선언하고 싶은 부모클래스의 메소드명 입력 → [Ctrl]+[Space] → Override 선택
  • @Override : 오버라이드 선언된 메소드를 표현하기 위한 어노테이션
    • @ : 어노테이션(Annotation) - API 문서에서 특별한 설명을 제공하기 위한 기능을 구현
    • java에서 사용할 어노테이션 : @Override, @Deprecated, @Suppresswarnings
    • 메소드 오버라이드 작성 규칙을 위반한 경우 에러 발생
    • Java Source 작성에 필요한 특별한 기능을 제공 위해 사용

🐣 예제2 (자식클래스)

  1. 이벤트 관련 회원정보(아이디,이름,이메일)를 저장하기 위한 클래스
  • 회원정보를 저장하는 Member 클래스(아이디,이름)를 상속받아 작성하는 것을 권장
    • 재사용성 증가
  • extends 키워드로 기존 클래스(부모클래스: Member클래스)를 상속받아 새로운 클래스(자식클래스) 작성
  • 자식클래스는 부모클래스의 필드 또는 메소드에 접근하여 사용 가능 - 상속성(Inheritance)
  • Java에서는 단일 상속만 가능 (부모클래스는 하나만 설정 가능)
    • 다중 상속하지 않는 이유 : 어떤 부모를 참조해야하는지 선택하는 것이 불편, 상속이 끊기는 경우 생겨
  • 자식클래스에서 필드 또는 메소드에 접근하는 순서
    • 자식클래스의 필드 또는 메소드 참조 후 없는 경우 부모클래스의 필드 또는 메소드 참조
    • 부모클래스의 은닉화 선언된 필드 또는 메소드 접근 불가능
  • 부모클래스 생성자 선언 단축키
    • [Alt]+[Shift]+[S] → 팝업메뉴 → [O] → (super constructor to invoke) 부모클래스의 생성자 선택 → 필드 선택 → Generate

public class MemberEvent extends Member {
	//부모클래스(Member)을 상속받아 사용하므로 (아이디, 이름)필드 미선언 
	private String email;//email 필드 선언

	public MemberEvent() { }// 기본 생성자
	//부모클래스의 기본 생성자 호출 → 부모클래스의 객체 생성
	//super(); 기본 생성자를 호출하는 명령은 생략 가능

	public MemberEvent(String id, String name, String email) {	
    //부모클래스의 매개변수가 선언된 생성자 호출 
	// 부모클래스 객체에 원하는 초기값이 저장되도록 설정
		super(id, name);
		this.email = email;}
        
    //id,name getter, setter 메소드 미호출 (부모클래스에서 상속)    
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}

	@Override
	public void display() {
		//super 키워드로 부모클래스의 숨겨진 메소드 호출
		super.display();//아이디와 이름 출력
		System.out.println("이메일 = "+email); }}
        
  



🐣 예제3 (실행)

  1. 이벤트 관련 회원정보(아이디,이름,이메일) 클래스 실행
  • 자식클래스(MemberEvent)의 생성자로 객체를 생성할 경우 부모클래스(Member)의 생성자가 먼저 호출되어 부모클래스의 객체가 생성된 후 자식클래스의 객체 생성되어 상속 관계 성립
    • 자식클래스의 참조변수에는 자식 클래스의 객체 저장
public class MemberEventApp {
	public static void main(String[] args) {
		
		MemberEvent member1=new MemberEvent();
		
		//참조변수에 저장된 자식클래스의 객체를 참조하여 메소드 호출
		// → 자식클래스 객체에 없는 메소드는 부모클래스의 객체를 참조하여 메소드 호출
		member1.setId("abc123");
		member1.setName("홍길동");
		member1.setEmail("abc@itwill.xyz");
		member1.display();

		MemberEvent member2=new MemberEvent("xyz789", "임꺽정", "xyz@itwill.xyz");
		member2.display(); }}





📌 참조변수와 객체와의 관계

  • 상속관계의 클래스에서 참조변수와 객체와의 관계
  1. 부모클래스 참조변수 = new 부모클래스();

    • 부모클래스로 객체를 생성하여 부모클래스의 참조변수에 저장 : 가능
  2. 자식클래스 참조변수 = new 자식클래스();

    • 부모클래스의 객체와 자식클래스의 객체를 생성하고 자식클래스의 참조변수에는 자식클래스의 객체 저장 : 가능
    • 참조변수에 저장된 자식클래스의 객체를 사용하여 자식클래스의 메소드 호출이 가능하며
    • 부모클래스의 객체를 참조하여 부모클래스의 메소드 호출 가능
  3. 자식클래스 참조변수 = new 부모클래스();

    • 부모클래스로 객체를 생성하여 자식클래스의 참조변수에 저장 : 불가능
    • 자식클래스의 참조변수에는 자식클래스의 객체를 저장해야 되지만 자식클래스의 객체가 없으므로 에러 발생
  4. 부모클래스 참조변수 = new 자식클래스();

    • 부모클래스의 객체와 자식클래스의 객체를 생성하고 부모클래스의 참조변수에는 부모클래스의 객체 저장 : 가능

📙 객체 형변환

  • 객체 형변환을 이용하여 부모클래스의 참조변수를 사용하여 자식클래스의 메소드 호출 가능
      1. 명시적 객체 형변환(강제 형변환), 2. 묵시적 객체 형변환(자동 형변환)
    • 상속관계의 클래스에서만 객체 형변환 사용 가능
  1. 명시적 객체 형변환

    • Cast 연산자를 사용하여 부모클래스의 참조변수 자료형을 자식클래스로 변경하면 일시적으로 참조변수에는 자식클래스의 객체가 자동 저장
    • 명시적 객체 형변환에 의해 자식클래스로 자료형이 변경된 참조변수는 자식클래스의 객체를 참조할 수 있으므로 자식클래스의 메소드 호출 가능
    • Cast 연산자로 참조변수의 자료형을 자식클래스로 변경하면 자식클래스의 객체를 저장하고 자식클래스의 메소드 호출 가능
  2. 묵시적 객체 형변환

    • 부모클래스의 메소드를 오버라이드 선언된 자식클래스의 메소드는 (부모클래스의 숨겨진 메소드 대신 자식클래스의 메소드를 호출하기 위해) 참조변수의 자료형이 자동으로 자식클래스로 변경되어 자식클래스의 객체를 참조하여 메소드 호출

🐣 예제4 (객체 형변환)

public class MemberCastApp {
	public static void main(String[] args) {
//1. 부모클래스 참조변수 = new 부모클래스(); 
// → 부모클래스로 객체를 생성하여 부모클래스의 참조변수에 저장 : 가능
		Member member1=new Member();
		
		//참조변수에 저장된 객체를 사용하여 부모클래스의 메소드 호출
		member1.setId("aaa");
		member1.setName("홍길동");
		member1.display();
		

//2. 자식클래스 참조변수 = new 자식클래스(); → 가능
//부모클래스와 자식클래스의 객체를 생성하고 자식클래스의 참조변수에는 자식클래스의 객체 저장
		MemberEvent member2=new MemberEvent();
		
		member2.setId("bbb");
		member2.setName("임꺽정");
		member2.setEmail("bbb@itwill.xyz");
		member2.display();
		

//3. 자식클래스 참조변수=new 부모클래스(); → 불가능
// → 부모클래스로 객체를 생성하여 자식클래스의 참조변수에 저장
// → 참조변수에 자식클래스의 객체가 없으므로 에러 발생
		//MemberEvent member3=new Member();
        
        
//4. 부모클래스 참조변수=new 자식클래스(); → 가능
//부모클래스와 자식클래스의 객체를 생성하고 부모클래스의 참조변수에는 부모클래스의 객체 저장
		Member member4=new MemberEvent();
		
		//부모클래스의 참조변수에는 부모클래스의 객체가 저장되어 있으므로 부모클래스의 메소드 호출
		//부모클래스의 참조변수는 자식클래스의 객체를 참조 불가능(자식클래스의 메소드 호출 불가능)
		member4.setId("ccc");
		member4.setName("전우치");
		
		//명시적 객체 형변환에 의해 자식클래스로 자료형이 변경된 참조변수는
        //자식클래스의 객체를 참조할 수 있으므로 자식클래스의 메소드 호출 가능
		/*
		MemberEvent event=(MemberEvent)member4;
		event.setEmail("ccc@itwill.xyz");
		*/
		//Cast 연산자로 참조변수의 자료형을 자식클래스로 변경하면 자식클래스의 객체를 저장하고
		//자식클래스의 메소드 호출
		((MemberEvent)member4).setEmail("ccc@itwill.xyz");
		
		//((MemberEvent)member4).display();
		//묵시적 객체 형변환에 의해 참조변수의 자료형이 자동으로 자식클래스로 변경되어
        //자식클래스의 객체를 참조하여 메소드 호출
		member4.display(); }}





🎀 연습문제

  • 학원인적자원(학생,강사,직원) 관리 프로그램 만들기에 앞서 (학생,강사,직원)클래스 생성

🐣 예제1 (사람정보 - 번호, 이름)

  1. AcademyPerson
  • 사람정보(번호,이름)를 저장하기 위한 클래스
  • 학생,강사,직원에 대한 공통적인 속성과 행위를 정의하기 위한 클래스
  • 학원인적자원 관련 클래스가 상속받아야 되는 부모클래스
  • 코드의 중복성을 최소화하여 프로그램의 생산성 및 유지보수의 효율성 증가

public class AcademyPerson {
	private int num; //필드 선언
	private String name;
	
	public AcademyPerson() { } //기본 생성자
	
	public AcademyPerson(int num, String name) { //생성자 초기화
		super();
		this.num = num;
		this.name = name;
	}
	public int getNum() { //getter, setter 메소드 선언
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void display() {	//display 메소드 선언
		System.out.println("번호 = "+num);
		System.out.println("이름 = "+name); }}





🐣 예제2 (학생정보)

  1. AcademyStudent
  • 학생정보(학생번호, 학생이름, 수강과정)를 저장하기 위한 클래스
  • 학생번호와 학생이름 관련 속성과 행위는 AcademyPerson 클래스를 상속받아 작성

public class AcademyStudent extends AcademyPerson {//AcademyPerson 상속
	private String course;	//필드 선언
	
	public AcademyStudent() { }	//기본 생성자

	public AcademyStudent(int num, String name, String course) {//생성자 초기화
		super(num, name);//부모클래스 생성자 호출
		this.course = course;
	}
	public String getCourse() {	//course getter, setter 메소드 선언
		return course;
	}
	public void setCourse(String course) {
		this.course = course;
	}
	@Override	//display 오버라이드
	public void display() {
		System.out.println("학생번호 = "+getNum());
		System.out.println("학생이름 = "+getName());
		System.out.println("수강과정 = "+course); }}





🐣 예제3 (강사정보)

  1. AcademyInstructor
  • 강사정보(강사번호, 강사이름, 강의과목)를 저장하기 위한 클래스
  • 강사번호와 강사이름 관련 속성과 행위는 AcademyPerson 클래스를 상속받아 작성

public class AcademyInstructor extends AcademyPerson {//AcademyPerson 상속
	private String subject;	//필드 선언
	
	public AcademyInstructor() { }	//기본 생성자

	public AcademyInstructor(int num, String name, String subject) {//생성자 초기화
		super(num, name);	//부모클래스 생성자 호출
		this.subject = subject;
	}
	public String getSubject() {//subject getter, setter 메소드 선언
		return subject;
	}
	public void setSubject(String subject) {
		this.subject = subject;
	}
	@Override	//display 오버라이드
	public void display() {
		System.out.println("강사번호 = "+getNum());
		System.out.println("강사이름 = "+getName());
		System.out.println("강의과목 = "+subject); }}





🐣 예제4 (직원정보)

  1. AcademyStaff
  • 직원정보(직원번호, 직원이름, 근무부서)를 저장하기 위한 클래스
  • 직원번호와 직원이름 관련 속성과 행위는 AcademyPerson 클래스를 상속받아 작성

public class AcademyStaff extends AcademyPerson {//AcademyPerson 상속
	private String depart;	//필드 선언
	
	public AcademyStaff() { }	//기본 생성자

	public AcademyStaff(int num, String name, String depart) {//생성자 초기화
		super(num, name);	//부모클래스 생성자 호출
		this.depart = depart;
	}
	public String getDepart() {	//depart getter, setter 메소드 선언
		return depart;
	}
	public void setDepart(String depart) {
		this.depart = depart;
	}
	@Override	//display 오버라이드
	public void display() {
		System.out.println("직원번호 = "+getNum());
		System.out.println("직원이름 = "+getName());
		System.out.println("근무부서 = "+depart); }}





🐣 예제5 (프로그램 실행)

  1. AcademyApp
  • 학원인적자원(학생,강사,직원) 관리 프로그램 실행

  • 오버라이드 선언되지 않은 자식클래스의 메소드를 호출하기 위해서는 명시적 객체 형변환을 이용하여 참조변수에 자식클래스의 객체가 일시적으로 저장하여 호출

    • 문제점) 상속관계가 아닌 클래스로 명시적 객체 형변환 할 경우 ClassCastException 발생
    • 해결법) 참조변수로 객체 형변환 가능한 클래스를 확인한 후 명시적 객체 형변환하여 사용
    • instanceof 연산자 사용 → 형식) 참조변수 instanceof 클래스명
    • 참조변수로 참조 가능한 클래스를 확인하여 거짓(false) 또는 참(true)중 하나를 제공

public class AcademyApp {
	public static void main(String[] args) {
		//학생정보 객체 배열 생성 → 배열 참조요소에 학생정보만 저장 가능
		//AcademyStudent[] students=new AcademyStudent[300];
		
		//사람정보를 저장하기 위한 요소들이 존재하는 배열 생성
		// → 배열 참조요소에 학생정보,강사정보,직원정보 저장 가능
		// → 부모클래스의 참조변수에는 자식클래스의 생성자로 객체를 만들어 저장 가능
		AcademyPerson[] persons=new AcademyPerson[5];
		
		//자식클래스의 생성자로 객체를 생성→ 부모클래스의 객체 생성 후 자식클래스의 객체 생성
		//배열의 참조요소는 부모클래스의 객체가 저장되어 참조되므로 부모클래스의 메소드 호출
		//객체 형변환을 이용하면 배열의 참조요소로 자식클래스 객체를 참조하여
        //자식클래스의 메소드 호출 가능 
		persons[0]=new AcademyStudent(1000, "홍길동", "웹개발자 과정");
		persons[1]=new AcademyInstructor(2000, "임꺽정", "Java 과목");
		persons[2]=new AcademyStaff(3000, "전우치", "운영관리팀");
		persons[3]=new AcademyStudent(4000, "일지매", "웹디자인 과정");
		persons[4]=new AcademyStaff(5000, "장길산", "경영회계팀");
		
		for(AcademyPerson person:persons) { 
        //person이라는 변수에 AcademyPerson객체인 persons참조변수값 저장
		
			// person이라는 참조변수가 academystudent로 형변환 가능하다면
			if(person instanceof AcademyStudent) { 
				System.out.println(((AcademyStudent)person).getCourse()+"의 학생정보:");
			} else if(person instanceof AcademyInstructor) {
				System.out.println(((AcademyInstructor)person).getSubject()+"의 강사정보:");
			} else if(person instanceof AcademyStaff) {
				System.out.println(((AcademyStaff)person).getDepart()+"의 직원정보:");
			}
			
			//오버라이드 선언된 메소드는 묵시적 객체 형변환에 의해 부모클래스의 메소드를 
			//호출하지 않고 자식클래스의 메소드 호출
			//→ 묵시적 객체 형변환으로 인해 참조변수에는 일시적으로 자식클래스의 객체가
			//자동 저장되어 자식클래스의 메소드 호출
			//참조변수에 저장된 자식클래스의 객체에 의해 다른 클래스의 메소드 호출
			// => 오버라이드에 의한 다형성 : 객체 형변환에 의해 참조변수에 저장된 객체에 따라
			//다른 클래스의 메소드를 선택 호출
			person.display(); }}}





📒 Object

  • 클래스 선언시 상속받은 부모클래스가 없는 경우 기본적으로 Object 클래스를 자동으로 상속
  • 모든 Java 클래스는 무조건 Object 클래스를 상속받아 사용 가능
  • Object 클래스 : 모든 Java 클래스의 최선조 클래스로 모든 클래스들을 대표해서 표현 가능
  • Object 클래스로 생성된 참조변수에는 모든 클래스로 생성된 객체 저장 가능
    • 모든 클래스 들의 부모이기 때문에 어떤 객체든 전달받아 저장 가능
    • ex) object가 반환된다 : 모든 객체가 반환될수있다

🐣 예제1 (car class)

  • 자동차정보(모델명, 소유자명)를 저장하기 위한 클래스
  • Object 클래스의 toString() 메소드를 오버라이드 선언
    • Object 클래스의 toString() 메소드는 숨겨지고 Car 클래스의 toString() 메소드 호출
    • VO 클래스에서는 필드값을 문자열로 변환하여 반환 처리되도록 작성 (필드값 확인)

public class Car /* extends Object */ {
	private String modelName;//필드 선언
	private String userName;
	
	public Car() { } //기본 생성자

	public Car(String modelName, String userName) {	//생성자 초기화
		super();
		this.modelName = modelName;
		this.userName = userName;
	}
	public String getModelName() {	//getter, setter메소드
		return modelName;
	}
	public void setModelName(String modelName) {
		this.modelName = modelName;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	@Override 
    //toString을 override 하여 필드값을 출력하라고 하면 오버라이드 선언된 값으로 출력
	public String toString() {
		return "모델명 = "+modelName+", 소유자 = "+userName; }}





🐣 예제2 (car 실행)

  • Object.toString() : 참조변수에 저장된 객체정보(메모리주소)를 문자열로 변환하여 반환하는 메소드
  • String.toString() : String 객체에 저장된 문자열을 반환하는 메소드
  • 참조변수 출력시 toString() 메소드 호출 생략 가능
public class CarApp {
	public static void main(String[] args) {
		Car car=new Car("싼타페", "홍길동");	//Car객체 생성
		
		System.out.println("모델명 = "+car.getModelName());//싼타페
		System.out.println("소유자 = "+car.getUserName());//홍길동
		
		System.out.println("car.toString() = "+car.toString());
		//참조변수를 출력할 경우 자동으로 Object 클래스의 toString() 메소드 호출
        //Object 클래스의 toString() 메소드를 오버라이드 선언한 경우 자식클래스의 메소드 호출 
		System.out.println("car = "+car);//자식클래스의 toString메소드 호출
		
		String name="홍길동";	// name은 string클래스에 있는 필드이기 때문에 문자열 반환
		
		//String 클래스에서 toString() 메소드를 오버라이드 선언, String 클래스의 메소드 호출
		//System.out.println("name.toString() = "+name.toString());
		//참조변수 출력시 toString() 메소드 호출 생략 가능
		System.out.println("name = "+name);
        




📒 제한자

  1. static 제한자 : 필드, 메소드, 클래스(내부클래스)에 설정 가능한 제한자

    • 객체에 상관 없이 클래스로 접근하기 위해 사용하는 제한자
  2. final 제한자 (더이상 값 바꿀수 없음) : 1) 필드, 2) 메소드, 3) 클래스에 설정 가능한 제한자

    1) final 필드 : final 제한자를 사용하여 선언한 필드

    • 형식) 접근제한자 final 자료형 필드명=값;
    • ex) Math 클래스 : public static final double PI : 원주율을 제공하기 위한 상수
    • 필드에 저장된 값 변경 불가능 (필드값을 변경할 경우 에러 발생)
    • 필드 선언시 반드시 초기값이 저장되도록 설정

    2) final 메소드 : final 제한자를 사용하여 선언한 메소드

    • 형식) 접근제한자 final 반환형 메소드명(자료형 매개변수명,...) { 명령; ... }
    • ex) Object 클래스 : public final void notify()
    • 자식클래스에서 절대로 오버라이드 선언하지 못하도록 설정하는 메소드

    3) final 클래스 : final 제한자를 사용하여 선언한 클래스

    • 형식) public final class 클래스명 { }
    • 다른 클래스에서 상속 받을 수 없는 클래스
    • ex) public final class System extends Object 클래스
  3. abstract 제한자 : 1)클래스, 2)메소드에 설정 가능한 제한자
    1) 추상클래스(Abstract Class) : abstract 제한자를 사용하여 선언된 클래스

    • 형식) public abstract class 클래스명 {}
    • 상속 전용 클래스로 생성자가 있어도 객체 생성 불가능

    2) 추상메소드(Abstract Method) : abstract 제한자를 사용하여 선언된 메소드

    • 메소드의 머릿부만 작성하고 몸체부는 작성하지 않는 미완성된 메소드
    • 형식) 접근제한자 abstract 반환형 메소드명(자료형 매개변수명,...);
    • 추상메소드가 선언된 클래스는 무조건 추상클래스로 선언
  • abstract : 무조건 override, 상속 ↔ final override, 상속 불가 즉 두 제한자는 정반대의 제한자
  1. public 제한자, 5. private 제한자

🐣 예제1 (사원정보)

  • 사원 급여 관리 프로그램 작성에 앞서 사원정보(사원번호, 사원이름)를 저장하기 위한 클래스 작성 (Employee class)

  • 모든 사원 관련 클래스가 상속받아야 되는 부모클래스

  • 객체 생성이 목적이 아닌 상속이 목적인 클래스로 작성 (추상클래스로 작성하는 것을 권장)

  • 상수필드(Constant Field) : 프로그램에서 값(리터럴) 대신 사용하기 위해 의미있는 단어로 제공되는 필드값

    • 형식) public static final 자료형 상수명=값;

public abstract class Employee {
	private int empNo;	//필드 선언
	private String empName;
	
	public static final double INCENTIVE_RATE=1.5;
	//static 제한자 : 객체에 상관없이 클래스로 접근하기 위해 사용하는 제한자
	//상수명은 대문자로 작성하며 스네이크 표기법을 사용하여 작성하는 것을 권장	
    
	public Employee() { }//기본 생성자

	public Employee(int empNo, String empName) {//생성자 초기화
		super();
		this.empNo = empNo;
		this.empName = empName;
	}
	public int getEmpNo() {	//getter, setter 메소드 선언
		return empNo;
	}
	public void setEmpNo(int empNo) {
		this.empNo = empNo;
	}
	public String getEmpName() {
		return empName;
	}
	public void setEmpName(String empName) {
		this.empName = empName;
	}
	/*
	//급여를 계산하여 반환하는 메소드
	//자식클래스에서 부모클래스의 메소드를 오버라이드 선언하지 않아도 에러 미발생
	//but 부모클래스의 메소드 호출하여 비정상적인 결과 발생
	public int computePay() {
		return 0;
	}
	*/
	//자식클래스에서 부모클래스의 메소드를 무조건 오버라이드 선언되도록 설정하기 위해 추상메소드로 선언
	public abstract int computePay();
	
	//모든 사원에게 급여의 150%를 인센티브로 제공되도록 계산하여 반환하는 메소드
	//자식클래스에서 메소드를 오버라이드 선언하면 비정상적인 결과값 반환
	//→ 자식클래스에서 메소드를 오버라이드 선언하지 못하도록 final 메소드로 선언
	public final int computeIncentive() {
		//추상메소드를 호출한 경우 묵시적 객체 형변환에 의해 자식클래스의 메소드 호출
		//return (int)(computePay()*1.5);
		return (int)(computePay()*INCENTIVE_RATE); }}





🐣 예제2 (정규직)

  • 정규직 사원정보(사원번호, 사원이름, 연봉)를 저장하기 위한 클래스로 Employee 클래스를 상속받아 작성

public class EmployeeRegular extends Employee {	//Employee 클래스 상속
	private int annualSalary;//필드 선언
	
	public EmployeeRegular() { }//기본 생성자

	public EmployeeRegular(int empNo, String empName, int annualSalary) {
		super(empNo, empName); //부모생성자 초기화
		this.annualSalary = annualSalary;
	}
	public int getAnnualSalary() {	//연봉 getter, setter 메소드 선언
		return annualSalary;
	}
	public void setAnnualSalary(int annualSalary) {
		this.annualSalary = annualSalary;
	}
	//급여를 계산하여 반환하는 메소드
	public int computeRegular() {
		return annualSalary/12;
	}
	//추상메소드가 선언된 추상클래스를 상속받은 자식클래스에서는 반드시 부모클래스의 모든
	//추상메소드를 무조건 오버라이드 선언 (오버라이드 선언하지 않은 경우 에러 발생)
	//추상메소드를 오버라이드 선언하지 않은 자식클래스는 추상클래스로 설정 가능 (비권장)
	@Override
	public int computePay() {
		return annualSalary/12; }
	/*
	//부모클래스의 final 메소드를 자식클래스에서 오버라이드 선언한 경우 에러 발생
	@Override
	public int computeIncentive() {
		return 100000000; }}
	*/
    
    
    
    

🐣 예제3 (계약직)

  • 계약직 사원정보(사원번호, 사원이름, 계약급여)를 저장하기 위한 클래스로 Employee 클래스를 상속받아 작성

public class EmployeeContract extends Employee {//Employee 클래스 상속
	private int contractPay;//필드 선언
	
	public EmployeeContract() { }//기본 생성자

	public EmployeeContract(int empNo, String empName, int contractPay) {
		super(empNo, empName);//부모 생성자 초기화
		this.contractPay = contractPay;
	}
	public int getContractPay() {//급여 getter, setter 메소드 선언
		return contractPay;
	}
	public void setContractPay(int contractPay) {
		this.contractPay = contractPay;
	}
	//급여를 계산하여 반환하는 메소드
	public int computeContract() {
		return contractPay;
	}
	@Override
	public int computePay() {
		return contractPay; }}





🐣 예제4 (아르바이트)

  • 시간제 사원정보(사원번호, 사원이름, 시급, 근무시간)를 저장하기 위한 클래스로 Employee 클래스를 상속받아 작성

public class EmployeeTime extends Employee {//Employee 클래스 상속
	private int moneyPerHour;//필드 선언
	private int workedHour;	
	
	public EmployeeTime() { }//기본 생성자

	public EmployeeTime(int empNo,String empName,int moneyPerHour,int workedHour){
		super(empNo, empName);	//부모생성자 초기화
		this.moneyPerHour = moneyPerHour;
		this.workedHour = workedHour;
	}
	public int getMoneyPerHour() {//시급, 시간 getter, setter 메소드 선언
		return moneyPerHour;
	}
	public void setMoneyPerHour(int moneyPerHour) {
		this.moneyPerHour = moneyPerHour;
	}
	public int getWorkedHour() {
		return workedHour;
	}
	public void setWorkedHour(int workedHour) {
		this.workedHour = workedHour;
	}
	//급여를 계산하여 반환하는 메소드
	public int computeTime() {
		return moneyPerHour*workedHour;
	}
	@Override
	public int computePay() {
		return moneyPerHour*workedHour; }}





🐣 예제5 (프로그램)

  • 사원 급여 프로그램 실행
  • 추상클래스로 객체를 생성할 경우 에러 발생

public class EmployeeApp {
	public static void main(String[] args) {
		//추상클래스(부모클래스)로 참조변수를 생성하여 모든 자식클래스의 객체 저장 가능
		//Employee employee1=new EmployeeRegular();
		//Employee employee2=new EmployeeTime();
		//Employee employee3=new EmployeeContract();
		
		//모든 사원정보를 저장할 수 있는 참조요소가 존재하는 배열 생성
		Employee[] empArray=new Employee[5];
		
		empArray[0]=new EmployeeRegular(1000, "홍길동", 96000000);
		empArray[1]=new EmployeeTime(2000, "임꺽정", 50000, 150);
		empArray[2]=new EmployeeContract(3000, "전우치", 7000000);
		empArray[3]=new EmployeeTime(4000, "일지매", 20000, 100);
		empArray[4]=new EmployeeRegular(5000, "장길산", 60000000);
		
		for(Employee employee:empArray) {
			System.out.println("사원번호 = "+employee.getEmpNo());			
			System.out.println("사원이름 = "+employee.getEmpName());
			
			/*
			//사원의 급여를 반환받아 출력
			//참조변수는 부모클래스의 객체만 참조 가능하므로 자식클래스의 메소드 호출 불가능
			//명시적 객체 형변환을 사용하여 참조변수로 자식클래스의 객체를 참조하여 메소드 호출 가능
			//instanceof 연산자를 사용하여 자식클래스를 구분하여 객체 형변환 (에러 발생 방지)
			if(employee instanceof EmployeeRegular) {
				System.out.println("급여="+((EmployeeRegular)employee).computeRegular());
			} else if(employee instanceof EmployeeTime) {
				System.out.println("급여="+((EmployeeTime)employee).computeTime());
			} else if(employee instanceof EmployeeContract) {
				System.out.println("급여="+((EmployeeContract)employee).computeContract());
			}
			*/
			
			//자식클래스에서 부모클래스의 메소드를 오버라이드 선언하면 묵시적 객체 형변환에
			//의해 자동으로 참조변수가 자식클래스로 형변환되어 자식클래스의 메소드 호출 가능
			System.out.println("급여 = "+employee.computePay());
			
			//사원의 인센티브를 반환받아 출력
			System.out.println("인센티브 = "+employee.computeIncentive()); }}
      




🌻 패키지(Package)

  • 같은 목적의 자료형(참조형)를 명확히 구분하여 그룹화 하기 위해 패키지 사용
  • 디렉토리 또는 폴더(파일들을 분류해서 사용)와 같이 클래스들을 묶어서 사용하는것
  • Java 자료형(참조형) : 1. 클래스(Class), 2. 인터페이스(Interface), 3. 열거형(Enum)
  • Java 자료형을 보다 쉽게 관리하기 위해 패키지 이용
  • 패키지의 이름은 그룹의 도메인을 역방향으로 나열하고 그룹명을 지정하여 작성하는 것을 권장
    • ex) 도메인 : itwill.xyz 이면 패키지 이름 : xyz.itwll.board (board: 그룹의 이름)
    • 패키지 이름으로 패키지안에있는 클래스의 목적 확인 가능
    • 도메인을 같이 쓰는 이유는 어떤 그룹에서 만들어진 클래스인지 명확히 구분하기 위해서 사용
    • 도메인(Domain) : 인터넷에서 개인 또는 그룹이 사용하기 위한 네트워크 식별자
    • ex) kr: 국가,코리아, CO: company, go: government
    • ip주소는 외우기 어려워서 도메인(정해줘야해 임대방식) 네트워크 주소 사용
    • www는 컴퓨터 이름, itwill.xyz는 도메인, 도메인 구매 업체 : gabia, .은 폴더를 의미
  • 패키지에 작성된 소스파일에는 첫번째 줄에 선언된 패키지를 반드시 설정
    • 형식) package 패키지명;
    • 소스파일에 작성된 java 자료형(참조형)이 어떤 패키지에 선언되어 있는지를 명확하게 표현

📌 import

  • 다른 패키지의 자료형을 현재 자료형에서 명확하게 표현하기 위해 사용하는 키워드
    • 형식) import 패키지명.자료형;
    • package 명령 하단에 작성
  • 이클립스에서는 다른 패키지의 자료형을 자동 완성(Ctrl+Space)할 경우 자동 import 처리
  • import 설정을 정리하는 단축키 : [Ctrl]+[Shift]+[O]
    • 불필요한 자료형의 import 설정을 제거하거나 필요한 자료형의 import 설정 추가
    • 이미 import 처리된 자료형과 같은 이름의 자료형은 import 처리 불가능
      (자료형을 사용시 패키지를 같이 표현하여 접근 가능)

🐣 예제

  • 같은 패키지의 클래스는 패키지 표현없이 클래스만 사용하여 접근 가능 (클래스명)
  • 다른 패키지의 클래스는 패키지를 표현해야만 클래스 접근 가능 (패키지명.클래스명)
    • 다른 패키지의 클래스를 import 처리한 경우 패키지 표현없이 클래스만 사용하여 접근 가능
  • 같은 이름의 클래스가 존재할 경우 패키지를 확인하여 클래스 사용
package xyz.itwill.app;
import xyz.itwill.subject.OracleSubject;
import xyz.itwill.subject.JavaSubject;
public class SubjectApp {
	public static void main(String[] args) {
		//xyz.itwill.subject.OracleSubject subject1=new xyz.itwill.subject.OracleSubject();
		
		OracleSubject subject1=new OracleSubject();
        //import 처리하여 패키지 표현없이 클래스 접근 
		subject1.display();
		
		//같은 이름의 클래스가 존재할 경우 패키지를 확인하여 클래스 사용
		JavaSubject subject2=new JavaSubject();
		subject2.display();
		
		xyz.uniwill.subject.JavaSubject subject3=new xyz.uniwill.subject.JavaSubject();
		subject3.display(); }}





📌 어노테이션

  • @Deprecated : 메소드 사용을 권장하지 않도록 설정하는 어노테이션(Annotation)
    • 좀 더 나은 메소드가 있으니(업데이트되면 없어질가능성) 다른 메소드 사용을 권장하면서 현재 메소드에 대한 경고
    • @Deprecated 설정된 메소드를 호출할 경우 경고 발생
  • @SuppressWarnings : 경고 메세지를 제거하는 어노테이션
    • 경고관련 속성값은 정해져있음 (deprecated : "deprecation")

🐣 예제

  • 키보드로 이름과 태어난 년도를 입력받아 나이를 계산하여 이름과 나이를 출력하는 프로그램 작성

  • ex) 이름 입력 >> 홍길동, 태어난 년도 입력 >> 2000, [결과]홍길동님의 나이는 23살입니다.

  • java.util.Date 클래스 : 날짜와 시간정보를 저장하기 위한 클래스

    • Date 클래스의 기본 생성자를 이용하여 객체를 생성할 경우 Date 객체에는 시스템(운영체제 - OS)의 현재 날짜와 시간이 저장
  • Date.toString() : Date 객체에 저장된 날짜와 시간을 문자열로 변환하여 반환하는 메소드

    • 참조변수를 출력할 경우 toString() 메소드 호출 생략 가능
  • Date.getYear() : Date 객체에 저장된 날짜와 시간 중 년도를 반환하는 메소드

    • Date 객체에 저장된 년도는 1900년부터 1년에 1씩 증가된 값으로 표현
    • @Deprecated 어노테이션이 적용된 메소드

package xyz.itwill.app;

import java.util.Date;//java.lang 패키지의 자료형은 기본적으로 import 처리되어 제공
import java.util.Scanner;

public class CalcAgeApp {
	public static void main(String[] args) {
		//Scanner 클래스로 객체를 생성하여 참조변수에 저장
		Scanner scanner=new Scanner(System.in);
		
		//키보드를 이용하여 사용자로부터 이름과 태어난 년도를 입력받아 저장
		System.out.print("이름 입력 >> ");
		String name=scanner.nextLine();
		
		System.out.print("태어난 년도 >> ");
		int birthYear=scanner.nextInt();

		//java.util.Date 클래스로 객체를 생성하여 참조변수에 저장
		//Date 객체에는 시스템(운영체제)의 현재 날짜와 시간이 저장
		Date now=new Date();
		
        //참조변수를 출력할 경우 toString() 메소드 호출 생략 가능
		//System.out.println("now.toString() = "+now.toString());
		
		//Date 객체로부터 현재 년도를 반환받아 저장
        //Date.getYear() : @Deprecated 어노테이션이 적용된 메소드 (경고) 
        //@SuppressWarnings : 경고 메세지를 제거하는 어노테이션
		// → value 속성을 사용하여 경고 관련 속성값을 설정
		// → value 속성외에 다른 속성이 없는 경우 속성값만 설정 가능
		//@SuppressWarnings(value = "deprecation")
		@SuppressWarnings("deprecation")
		int currentYear=now.getYear()+1900;
		
		//태어난 년도를 이용하여 나이 계산하여 저장
		int age=currentYear-birthYear+1;
		
		System.out.println("[결과]"+name+"님의 나이는 "+age+"살입니다.");
		
		scanner.close(); }}
        




📌 접근제한자(Acess Modifier)

  • 클래스, 필드, 메소드에 대한 접근 유무를 설정하기 위한 제한자
  1. private: 필드와 메소드에 사용 가능한 접근제한자 (은닉화)

    • 클래스 내부에서만 접근 가능하며 클래스 외부에서는 접근 불가능
    • private 접근제한자로 설정된 필드와 메소드에 접근할 경우 에러 발생
  2. public: 클래스, 필드, 메소드에 사용 가능한 접근제한자

    • 모든 패키지의 클래스에서 접근 가능하도록 설정
    • public클래스가 아닌 경우 다른 패키지의 클래스에서 접근 불가능 (에러 발생)
    • 소스파일에 public 클래스는 하나만 작성 가능
  3. package(default): 클래스, 필드, 메소드에 사용 가능한 접근제한자

    • 같은 패키지의 클래스에서 접근 가능하도록 설정
    • 다른 패키지의 클래스에서 접근할 경우 무조건 에러 발생
    • 클래스, 필드, 메소드 작성시 접근제한자 관련 키워드를 사용하지 않으면 package 접근제한자로 설정된다.
    • package 접근제한자로 설정된 부모클래스의 필드 또는 메소드에 접근할 경우 에러 발생
  4. protected: 필드, 메소드에 사용 가능한 접근제한자

    • 같은 패키지의 클래스에서 접근 가능하도록 설정
    • 다른 패키지의 클래스에서 접근할 경우 에러 발생 상속을 사용하면 접근 가능
    • protected 접근제한자로 설정된 부모클래스의 필드 또는 메소드에 접근 가능

💡 패키지 정보 확인, 구문 색상 지정

  • 이클립스 왼쪽 창 Package Explore에 패키지 정보 확인 가능

    • C가 붙으면 생성자
    • 색이 채워져있으면 메소드, 채워져 있지 않으면 필드
    • 접근제한자 : 빨간색 사각형 private, 초록색 원 public, 파란색 삼각형 package, 노란색 마름모는 protected
  • 구문 색상 지정 가능

    • window → preferences → java → editor → syntax Coloring → jave → classes → Enable → 색상 지정 →Apply and Close

profile
Study Log 📂

0개의 댓글

관련 채용 정보