8 분 소요

클래스

객체 지향 프로그래밍

부품에 해당하는 객체들을 먼저 만들고, 이것들을 하나씩 조립해서 완성된 프로그램을 만드는 기법

객체란

  • 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고 다른 것과 식별 가능한 것
  • 속성(필드)와 동작(메소드)로 구성

객체의 상호작용

  • 소프트웨어에서 객체들은 각각 독립적으로 존재하고, 다른 객체와 서로 상호작용 하면서 동작
  • 메소드 호출 : 객체가 다른 객체의 기능을 이용하는 것
    • 객체에 마침표(.) 연산자를 붙이고 메소드 이름 기술

객체 간의 관계

  • 집합 관계 : 객체 하나는 부품, 하나는 완성품에 해당 ⇒ 엔진, 타이어, 핸들 / 자동차
  • 사용 관계 : 객체 간의 상호작용
  • 상속 관계 : 상위 객체를 기반으로 하위 객체 생성

객체 지향 프로그래밍 특징

  • 캡슐화 : 객체의 필드, 메소드를 하나로 묶고 실제 구현 내용을 감추는 것
    • 외부 객체는 객체 내부 구조를 알지 못하며 객체가 노출해서 제공하는 필드와 메소드만 이용 가능
      • 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 하기 위해
    • 접근 제한자 : 캡슐화된 멤버를 노출 시킬 것인지 숨길 것인지 결정
  • 상속 : 상위 객체가 가지고 있는 필드와 메소드를 하위 객체에 물려주어 하위 객체가 사용할 수 있도록 함
    • 하위 객체 쉽고 빠르게 설계
    • 반복된 코드 중복 줄여줌
  • 다형성 : 같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질
    • 부모 클래스 또는 인터페이스의 타입 변환 허용
    • 객체의 부품화 가능

객체와 클래스

  • 클래스 : 객체를 만들기 위한 설계도
    • 객체를 생성하기 위한 필드와 메소드 정의
    • 인스턴스 : 클래스로부터 만들어진 객체
    • 하나의 클래스로부터 여러 개의 인스턴스를 만들 수 있음
  • 개발 단계
    1. 클래스 설계
    2. 클래스로 객체 생성
    3. 객체 이용

클래스 선언

  • 첫글자 대문자
  • 클래스 이름과 소스 파일명 같도록
  • 일반적으로 소스 파일당 하나의 클래스 선언
    • 두개 이상 클래스 선언 가능 ⇒ 파일 이름과 동일한 클래스 선언에만 public 접근 제한자 붙일 수 있음

객체 생성과 클래스 변수

  • new 연산자로 객체 생성
  • 메모리 힙 영역에 객체 생성 후 객체의 주소 리턴
  • 같은 클래스에서 생성되도 new 연산자로 생성하면 자신만의 고유 데이터를 가지면서 메모리에서 활동
    • 독립된 다른 객체

클래스 구성 멤버

필드

  • 객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳
  • 선언 형태는 변수와 비슷하지만 변수라고 부르지 않음
  • 생성자와 메소드 전체에서 사용되며 객체 소멸하지 않는 한 객체와 함께 존재
  • 선언
    • 클래스 중괄호 블록 어디서든 존재할 수 있음
    • 생성자와 메소드 중괄호 블록 내부에 선언될 수 없음 ⇒ 로컬 변수가 됨
    • 기본 타입, 참조 타입 모두 가능
  • 사용
    • 필드값을 읽고 변경하는 작업
    • 클래스 내부 ⇒ 필드 이름을 읽고 변경
    • 클래스 외부 ⇒ 클래스로부터 객체를 생성한 뒤 필드 사용
  • 초기화
    • 클래스로부터 객체가 생성될 때 필드는 기본 초기값으로 자동 설정
    • 다른 값으로 초기화 ⇒ 필드 선언할 때 초기값 주는 방법 / 생성자에서 초기값 주는 방법

