210104 이것이 자바다 6장

송은석·2021년 1월 4일
0
post-thumbnail

신용권 님의 ''이것이 자바다'' 6장 공부 기록

책을 보면서 새롭게 눈에 들어온 부분만 담았다. 이전에 배운 부분이기도 하고, 비교적 간단한 내용을 다루고 있기 때문이다.

6. 클래스

6.1 객체 지향 프로그래밍

소프트웨어를 개발할 때 부품에 해당하는 객체들을 먼저 만들고, 이것들을 하나씩 조립해서 완성된 프로그램을 만드는 기법을 객체 지향 프로그래밍(OOP:Object Oriented Programming)이라고 한다.

6.1.1 객체란?

객체란 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고 다른 것과 식별 가능한 것을 말한다.

  • 객체는 속성과 동작으로 구성되어 있으며, 이를 각각 필드(field)와 메소드(method)라고 부른다.
  • 현실 세계의 객체를 소프트웨어 객체로 설계하는 것을 객체 모델링(Object Modeling)이라고 한다. 이는 현실 세계의 객체의 속성과 동작을 추려내어 소프트 웨어 객체의 필드와 메소드로 정의하는 과정이라고 볼 수 있다.

6.1.2 객체의 상호작용

객체들은 각각 독립적으로 존재하고, 다른 객체와 서로 상호작용하면서 동작하는데, 이 때 객체들의 상호작용 수단이 메소드이다. 객체가 다른 객체의 기능을 이용하는 것이 메소드 호출이다.

  • 메소드 호출은 도트(.)연산자를 통해서 할 수 있다. 도트 연산자는 객체의 필드와 메소드에 접근할 때 사용한다.

    ex) 객체.필드, 객체.메소드(매개값), 리턴값 = 객체.메소드(매개값)

  • 매개값은 메소드를 실행하기 위해 필요한 데이터이다. 리턴 값은 메소드가 실행하고 나서 호출한 곳으로 돌려주는 값이다.

객체의 상호작용은 객체 간의 메소드 호출을 의미하며, 매개값과 리턴값을 통해서 데이터를 주고 받는다.

6.1.3 객체 간의 관계

  • 객체는 대부분 다른 객체와 관계를 맺는다.
    1. 집합 관계 : 하나는 부품이고 하나는 완성품인 관계이다. 자동차와 핸들, 타이어 등의 부품 간의 관계라고 볼 수 있다.
    2. 사용 관계 : 객체 간의 상호작용을 말한다. 자동차를 쓰는 사람과 자동차의 관계 라고 할 수 있다.
    3. 상속 관계 : 상위(부모) 객체를 기반으로 하위(자식) 객체를 생성하는 관계를 말한다. ex) 자동차(하위)-기계(상위)

6.1.4 객체지향 프로그래밍의 특징

  1. 캡슐화(Encapsulation)
    • 객체의 필드와 메소드를 하나로 묶고, 접근제한자를 사용하여 실제 구현 내용을 감추는 것을 말한다.
    • 외부 객체는 객체 내부의 구조를 알지 못하며, 노출된 정보만 이용할 수 있다.
    • 이는 외부의 잘못된 사용으로 객체가 손상되지 않도록 하는데 있다.(무결성)
  2. 상속(Inheritance)
    • 상위 객체를 재사용해서 하위 객체를 쉽고 빨리 설계할 수 있도록 도와주고, 이미 잘 개발된 객체를 재사용해서 새로운 객체를 만들도록 하는 것이다.
    • 이로써 반복된 코드의 중복을 줄일 수 있다. 또한 유지보수 시간을 최소화시킬 수 있다.
  3. 다형성(Polymorphism)
    • 같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질을 말한다.

6.2 객체와 클래스

  • 자동체를 설계도를 보고 만드는 것처럼, oop에서는 클래스를 설계도 삼아 객체를 생성한다.
  • 클래스로부터 만들어진 객체를 해당 클래스의 인스턴스(instance)라고 한다.
  • main() 메소드가 없는 클래스는 객체 생성과정을 통해 사용해야 한다.

