상속

A is a B : A 는 B 다 - A는 B를 상속받아 결국 A는 B의 것을 가지게 된다
객체지향 프로그래밍에서는 상속이라는 개념 사용


상속 받은 필드가 private 이라면?
자식 클래스에서는 상속 받은 필드가 private 되어 있으면 직접적인 접근은 불가능하나,
상속 받은 필드에 접근하기 필요성이 있을때에는 크게 3가지 방법을 통해 접근할 수 있다


1. 필드는 private으로 선언하지 않고 protected로 선언
2. 부모의 setter를 이용
3. 자식 생성자에서 사용할 수 있는 super 키워드로 부모 생성자 호출


다형성

상속을 이용한 기술로 상속 관계에 있는 부모, 자식 클래스 간에 부모 타입은 모든 후손 타입을 받아 줄 수 있다
부모 클래스 타입의 레퍼런스가 후손 객체의 주소를 저장할 수 있다는 뜻 (후손 객체 안에 부모 멤버가 포함되어 있기 때문에 가능)
부모 레퍼런스를 통해 객체의 접근시 부모가 가지고 있는 메소드만 사용 가능 (부모레퍼런스이지만 자식의 메소드를 호출하려면 다운캐스팅)


메소드 오버라이딩
부모 클래스의 메소드를 상속받지 않고 자신이 재정의 할때 사용하는 것
- Annotation (애너테이션, 어노테이션)
자바 소스코드에 추가하여 사용할 수 있는 메타데이터의 일종
'@' 기호를 붙여 사용하며 가상 머신에게 해당 문법에 대해 알려준다
메소드 오버라이딩시에는 @Override를 명시하여 오버라이드 된 메소드임을 JVM에게 알려준다 (생략하여도 자동으로 @Override가 명시)


abstract (추상화)
추상이라는 의미를 가지고 있는 키워드
메소드를 abstract로 만들경우 부모 클래스는 자신을 상속 받는 자식들에게 해당 메소드를 강제적으로 생성하라는 의미
(부모는 기능이 없는 메소드를 만든것이고 해당 기능을 가진 메소드를 자신을 상속 받은 자식들이 오버라이딩해서 정의하라는 의미)
abstract 메소드를 포함하고 있는 클래스는 불완전한 클래스 (기능이 없는 메소드를 가지고 있는 클래스가 객체화 되면 안된다)
그렇기 때문에 abstract 메소드를 포함하고 있는 클래스는 객체화 할 수 없도록 클래스 명 앞에 abstract 키워드를 붙여서 추상클래스로 선언 
(추상 클래스는 객체화 할 수 없는 클래스를 의미)


추상 클래스 (미완성된 클래스) : 객체 생성을 막아놓은 클래스 (추상 메소드가 없어도 명시할 수 있다)


public abstract class 클래스명 { }


클래스 안에 추상 메소드를 가지고 있으면 해당 클래스는 반드시 추상 클래스가 되어야 한다
추상 클래스를 상속받은 후손 클래스는 반드시 부모의 추상 메소드를 완성시켜야 하는 강제성이 부여되어,
후손은 추상 메소드를 반드시 오버라이딩 해서 선언 해두어야 한다


추상 메소드 (미완성된 메소드) : 메소드의 헤드(Head)만 있고, 몸체(Body : 내용)가 없는 메소드


public abstract 반환자료형 메소드명([자료형 매개변수]);


표준화된 인터페이스를 제공할 목적으로 추상메소드를 사용한다
메소드 사용의 통일성을 확보하고 메소드 제작을 강제화 한다



문제. 급여관리 시스템 제작하기

요구사항

1. has a 포함관계 is a 상속관계를 구현할것 !

2. VO 클래스와 controller 클래스를 나눌것 !

3. 확장성을 고려할것 ! (다형성)

4. 첫번째 VO 클래스 이름 : Permanent (정규직) - kh.java.pay.model.vo

5. Permanent 의 멤버필드 : 이름 , 분류, 급여 (3가지)

6. 멤버메소드 : setter, getter, 생성자 

7. 두번째 VO 클래스 이름 : PartTime (시간직) - kh.java.pay.model.vo

8. Parttime 의 멤버필드 : 이름 , 분류 , 시급, 일한시간 (4가지)

9. 자식 클래스들의 멤버메소드 : setter, getter, 생성자 , 급여getter 추가로 만들어야함

10. controller 클래스  이름 : PayMgr (급여매니저) - kh.java.pay.controller