생성자

  • new 연산자로 호출되는 특별한 중괄호 블록
  • 객체 생성 시 초기화 담당
  • 메소드와 비슷하게 생겼지만 클래스 이름으로 되어 있고 리턴 타입 없음
  • 기본 생성자
    • 클래스 내부에 생성자 선언 생략하면 컴파일러는 블록 내용이 비어있는 기본 생성자 바이트 코드에 자동 추가
    • 클래스가 public class로 선언되면 기본 생성자에도 public이 붙음
  • 선언
    • 메소드와 비슷한 형태 ⇒ 리턴 타입 없고 클래스 이름과 동일
    • 매개 변수는 여러개 선언하거나 생략 가능
    • 클래스에 생성자가 명시적으로 선언되어 있으면 반드시 선언된 생성자 호출해서 객체 생성
  • 오버로딩
    • 매개 변수를 달리하는 생성자를 여러 개 선언하는 것
  • 다른 생성자 호출(this())
    • 생성자 오버로딩이 많아질 경우 중복된 코드 발생할 수 있음 ⇒ 한 생성자에서 초기화 내용 집중적으로 작성, 나머지 생성자는 초기화 내용을 가지고 있는 생성자를 호출하는 방법으로 개선
    • 생성자에서 다른 생성자를 호출할 때 this() 사용
      • 자신의 다른 생성자를 호출한는 코드
      • 반드시 생성자의 첫줄에서만 허용

메소드

  • 객체의 동작에 해당하는 중괄호 블록
  • 메소드를 호출하면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행
  • 필드를 읽고 수정하거나, 다른 객체를 생성해서 다양한 기능 수행
  • 객체 간의 데이터 전달 수단
  • 선언
    • 선언부와 실행부로 구성
    • 리턴 타입 : 메소드가 실행 후 리턴하는 값의 타입
    • 리턴 타입이 있을 경우 저장할 변수가 있어야 함
    • 매개 변수 선언
      • 메소드가 실행할 때 필요한 데이터를 외부로부터 받기 위해 사용
      • 매개 변수의 수를 모를 경우
        • 매개 변수를 배열 타입으로 선언 ⇒ 메소드 호출하기 전에 배열 생성해야 함
        • 매개 변수를 를 사용해서 선언 ⇒ 메소드 호출 시 넘겨준 값의 수에 따라 자동으로 배열이 생성되고 매개값으로 사용
  • 리턴문
    • 리턴값이 있는 메소드
      • 리턴문이 있으면 반드시 리턴문 사용해서 리턴값 지정 ⇒ 리턴문 없으면 컴파일 오류
    • 리턴값 없는 메소드
      • 리턴값이 없어도 리턴문 사용할 수 있음 ⇒ 메소드 실행 강제 종료
  • 호출
    • 클래스 내부의 다른 메소드에서 호출할 경우 단순 메소드 이름으로 호출
    • 클래스 외부에서 호출할 경우 클래스로부터 객체 생성 뒤 참조 변수를 이용해서 메소드 호출 ⇒ 객체가 존재해야 메소드도 존재하기 때문
  • 오버로딩
    • 클래스 내에 같은 이름의 메소드를 여러 개 선언하는 것
    • 매개 변수의 타입, 개수, 순서 중 하나가 달라야 함
    • 매개값을 다양하게 받아 처리할 수 있도록 하기 위해 사용

인스턴스 멤버와 this

  • 인스턴스 멤버 : 객체(인스턴스)를 생성한 후 사용할 수 있는 필드(인스턴스 필드)와 메소드(인스턴스 메소드)

정적 멤버와 static

정적 멤버 선언

  • 정적 멤버 : 클래스에 고정된 멤버. 객체를 생성하지 않고 사용할 수 있는 필드(정적 필드)와 메소드(정적 메소드)
  • 클래스에 소속된 멤버이기 떄문에 클래스 멤버라고도 함
  • 선언
    • 필드와 메소드 선언 시 static 키워드 추가
    • 객체마다 가지고 있어야 할 데이터 ⇒ 인스턴스 필드로 선언
    • 객체마다 가지고 있을 필요성이 없는 공용적인 데이터 ⇒ 정적 필드로 선언

정적 멤버 사용

  • 클래스가 메모리로 로딩되면 정적 멤버 바로 사용 가능 ⇒ 클래스 이름과 마침표(.) 연산자로 접근

정적 초기화 블록

  • 정적 필드는 선언과 동시에 초기값을 주는 것이 보통 ⇒ 계산이 필요한 초기화 작업이 있을 수 있음
  • 정적 필드의 복잡한 초기화 작업을 위해 정적 블록 제공
  • 클래스가 메모리로 로딩될 때 자동으로 실행

정적 메소드 / 블록 선언 시 주의점

  • 객체가 없어도 실행된다는 특징 때문에 내부에 인스턴스 필드나 인스턴스 메소드 사용 불가
  • this 키워드 사용 불가
  • 인스턴스 멤버 사용시 객체를 먼저 생성하고 참조 변수로 접근
  • main() 메소드도 동일한 규칙 적용