6.3 클래스 선언

  • 클래스 이름은 규칙에 따라 지으며, 클래스이름.java로 소스파일을 생성한다.
  • 일반적으로 소스 파일당 하나의 클래스를 선언하나, 두 개 이상도 가능하다. 권하지는 않는다. 이러한 소스 파일을 컴파일하면 바이트 코드 파일은 클래스를 선언한 개수 만큼 생긴다. 결국 소스파일은 클래스 선언을 담고 있는 저장단위일 뿐이기 때문이다.
  • 파일이름과 동일한 클래스 선언에만 public 접근 제한자를 붙일 수 있다. ex) public class oop{ ... }

6.4 객체 생성과 클래스 변수

  • 클래스 역시 new 연산자를 통해 객체를 생성할 수 있다. new연산자로 힙 영역에 객체를 생성 후, 객체의 주소를 리턴하여 참조타입인 클래스 변수에 저장하여 객체를 사용할 수 있다.
  • 힙 영역에 생성된 객체들은 자신만의 고유데이터를 가지면서 완전히 독립적으로 사용된다.
  • 클래스는 라이브러리(API:Application Program Interface)용과 실행용으로 나뉜다. 라이브러리 클래스는 다른 클래스에서 이용할 목적으로 설계되며, 실행 클래스는 프로그램의 실행 진입점인 main() 메소드를 제공하는 역할을 한다.

6.5 클래스의 구성멤버

  • 필드(Field), 생성자(Constructor), 메소드(Method)가 있다.

6.6 필드

  • 필드는 객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳이다. 변수와 선언 형태가 비슷하나, 변수는 아니다. 필드는 객체가 소멸되지 않는 한 계속 존재한다는 점이 다르다.

  • 클래스 중괄호 블록 어디든 존재할 수 있으나, 생성자와 메소드 블록 안에 들어가면 로컬 변수가 되므로 불가하다.

  • 모든 데이터 타입이 사용 가능하고, 초기값을 지정하지 않고 선언시 기본 초기값으로 설정된다.

  • 필드를 사용한다는 것은 필드값을 읽고 변경하는 작업을 말한다. 이 때 클래스 내부의 생성자나 메소드에서는 단순히 필드 이름으로 읽고 변경하나, 클래스 외부에서 사용시에는 우선적으로 클래스로부터 객체를 생성한 후 도트 연산자를 통해 사용할 수 있다.


6.7 생성자

  • 생성자는 new 연산자로 호출되는 특별한 중괄호 블록이다. 객체 생성시 초기화를 담당한다. 리턴타입이 없다.

  • 객체 초기화란 필드를 초기화하거나, 메소드를 호출하여 객체를 사용할 준비를 하는 것을 말한다.

6.7.1 기본 생성자

  • 모든 클래스는 생성자가 반드시 하나 이상 존재한다. 생성자 선언을 생략했다면 컴파일러는 중괄호 블록 내용이 비어 있는 기본 생성자(Default Constructor)를 바이트 코드에 자동 추가시킨다.
  • 클래스가 public class이면 기본 생성자에도 public이 붙지만, class로만 선언시 붙지 않는다.
  • 그러나 명시적으로 선언한 생성자가 하나라도 있으면 컴파일러는 기본 생성자를 추가하지 않는다.
  • 객체를 다양하게 초기화하기 위해 생성자를 명시적으로 선언한다.

6.7.2 생성자 선언

//생성자의 명시적 선언 기본 형태
클래스(매개변수선언, ... ){
    //객체의 초기화 코드
}
  • 매개변수 선언은 생략할 수 있으며, 여러 개 할 수도 있다. 이는 생성자 호출시 외부의 값을 생성자 블록 내부로 전달하는 역할을 한다.
  • 명시적으로 생성자가 선언시에는 반드시 선언된 생성자를 호출하여 객체를 생성해야 한다.

6.7.3 필드 초기화

  • 객체 생성시 필드는 기본 초기값으로 설정되나, 다른 값으로 초기화하고 싶다면 다음의 방법을 사용한다..
    1. 필드를 선언할 때 초기값으로 선언한다.
    2. 생생자를 선언할 때 매개값을 통해 초기화한다.
  • 생성자로 필드 초기화 시 필드와 동일한 이름을 갖는 매개 변수를 설정하는데, 동일한 이름의 매개 변수가 사용 우선순위가 높으므로 필드 앞에 this를 붙여 사용한다. this는 객체 자신의 참조이다.