11. Paymgr 의 멤버필드 : 직원10명관리할수 있는 객체 배열!!, 인덱스 

12 Paymgr 의 멤버메소드 : insertData, printData, 생성자 

13. 실행형 클래스에서 아래와 같이 실행 - kh.java.pay.run.TestMain

PayMgr p = new PayMgr();

p.insertData(new Permanent("홍길동","정규직",2000000));

p.insertData(new PartTime("김말똥","시간직",6000,200));

< < = = = = = = 출력결과 = = = = = = = > >

이름 분류 급여

길똥이 정규직 2000000

개똥이 시간직 1200000

만족 할때쯤 점검 !! 인턴직을 추가 해본다. 그때 컨트롤 클래스에 손이 가면 

다형성이 실패한것이다. (인터직은 급여 * 80 % )  

멤버변수는 정규직과 같다. 다만 급여*80%

p.insertData(new intern("김인턴","인턴직",2000000); // 김인턴 인턴직 1600000  이 출력


PayMgr p = new PayMgr();

p.insertData(new Permanent("홍길동","정규직",2000000));

p.insertData(new PartTime("김말똥","시간직",6000,120));

p.insertData(new Intern("삼국지","인턴직",2000000));

p.printData();


Permanent, PartTime, Intern의 부모 클래스

package kh.java.pay.model.vo;


public abstract class Job {

private String name;

private String job;

public Job() {}

public Job(String name, String job

{

this.name = name;

this.job = job;

}

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

public void setJob(String job) {this.job = job;}

public String getName() {return name;}

public String getJob() {return job;}

public abstract int getPay();

}


Permanent.java

package kh.java.pay.model.vo;


public class Permanent extends Job{

private int pay;

public Permanent() {}

public Permanent(String name, String job,int pay)

{

super(name,job);

this.pay = pay;

}

@Override

public int getPay() 

{

return pay;

}

}


PartTime.java

package kh.java.pay.model.vo;


public class PartTime extends Job{

private int payHour;

private int payWork;

public PartTime() {}

public PartTime(String name, String job, int payHour, int payWork)

{

super(name,job);

this.payHour = payHour;

this.payWork = payWork;

}

@Override

public int getPay() {

return payHour * payWork;

}

}


Intern.java

package kh.java.pay.model.vo;


public class Intern extends Job{

private int pay;

public Intern() {}

public Intern(String name, String job, int pay)

{

super(name, job);

this.pay = pay;

}

@Override

public int getPay() {

return (int)(pay*0.8);

}

}


PayMgr.java

package kh.java.pay.controller;


import kh.java.pay.model.vo.*;


public class PayMgr {

private Job [] j = new Job [10];

private int index = 0;

public PayMgr() {}

public void insertData(Job j)

{

this.j[index++] = j;

}

public void printData()

{

System.out.println("<<====== 출력결과 ======>>");

System.out.printf("%-15s %-15s %-15s \n", "이름","분류","급여");

for(int i=0;i<index;i++)

{

System.out.printf("%-13s %-13s %-15d \n", j[i].getName(),j[i].getJob(),j[i].getPay());

}

}

}


TestMain.java

package kh.java.pay.run;


import kh.java.pay.controller.PayMgr;

import kh.java.pay.model.vo.*;


public class TestMain {

public static void main(String[] args) {

PayMgr p = new PayMgr();

p.insertData(new Permanent("홍길동","정규직",2000000));

p.insertData(new PartTime("김말똥","시간직",6000,200));

p.insertData(new Intern("삼국지","인턴직",2000000));

p.printData();

}

}



객체지향 프로그래밍

현실 세계는 사물이나 개념처럼 독립되고 구분되는 각각의 객체로 이루어져 있다
각각의 독립되는 형태로 구현되어 있는 것이 객체이고 이 개념을 바탕으로 프로그래밍을 하는 것을 객체지향 프로그래밍

- 객체지향 언어는 객체지향 프로그래밍을 하기 위해 만들어진 언어

프로그램 객체를 만들기 위해서는 실제 객체에 대한 분석이 필요

객체(Instance)를 표현하는 것에는 속성(데이터)와 기능(메소드)을 가지고 있다


객체지향 용어
클래스 : 객체를 만들기 위한 설계도 혹은 틀. 사물이나 개념의 공통요소(속성, 기능)을 용도에 맞게 추상화
추상화(abstraction)
- 프로그램에서 필요한 속성과 기능을 추출하고 불필요한 것을 제거하는 과정
- 프로그래밍적으로 보았을 때 속성(변수)으로 사용할 것과 기능(메소드)으로 구현할 것들을 설계하는 과정


객체지향 프로그래밍 단계 : 대상 물색 → 추상화 → 설계 (클래스 작성) → 사용 (인스턴스화)


변수 : 데이터를 저장하는 공간
배열 : 데이터를 연속적으로 저장하는 공간 (같은 타)
구조체 : 여러 데이터 타입의 데이터를 저장하는 공간


클래스 선언

[접근제어지시자] [예약어] class 클래스명

{

// 속성

[접근제어지시자] 자료형 변수명;

[접근제어지시자] 자료형 변수명;


// 기능

[접근제어지시자] [예약어] 리턴형 메소드명 ( )

{

// 기능정의

}

}


접근제어 지시자 : 클래스 안에서 변수 및 메소드 생성시 접근제어 지시자를 사용. 접근할 때 허용하는 범위를 말하는 것
- public : 어디서든 접근 허용
- protected : 후손클래스(상속), 같은 패키지 내, 해당클래스 내부에서 접근 가능
- default : 같은 패키지 내, 해당클래스 내부에서 접근 가능

접근제어 지시자를 작성하지 않으면 default로 설정

- private : 해당 클래스에서만 접근 가능


원칙
클래스 안의 멤버 변수는 private으로 설정하는 것을 원칙 (멤버 변수는 데이터를 저장하고 있는 중요한 공간이기 때문에 보호)
클래스 안의 멤버 메소드는 다양하게 사용할 수 있다 (기본은 public)



객체지향 3대 원칙 : 캡슐화, 상속, 다형성


캡슐화

하나의 객체는 독립적으로 완벽한 역할을 수행할 수 있어야 한다
정보은닉 + 독립적인 역할을 캡슐화 작업을 하였다 라고 볼 수 있다 - 실제 내부 코드를 보지 않고도 사용자는 사용할 수 있어야 한다


정보은닉 : 정보를 숨기는 것
- 클래스의 멤버 변수는 일반적으로 private 영역에 저장하여 의도치 않은 외부 접근에 대한 오류를 방지
- 클래스를 만든 개발자는 해당 클래스의 멤버 변수를 타 사용자가 마음대로 바꾸게 두어서는 안 됨 (흐름의 문제가 발생)


변수의 종류
- 지역변수 : 해당 메소드 안에서만 사용가능. 메소드가 호출될 때 생성되고 메소드가 종료될 때 삭제. Stack에 생성
- 전역변수 : 해당 클래스 안에서 사용가능 (객체 생성시 해당 객체만). 객체가 생성될 때 생성되고 객체가 소멸할 때 삭제. Heap에 생성
- 정적변수 : private으로 생성시 실제 생성된 객체끼리 공유, public으로 생성시 어디서든 사용가능. 프로그램 시작/종료. Static에 생성


public class Test{

private static int staticVal;    // 정적변수 (클래스변수)

private int globalVal;          // 전역변수 (멤버변수)

public void local(){

int localVal;                // 지역변수

}


}


final 키워드 : 상수화 시키는 키워드. 변수 데이터 타입 앞에 final 키워드를 붙이면 상수화 시키겠다 라는 의미
final 변수는 명명규칙에 의하여 대문자를 사용


int a = 10;          // 10을 담고 있는 a라는 변수

final int a = 10;    // 10을 담고 있는 a라는 상수


static을 명시하면서 final 키워드를 붙이게 되면 어디서든 사용가능한 상수 라는 의미


public static final int RED = 0xFF0000;    // final 변수는 명명규칙에 의하여 대문자를 사용


메소드에 사용되는 static 키워드 와 final 키워드
- 메소드에 static 키워드를 붙이게 되면 객체의 메소드가 아닌 클래스의 메소드. 따로 객체를 만들고 사용하지 않아도 된다 (즉석 사용 가능)
- 메소드에 final 키워드를 붙이게 되면 메소드 오버라이딩을 막겠다는 의미
- 클래스에 final 키워드를 붙이게 되면 상속을 막겠다는 의미


getter 메소드와 setter 메소드
클래스를 개발할 때 멤버변수의 값을 넣거나 혹은 꺼낼 수 있는 메소드를 만들 때에는 get과 set을 메소드명에 붙여서 제작


this 키워드 : 해당 클래스 안에 존재하는 멤버변수를 표현할 때에는 this라는 키워드를 사용하여 자기 자신을 지칭. 해당 객체의 주소값을 담고 있다


// Setter 메소드 : 필드에 변경할 값을 전달 받아서 필드값을 변경하는 메소드

접근제한자 void set필드명(자료형 변수)

{

this.필드명 = 자료형 변수;

}


// Getter 메소드 : 필드에 기록된 값을 읽어서 요구하는 쪽으로 읽은 값을 넘기는 메소드

접근제한자 반환형 get필드명( )

{

return 필드명;

}


private String name;    // name이라는 멤버변수


public void setName(String name)    // 멤버변수와 매개변수의 이름이 동일한 경우 가장 가까운 변수를 지목한다

{

this.name = name;

}

public String getName( )

{

return name;

}


생성자와 소멸자
생성자는 class를 바탕으로 객체가 생성될 때 자동으로 호출되는 메소드

- 일반적으로 객체가 제대로 동작할 수 있게 준비하는 역할 (기본 데이터 입력)
- 메소드 이름은 클래스 이름과 같아야 하며 턴 값은 존재하지 않는다 (리턴 데이터 타입도 명시하지 않는다)
- 주의할 점 : 생성자 코드를 수정하게 되면 디폴트(기본) 생성자(매개변수가 존재하지 않는 생성자)가 없어지게 된다
- 일반 메소드와 마찬가지로 오버로딩이 가능


→ 메소드 오버로딩
메소드 호출시 메소드명과 매개변수 개수, 타입을 보고 호출할 메소드를 찾으므로,
같은 이름의 메소드명이라고 하더라도 매개변수의 개수가 다르거나 타입이 다르다면 동일한 메소드명으로 제작이 가능


class 클래스명

{

[접근제어지시자] 클래스명( ) {  }    // 기본 생성자 - 코드 꼭 추가

[접근제어지시자] 클래스명(매개변수)

{

(this.)필드명 = 매개변수;

}

}


소멸자는 객체가 소멸할 때 자동으로 호출되는 메소드 - 타 언어에서는 존재하지만 '자바'에서는 존재하지 않는다

- 존재하지 않는 이유
타 언어(c++)에서는 사용한 메모리에 대한 정리도 개발자가 직접 해야 한다. (new를 사용하면 사용한 객체를 지울 때는 delete를 코딩)
'자바'라는 언어는 메모리에 대한 정리는 개발자가 하지 않고 JVM이 직접 관리 하도록 하기 위하여 GC(Garbage Collector)가 존재
GC는 JVM에서 사용하는 메모리가 꽉차기 전에 자동으로 특정 알고리즘에 의해서 메모리 정리 역할을 한다
즉, 자바는 개발자에게 메모리 관리까지 생각하여 코딩하지 말고 프로그램 개발에만 집중할 수 있도록 만든 개발자 중심의 언어


has a 포함 관계 - A has a B : A 안에는 B가 포함되어 있다
자바에서 포함이란 재활용하고 싶은 클래스의 객체를 멤버변수로 선언하는 방법 - A 클래스 안에 B 클래스를 멤버 변수로 사용하겠다
자바에서는 데이터를 표현하는 클래스와 해당 데이터를 운영하는 클래스를 별도로 두고 있다.

- 데이터가 되는 클래스 : Entity, VO, DTO - 순수 데이터를 표현
- 데이터를 컨트롤 하는 클래스 : Controller - 데이터를 운영


public Student    // 데이터가 되는 클래스 (Entity 또는 VO 또는 DTO 라고 부름)

{

private String name;

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

public String getName(){ return this.name; }

}


public StuMgr    // Controller - 데이터를 운영하는 클래스

{

private Student s;

}


객체배열

Student [ ] stdArr = new Student[3]; // 레퍼런스 배열 생성 : 객체를 생성할 때 new 라는 연산자를 사용하여 생성

stdArr[0] = new Student();         // 각 레퍼런스 마다 new라는 연산자를 사용하여 객체를 생성함

stdArr[1] = new Student();         // 각 레퍼런스 마다 new라는 연산자를 사용하여 객체를 생성함

stdArr[2] = new Student();         // 각 레퍼런스 마다 new라는 연산자를 사용하여 객체를 생성함


→ Student [ ] stdArr = new Student[3]는
실제 객체들에 대한 배열을 만드는 것이 아닌 레퍼런스의 배열을 생성하는 것이므로 레퍼런스마다의 객체는 별도로 생성 해주어야 한다


+ Recent posts