싱글톤

  • 단 하나의 객체만 만들도록 보장해야 하는 경우 생성
  • 클래스 외부에서 new 연산자로 생성자를 호출할 수 없도록 막아야 함
  • private 접근 제한자 사용
  • 자신의 타입인 정적 필드 한개 선언 ⇒ 자신의 객체 생성해 초기화
    • private 사용해서 외부에서 필드값 변경하지 못하도록 막음
    • 외부에서 호출할 수 있는 정적 메소드인 getInstance() 선언, 자신의 객체 리턴 ⇒ 단 하나의 객체만 리턴

final 필드와 상수

final 필드

  • 초기값이 저장되면 최종값이 되어 프로그램 실행 도중에 수정할 수 없음
  • 초기값 주는 방법
    1. 필드 선언 시
    2. 생성자에서

상수

  • 불변의 값
  • final 필드와 다른 점 ⇒ 불변의 값은 객체마다 저장할 필요가 없는 공용성을 띠고 있으며, 여러 가지 값으로 초기화될 수 없음
  • static final 필드
  • 초기값이 단순 값이면 선언 시, 복잡한 초기화일 경우 정적 블록에서 시행
  • 상수 이름은 모두 대문자로 작성

패키지

  • 클래스를 체계적으로 관리하기 위해 패키지 사용
  • 클래스의 일부분
  • 클래스를 유일하게 만들어주는 식별자 역할 ⇒ 클래스 이름이 동일해도 패키지가 다르면 다른 클래스로 인식
  • 클래스만 따로 복사해서 다른 곳으로 이동하면 사용 불가 ⇒ 패키지 전체를 이동시켜야 함

패키지 선언

  • 도메인 이름 역순으로 패키지 이름 지정

import 문

  • 다른 패키지에 속하는 클래스를 사용하는 방법
    1. 패키지와 클래스 모두 기술 ⇒ 패키지 이름이 길거나 클래스 수가 많아지면 코드 난잡
    2. 사용하고자 하는 패키지 import문으로 선언, 클래스 사용할 때 패키지 생략
  • 패키지 선언과 클래스 선언 사이에 위치
  • import문으로 지정된 패키지의 하위 패키지를 쓰려면 하위 패키지도 import 해야함

접근 제한자

  • public : 외부 클래스가 자유롭게 사용할 수 있는 공개 멤버 생성
  • protected : 같은 패키지 또는 자식 클래스에서 사용할 수 있는 멤버 생성
  • private : 외부에 노출되지 않는 멤버
  • default : 같은 패키지에 소속된 클래스에서만 사용할 수 있는 멤버 생성

클래스의 접근 제한

  • default : 클래스 선언할 때 public 생략하면 default 접근 제한
    • 같은 패키지에서는 아무런 제한 없이 사용할 수 있지만 다른 패키지에서는 사용할 수 없도록 제한
  • public : 같은 패키지 뿐만 아니라 다른 패키지에서도 제한 없이 사용

생성자의 접근 제한

  • 클래스에 생성자를 선언하지 않으면 컴파일러에 의해 자동으로 지본 생성자 추가됨 ⇒ 자동으로 생성되는 기본 생성자의 접근 제한은 클래스의 접근 제한과 동일

    접근 제한자 생성자 설명
    public 클래스 public 접근 제한은 모든 패키지에서 제한 없이 생성자를 호출할 수 있도록 함. 생성자가 public 접근 제한을 가지면 클래스도 public 접근 제한을 갖는 것이 정상적. 클래스가 default면 생성자가 public 접근 제한을 갖더라도 같은 패키지에서만 생성자를 호출
    protected 클래스 default 접근 제한과 마찬가지로 같은 패키지에 속하는 클래스에서 생성자 호출.다른 패키지에 속한 클래스가 해당 클래스의 자식 클래스라면 생성자 호출 가능
    default 클래스 생성자를 선언할 때 접근 제한 생략하면 default. 같은 패키지에서 아무런 제한 없이 생성자를 호출할 수 있으나, 다른 패키지에서는 생성자를 호출할 수 없음
    private 클래스 어디서든 생성자를 호출하지 못하도록 제한. 클래스 내부에서만 생성자 호출, 객체 생성

필드, 메소드의 접근 제한

접근 제한자 생성자 설명
public 필드, 메소드 public 접근 제한은 모든 패키지에서 제한 없이 생성자를 호출할 수 있도록 함. 필드, 메소드가 public 접근 제한을 가지면 클래스도 public 접근 제한. 클래스가 default면 같은 클래스 안에서만 클래스가 사용
protected 필드, 메소드 default 접근 제한과 마찬가지로 같은 패키지에 속하는 클래스에서 필드, 메소드 호출. 다른 패키지에 속한 클래스가 해당 클래스의 자식 클래스라면 필드, 메소드 호출 가능
default 필드, 메소드 필드, 메소드를 선언할 때 접근 제한 생략하면 default. 같은 패키지에서 아무런 제한 없이 생성자를 호출할 수 있으나, 다른 패키지에서는 필드, 메소드 호출할 수 없음
private 필드, 메소드 어디서든 생성자를 호출하지 못하도록 제한. 클래스 내부에서만 생성자 호출, 객체 생성