public 클래스이름(매개변수1){
    this.매개변수1 = 매개변수;//this를 붙이면 필드의 매개변수1을 참조한다.
}

6.7.4 생성자 오버로딩(Overloading)

  • 외부에서 제공되는 다양한 데이터들을 이용해서 객체를 초기화하려면 생성자도 다양화될 필요가 있다.
  • 생성자가 하나만이라면 여러 요구 조건을 수용할 수 없으므로, 자바는 매개 변수를 달리하는 생성자를 여러 개 선언하는 생성자 오버로딩을 제공한다.
  • 오버로딩 시 매개 변수의 타입, 개수, 순서가 다르게 선언되어야 한다. 이름만 바꾸는 것은 오버로딩이 아니다.

6.7.5 다른 생성자 호출(this())

  • 생성자 오버로딩이 많아질 경우 생성자 간의 중복된 코드가 발생할 수 있다. 이 경우 필드 초기화 내용을 한 생성자에만 집중적으로 작성하고 나머지 생성자는 초기화 내용을 가지고 있는 생성자를 호출하는 방법으로 개선할 수 있다.
클래스( 매개변수선언 ...){
    this(매개변수, ......);//클래스의 다른 생성자 호출
    실행문;
}
  • this()는 자신의 다른 생성자를 호출하는 코드로 반드시 생성자의 첫줄에서만 허용된다.
car(String model){
    this(model, 은색);
}
car(String model, String color){
    this.model = model;
    this.color = color;
}

6.8 메소드

  • 메소드는 객체의 동작에 해당하는 중괄호 블록을 말한다. 메소드는 필드를 읽고 수정하는 역할도 하고, 다른 객체를 생성해서 다양한 기능을 수행하기도 한다. 객체 간의 데이터 전달의 수단으로 사용된다. 리턴값을 줄 수도 있다.

6.8.1 메소드 선언

  • 선언부(리턴타입, 메소드이름, 매개변수선언)와 실행 블록으로 구성된다. 메소드 선언부를 메소드 시그니처(signature)라고도 한다.

  • 리턴값이 없는 경우 리턴 타입에 void가 오고, 리턴값이 있는 메소드는 리턴 값의 타입이 와야 한다. 그러나 리턴 타입이 있다고 해서 반드시 리턴값을 변수에 저장할 필요는 없다.

  • 메소드 이름은 기능 이름으로 지어주는 것이 좋다.

  • 매개변수는 메소드 실행 시 필요한 데이터를 외부로부터 받기 위해 사용된다. 매개 값을 받을 때 자동변환이 사용될 수 있다.

  • 매개 변수의 수를 모를 경우

    • 매개 변수를 배열 타입으로 선언해야 한다.
int[] values = {1, 2, 3};
int result = sum1(values);
int result = sum1(new int []{1,2,3,4,5});
  • 배열을 생성하지 않고 값의 리스트만 넘겨주는 방법도 있다. 매개변수를 "···"를 사용해서 선언하면 넘겨준 값의 수에 따라 자동으로 배열이 생성되고 매개값으로 사용된다.
int sum2(int ··· values){}
//ex 사용시
int result = sum2(1,2,3);
int result = sum2(1,2,3,4,5);
  • "···"로 선언된 매개 변수는 배열 타입이므로 위와 같이 배열을 직접 사용해도 된다.

6.8.2 리턴문

메소드 선언에 리턴 타입이 있는 메소드는 반드시 리턴문을 사용해서 리턴값을 지정해야한다. 없을 시 컴파일 오류가 발생한다. return 문 실행시 메소드는 즉시 종료된다.

  • 리턴문에서 리턴 값은 리턴 타입이거나 리턴 타입으로 변환될 수 있으면 된다.

  • 리턴문 이후 실행문은 실행되지 않는다.(Unreachable code 컴파일 오류 발생) 다만 if문과 같은 경우 가능할 수 있다.

  • 리턴 값이 없는 메소드에서도 return값을 사용하여 메소드 실행을 강제 종료시킬 수 있다. while문이 있고 뒤에 실행문이 더 있는 경우라면, break문을 사용할 수도 있다.

6.8.3 메소드 호출

  • 클래스 내부에서 호출 시 메소드 이름으로 호출, 외부에서 호출시 객체 생성 후 참조 변수와 객체 접근 연산자인 도트 연산자 이용하여 메소드 호출

6.8.4 메소드 오버로딩

  • 클래스내에 같은 이름의 메소드를 여러 개 선언하는 것을 메소드 오버로딩이라고 한다.

  • 조건은 매개 변수의 타입, 개수, 순서 중 하나가 달라야한다.

  • 주의할 점은 매개 변수의 타입과 개수, 순서가 같을 경우 매개변수 이름만 바꾸는 것은 메소드 오버로딩이 아니다. 또한 리턴 타입만 다르고 매개변수가 동일하다면 오버로딩이 아니다. 리턴 타입은 자바 가상 기계가 메소드를 선택할 때 아무런 도움을 주지 않는다.

  • 메소드 오버로딩의 가장 대표적인 예는 System.out.println() 메소드이다.(여러 타입 대입 가능)


6.9 인스턴스 멤버와 this

인스턴스(intstance) 멤버란 객체를 생성한 후 사용할 수 있는 필드와 메소드를 말하며, 이들을 각각 인스턴스 필드, 인스턴스 메소드라고 부른다. 인스턴스 필드와 메소드는 객체 생성 없이 사용할 수 없다.

  • 인스턴스 필드는 객체 마다 따로 존재하며, 인스턴스 메소드는 객체 마다 존재하지 않고 메소드 영역에 저장되고 공유된다.
  • this : 주로 생성자와 메소드의 매개 변수 이름이 동일한 경우, 인스턴스 멤버인 필드임을 명시하고 할 때 사용된다.

6.10 정적 멤버와 static

정적 멤버는 클래스에 고정(static)된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메소드를 말한다. 이들을 각각 정적 필드, 정적 메소드라고 부른다. 이들은 객체가 아닌 클래스에 소속된 멤버이기 때문에 클래스 멤버라고도 한다.

  • 필드와 메소드 선언 시 static 키워드를 붙임으로 선언할 수 있다.
public class 클래스 {
    //정적 필드
    static 타입 필드 [=초기값];
    //정적 메소드
    static 리턴타입 메소드 (매개변수선언···){···};
}
  • 정적 필드와 메소드는 클래스에 고정된 멤버이므로 클래스 로더가 클래스(바이트 코드)를 로딩해서 메소드 메모리 영역에 적재할 때 클래스별로 관리된다. 따라서 클래스의 로딩이 끝나면 바로 사용할 수 있다.
  • 정적 필드 선언 기준 : 객체마다 가지고 있어야 할 데이터라면 인스턴스 필드로, 아닌 공용적 데이터라면 정적 필드로 선언하는 것이 좋다.
  • 정적 메소드 선언 기준 : 인스턴스 필드를 이용해서 실행해야 하면 인스턴스 메소드로, 이용하지 않는다면 정적 메소드로 선언한다.

6.10.1 정적 멤버 사용

  • 클래스가 메모리로 로딩되면 정적 멤버를 사용할 수 있는데, 클래스 이름과 함께 도트 연산자로 접근한다.
클래스.필드;
클래스.메소드(매개값);
  • 객체를 참조하여 접근할 수도 있으나, 정적요소는 클래스 이름으로 접근하는 것이 좋다.

6.10.2 정적 초기화 블록

  • 정적 필드는 필드 선언과 동시에 초기값을 주는 것이 보통이나, 계산이 필요한 초기화 작업이 필요할 경우 정적 블록을 이용한다.
static {
    ...
}
  • 정적 블록은 클래스가 메모리로 로딩될 때 자동적으로 실행되며, 클래스 내부에 여러개 있어도 상관은 없다. 선언된 순서대로 실행된다.
  • 정적 메소드와 블록 선언 시 객체가 없어도 실행되므로 이들 내부에 인스턴스 필드나 메소드, 그리고 객체 자신의 참조인 this 키워드 사용이 불가하다. 인스턴스 멤버를 사용하고 싶다면 블록 내에서 객체를 먼저 생성하고 참조 변수로 접근해야 한다.
  • 이는 main () 메소드에서도 동일한 규칙으로 적용된다. main메소드도 정적 메소드이므로 객체 생성 없이 인스턴스 멤버를 바로 사용할 수 없는 것이다.