Getter, Setter 메소드

  • 객체의 데이터는 외부에서 직접적으로 접근하는 것을 막음 ⇒ 객체 무결성을 위해
  • 메소드를 통해 데이터를 변경
  • Setter
    • 매개값을 검증해서 유효한 값만 데이터로 저장
  • Getter
    • 필드값을 가공한 후 외부로 전달
  • 외부에서 필드값 읽기 전용
    • Getter 메소드만 선언
    • Setter 메소드 private 접근 제한

어노테이션

  • 메타데이터 : 코드를 어떻게 컴파일하고 처리할 것인지 알려주는 정보
    1. 컴파일러에게 코드 문법 에러를 체크하도록 정보 제공
    2. 소프트웨어 개발 툴이 빌드나 배치 시 코드를 자동으로 생성할 수 있도록 정보 제공
    3. 실행 시 특정 기능을 실행하도록 정보 제공

어노테이션 타입 정의와 적용

  • 인터페이스를 정의하는 것과 유사
  • 엘리먼트를 멤버로 가질 수 있음. 각 엘리먼트는 타입과 이름으로 구성, 티폴트 값 가질 수 있음

적용 대상

ElementType 열거 상수 적용 대상
TYPE 클래스, 인터페이스, 열거 타입
ANNOTATION_TYPE 어노테이션
FIELD 필드
CONSTRUCTOR 생성자
METHOD 메소드
LOCAL_VARIABLE 로컬 변수
PACKAGE 패키지
  • @Target : 어노테이션이 적용될 대상 지정. 기본 엘리먼트 value는 ElementType 배열을 값으로 갖는다. ⇒ 어노테이션 적용될 대상 복수개로 지정하기 위해

어노테이션 유지 정책

  • 사용 용도에 따라 어느 범위까지 유지할 것인지 지정

    RetentionPolicy 열거 상수 설명
    SOURCE 소스상에서만 어노테이션 정보를 유지. 소스 코드를 분석할 때만 의미가 있으며, 바이트 코드 파일에는 정보가 남지 않음
    CLASS 바이트 코드 파일까지 어노테이션 정보를 유지. 하지만 리플렉션을 이용해서 어노테이션 정보를 얻을 수는 없다.
    RUNTIME 바이트 코드 파일까지 어노테이션 정보를 유지하면서 리플렉션을 이용해서 런타임 시에 어노테이션 정보를 얻을 수 있음

런타임 시 어노테이션 정보 사용

  • 어노테이션 자체는 아무런 동작을 가지지 않는 표식 ⇒ 리플렉션을 이용해서 어노테이션의 적용 여부와 엘리먼트 값을 읽고 적절히 처리할 수 있음
  • 클래스에 적용된 어노테이션 ⇒ java.lang.Class로 정보 얻음
  • 필드, 생성자, 메소드 ⇒ java.lang.reflect 패키지의 Field, Constructor, Method 타입의 배열 얻어야 함

    리턴 타입 메소드명(매개 변수) 설명
    Field[ ] getFields() 필드 정보를 Field 배열로 리턴
    Constructor[ ] getConstructors() 생성자 정보를 Constructor 배열로 리턴
    Method[ ] getDeclaredMethods() 메소드 정보를 Method 배열로 리턴
  • Field, Constructor, Method의 메소드를 호출해서 적용된 어노테이션 정보 확인

    리턴 타입 메소드명(매개 변수)
    boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 지정한 어노테이션이 적용되었는지 여부. Class에서 호출했을 때 상위 클래스에 적용된 경우에도 true 리턴
    Annotation getAnnotation(Class annotationClass) 지정한 어노테이션이 적용되어 있으면 어노테이션 리턴, 아니면 null 리턴. Class에서 호출했을 때 상위 클래스에 적용된 경우에도 어노테이션 리턴
    Annotation[ ] getAnnotations() 적용된 모든 어노테이션 리턴. Class에서 호출했을 때 상위 클래스에 적용된 어노테이션도 모두 포함. 적용된 어노테이션 없을 경우 길이가 0인 배열 리턴
    Annotation[ ] getDeclaredAnnotations() 직접 적용된 모든 어노테이션 리턴. Class에서 호출했을 때 상위 클래스에 적용된 어노테이션은 미포함.