6.10.3 싱글톤(Singlegon)

  • 전체 프로그램에서 단 하나의 객체만 만들도록 보장하는 경우가 있는데, 이 객체를 싱글톤이라고 한다.
  • 클래스 외부에서 new 연산자로 생성자를 호출할 수 없도록 막아야 하는데, 이를 위해 생성자 앞에 private 접근 제한자를 붙인다. 또한 자신의 타입인 정적 필드를 하나 선언하고 자신의 객체를 생성해 초기화한다. 정적 필드에도 private 접근 제한자를 붙인다.
public class 클래스{
	//정적 필드
	private static 클래스 singleton =new 클래스();
	
	//생성자
	private static 클래스(){}
	
	//정적 메소드 
	static 클래스 getInstance(){
		return singleton;
	}
}
  • 대신 외부에서 호출할 수 있는 정적 메소드인 getInstance()를 선언하여 정적 필드에서 참조하고 있는 자신의 객체를 리턴해준다.
클래스 변수1 = 클래스.getInstance();
클래스 변수2 = 클래스.getInstance(); // 동일한 객체를 참조한다.
  • 싱글톤은 고정된 메모리를 사용함으로 메모리 낭비를 방지하며, 전역 인스턴스로써 다른 클래스에 데이터를 공유하기 쉽다.
  • 그러나 멀티스레드에 좋지 않고, 객체 지향과는 거리가 있는 등의 단점을 가지기도 한다.

6.11 final 필드와 상수

6.11.1 final 필드

  • final필드란 초기값이 저장되면 이것이 최종적인 값이 되어서 프로그램 실행 도중에 수정할 수 없다는 것이다.
final 타입 필드[= 초기값]; // 선언 방식
  • final 필드의 초기값은 필드 선언 시 주는 방법과, 생성자에서 주는 방법 두 가지이다.복잡한 초기화 코드가 나오거나 객체 생성 시 외부 데이터로 초기화를 해야하는 경우 생성자에서 초기값을 지정해야 한다. 초기화 되지 않은 final 필드는 컴파일에러를 발생시킨다.

  • 객체 마다 가지는 불변의 인스턴트 필드라고 할 수 있다.

6.11.2 상수(static final)

  • 상수는 불변의 값을 뜻한다.

  • final 필드와 다른 것은,객체 마다 저장할 필요가 없는 공용성을 띠며, 여러 값으로 초기화될 수 없다는 것이다.

  • static final 필드는 객체마다 저장되지 않고, 클래스에만 포함된다. 또한 초기값이 저장되면 변경할 수 없다.

static final 타입 상수 [=초기값];
  • 초기 값이 단순 값이라면 선언 시 주는 것이 일반적이나, 복잡한 초기화일 경우 정적 블록에서도 할 수 있다.
  • 상수 이름은 모두 대문자로 작성하며, 혼합된 이름은 _(언더바)로 연결한다.

6.12 패키지

  • 패키지는 자바에서 클래스를 체계적으로 관리하기 위해 사용하는 파일 시스템의 폴더라고 할 수 있다.

  • 또한 클래스를 유일하게 만들어주는 식별자 역할을 한다.

    상위패키지.하위패키지.클래스
  • 클래스를 이동할 경우 피키지 전체를 이동시켜야 한다.

6.12.1 패키지 선언

  • 패키지는 클래스를 컴파일하는 과정에서 자동으로 생성되는 폴더이다. 이 때 클래스를 해당 폴더로 자동 생성시킨다.

    package 상위패키지.하위패키지;
    
    public class ClassName{...};
  • 흔히 회사의 도메인 이름으로 패키지를 만든다.

  • cmd에서 패키지 포함된 클래스를 선언할 경우, javac 명령어 다음에 -d 옵션을 추가하고 경로를 지정해야 한다.

  • 패키지 선언이 없는 클래스 파일은 default 패키지로 가게 된다.

6.12.2 import문

  • 다른 패키지에 속한 클래스들을 사용하려면?

    1. 패키지와 클래스를 모두 기술하는 것이다.
    package com.mycompany;
    
    public class Car{
        com.hankook.Tire tire = new com.hankook.Tire(); // com.hankook 패키지 소속 Tire 클래스 선언함
    }//코드가 조금 난잡해질 수 있다.
    
    // 서로 다른 패키지에 동일한 클래스 이름이 존재하고, 두 패키지가 모두 import되어 있을 경우 반드시 이 방법을 사용한다.
    1. 사용하고자 하는 패키지를 import문으로 선언하고, 클래스를 사용할 대는 패키지를 생략한다.
    package com.mycompany;
    
    import com.hankook.Tire; // 혹은 import com.hankook.*;
    
    public class Car{
        Tire tire = new Tire(); // com.hankook 패키지 소속 Tire 클래스 선언함
    }

6.13 접근 제한자

  • 객체 생성을 막기 위해 생성자를 호출하지 못하게 하거나 객체의 특정 데이트를 보호하기 위해 해당 필드에 접근하지 못하도록 막을 때, 그리고 특정 메소드를 호출할 수 없도록 할 때 접근 제한자(Access Modifier)를 사용한다.

  • 접근 제한자는 public, protected, default, private가 있다.

  • public 접근 제한자는 외부클래스가 자유롭게 사용할 수 있는 공개 멤버를 만든다. 이는 클래스, 필드, 생성자, 메소드가 적용된다.

  • protected 접근 제한자는 같은 패키지 또는 자식 클래스에서 사용할 수 있는 멤버를 만든다. 필드, 생성자, 메소드가 적용된다.

  • private 접근 제한자는 개인적인 것이라 외부에 노출되지 않는 멤버를 만든다. 필드, 생성자, 메소드에 적용된다.

  • default 접근 제한자는 위 세 접근 제한자가 적용되지 않은 멤버인데, 같은 패키지에 소속된 클래스에서만 사용할 수 있는 멤버이다. 클래스, 필드, 생성자, 메소드가 적용된다.

6.13.1 클래스의 접근 제한

  • 클래스에 적용할 수 있는 접근 제한은 public과 default 두 가지이다.
  • default 클래스를 가지게 되면, 다른 패키지에서는 사용이 제한된다.
  • public 클래스를 가지게 되면, 다른 패키지에서도 제한 없이 사용될 수 있다.

6.13.2 생성자의 접근 제한

  • 클래스 접근 제한자에 따라 기본 생성자도 default, public 접근 제한자가 될 수 있다.
  • public 생성자는 모든 패키지에서 호출 가능하나, 클래스가 default 제한을 가진다면 같은 패키지에서만 호출가능하다.
  • protected 생성자는 같은 패키지에 속하는 클래스만 호출가능하나, 다른 패키지에 속한 클래스가 해당 클래스의 자식(child)라면 생성자를 호출할 수 있다.
  • default 생성자는 같은 패키지에서만 생성자 호출이 가능하게 한다.
  • private 생성자는 오로지 클래스 내부에서만 생성자를 호출하여 객체를 만들 수 있게 한다.

6.13.3 필드와 메소드의 접근 제한

  • 필드와 메소드를 선언할 때는 클래스 내부에서만 사용할 것인지, 패키지 내부에서만 사용할 것인지, 다른 패키지에서도 사용할 수 있도록 할 것인지를 결정해야 한다. 이 때 접근 제한자를 사용한다.

  • public 필드와 메소드는 모든 패키지에서 접근 가능하다. 이 경우 클래스도 public 접근 제한자를 가져야 한다.

  • protected 필드와 메소드는 같은 패키지에서만 접근 가능하나, 다른 패키지라도 자식 클래스라면 접근 가능하다.

  • default 필드와 메소드는 같은 패키지에서만 접근이 가능하다.

  • private 필드와 메소드는 오로지 클래스 내부에서만 사용가능하다.


6.14 Getter와 Setter 메소드

  • 객체 지향 프로그래밍에서는 객체의 데이터를 객체 외부에서 직접적으로 접근하는 것을 막는데, 이는 외부에서 데이터를 변경할 경우 객체의 무결성이 깨어질 수 있기 때문이다.
  • 그래서 oop에서는 메소드를 통해 데이터를 변경하는 방법을 선호한다. 데이터는 외부접근을 막고 메소드를 통해 데이터에 접근하게 한다. 그 이유는 메소드는 매개값을 검증해서 유효한 값만 데이터로 저장할 수 있기 때문이다. 이 역할을 하는 메소드가 Setter이다.
  • 외부에서 객체의 데이터를 읽을 때 사용하는 메소드는 Getter이다. 메소드로 필드값을 가공한 후 외부로 전달하는 역할을 한다.
private 타입 fieldName;

//Getter
public 리턴타입 getFieldName(){
    return fieldName;
}
//Setter
public void setFieldNam(타입 fieldName){
    this.fieldName = fieldName;
}
  • 필드 타입이 boolean 일 경우에는 Getter에서 get으로 시작하지 않고 is로 시작한다. ex) isfield()

6.15 어노테이션

어노테이션(Annotation)은 메타데이터(metadata)이다. 메타데이터란 애플리케이션이 처리해야 할 데이터가 아니라, 컴파일 과정과 실행 과정에서 코드를 어떻게 컴파일하고 처리할 것인지를 알려주는 정보이다.

  • 어노테이션은 세 가지 용도로 사용된다.
    1. 컴파일러에게 코드 문법 에러를 체크하도록 정보를 제공
    2. 소프트웨어 개발 툴이 빌드나 배치 시 코드를 자동으로 생성할 수 있도록 정보를 제공
    3. 실행 시(런타임 시) 특정 기능을 실행하도록 정보를 제공

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

  • 어노테이션 타입을 정의하는 방법은 인터페이스를 정의하는 것과 유사하다.

    public @interface Annotation{
    }
    • 이렇게 정의한 어노테이션은 코드에서 @AnnotationName 으로 사용될 수 있다.
  • 어노테이션은 엘리먼트(element)를 멤버로 가질 수 있다.

    public @interface AnnotationiName{
        타입 elementName() [default]; //엘리먼트 선언
    }
    • 엘리먼트 타입으로 기본 데이터 타입이나 String, 열거, class 타입과 배열 타입이 사용가능하다.
    • 메소드를 작성하는 것처럼 엘리먼트 이름 뒤에 ()를 붙여야 한다.
    public @interface AnnotationName{
        String elementName1();
        int elementName2() default 5;
    }
    • 이렇게 정의한 어노테이션을 코드에서 적용할 때는 다음과 같이 기술한다.
    AnnotationName(elementName1="값", elementName2 =3);
    //디폴드 값이 있다면 생략가능하다.
    AnnotationName(elementName1="값");
    • 어노테이션은 기본 엘리먼트인 value를 가질 수 있다. 따라서 value 엘리먼트를 가진 어노테이션은 값만 기술될 수 있다.
    @AnnotationName("값"); //자동으로 value 값으로 설정된다.
    • 한편 value와 다른 엘리먼트의 값을 동시에 주고 싶다면 정상적인 방법으로 지정하면 된다.
    @AnnotationName(value ="값",elementName2 =2);

6.15.2 어노테이션 적용 대상

  • 어노테이션을 적용할 수 있는 대상은 java.lang.annotation.ElementType 열거상수 목록이다.
  • 어노테이션의 적용 대상을 지정할 때는 @Target 을 사용한다. @Target의 기본 엘리먼트인 value는 ElementType 배열을 값으로 가진다. 이것은 어노테이션이 적용될 대상을 복수 개로 지정하기 위해서이다.
@Target({ElementType.TYPE, ElementType.Field, ElementType.METHOD})
public @interface AnnotationName{
} // 클래스와 필드, 메소드만 어노테이션을 적용할 수 있다.
@AnnotationName
public class ClassName{
    @AnnotationName
    private String fieldName;
    
    //@AnnotationName -> 안됨
    public ClassName(){}
    
    @AnnotationName
    public void methodName(){}
}

6.15.3 어노테이션 유지 정책

  • 사용 내용에 따라 @AnnotationName을 어느 범위까지 유지할 것인지 지정해야 한다.
  • ex) 소스까지(SOURCE), 컴파일된 클래스까지(CLASS), 런타임 시까지(RUNTIME) // RetentionPolicy 열거상수로 정의되어 있음.
  • 리플렉션(Reflection)이란 런타임 시에 클래스의 메타 정보를 얻는 시능을 말한다.
  • 보통 어노테이션은 런타임 시점에 사용하기 위한 용도로 만들어진다.
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationName{
} //런타임 유지 정책을 적용한 어노테이션

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

  • 아직 무슨 말인지 잘 모르겠음. 추후 정리하겠음.

확인문제를 풀면서 알게 된 점
ex20 계좌만들기

profile
Done is better than perfect🔥

0개의 댓글