도서/자바의 신

[도서/자바의 신] #13 인터페이스와 추상클래스, enum

yulee_to 2022. 12. 23. 19:10

자바의 신

✔️이 글은 [자바의 신 - 이상민 지음] 도서를 바탕으로 정리한 글입니다. 


메소드 내용이 없는 interface

시스템 "방법론" 순서

  • 분석 : 시스템 제작을 요청한 사람들(SI에서는 고객, SM에서는 현업, 별도의 고객이 없는 회사는 기획이 업무를 수행)의 요구사항을 분석
  • 설계 : 분석 단계에서 만든 대략적인 기획을 프로그램으로 만들 수 있도록 설계
  • 개발 및 테스트 : 설계에서 만든 것을 개발하는 단계, 기능들이 제대로 동작하는지 테스트하는 작업도 수행
  • 시스템 릴리즈 : 시스템을 사용자에게 제공, 오픈 이후에는 운영/유지보수 단계를 거치면서 문제있는 부분을 수정해 나감

이 절차는 아주 일반적인 절차로 모든 개발 절차가 이렇진 않다. 

 

인터페이스와 abstract가 필요한 이유?

  • 설계 시 선언해 두면 개발할 때 기능 구현에만 집중하면 됨
  • 개발자의 역량에 따른 메소드의 이름과 매개 변수 선언의 격차를 줄일 수 있음
  • 공통적인 인터페이스와 abstract 클래스를 선언해 놓으면, 선언과 구현을 구분할 수 있음

인터페이스와 abstract의 역할로 사용하는 메소드의 내부 구현이 어떻게 되어있는지 사용자가 알 필요가 없기 때문에 그냥 원하는 메소드를 호출하고 그 결과를 받기만 하면 된다. 

가장 일반적인 것이 DAO(Data Access Object)라는 패턴으로 데이터를 저장하는 저장소에서 원하는 값을 요청하고 응답을 받는다.

인터페이스를 직접 만들어보자

인터페이스 클래스는 접근 제어자와 클래스 이름 사이에 class 예약어를 대신해 interface 예약어를 사용한다.

접근 제어자 interface 클래스 이름 { }

인터페이스 내부에 선언된 메소드들은 body(몸통)이 있으면 안된다. 즉 메소드 매개변수 소괄호가 닫히고 바로 세미콜론이 와야 한다.

인터페이스 클래스 파일 이름도 .java로 끝나고 일반 자바 파일과 똑같이 컴파일해준다. 

인터페이스 파일에 명시적인 단어를 지정하지 않거나, 구분하기 위해 클래스 이름앞에 I를 붙이는 등의 방법이 있지만 이건 개발 표준을 잡는 사람이 정한다.

 

인터페이스를 적용할 때는 적용할 클래스 선언문의 클래스 이름 뒤에 implements 예약어를 써주고 인터페이스들을 나열하면 된다.

상속과 달리 인터페이스는 여러개를 implements할 수 있다. 

해당 클래스에서 implements한 인터페이스 안의 메소드들을 모두 구현을 해줘야 컴파일이 정상적으로 수행된다. 

 

이렇게 설계 단계에서 인터페이스를 만들어 놓으면 개발 단계에서 실제 작업을 수행하는 메소드 내부만 구현해주면 돼서 더 효율적으로 관리할 수 있다. 

다른 용도로는 외부에 노출되는 것을 정의해 놓고자 할 때 사용된다. 

 

인터페이스 클래스로는 안에 메소드들이 구현되어 있지 않기 때문에 객체를 생성할 수 없으므로 인터페이스 클래스를 타입으로 하는 객체를 생성할 때는 implements된 클래스의 생성자로 객체를 생성해줘야 한다. 

일부 완성되어 있는 abstract 클래스

인터페이스와 클래스의 중간인 abstract 클래스는 그 자체로 초기화 및 실행이 안되고, abstract 클래스를 구현해 놓은 클래스로 초기화 및 실행을 해줄 수 있다. 

abstract 클래스 선언시 class 예약어 앞에 abstract 예약어를 추가해주고, 구현하지 않은 메소드들의 타입 앞에도 abstract를 써준다. 

abstract 메소드가 하나라도 있으면 그 클래스도 abstract로 선언해줘야 하지만, abstract 클래스 내에는 abstract로 선언된 메소드가 0개 이상 있으면 된다. 

abstract 클래스 안에 구현된 메소드가 있어도 되고, static이나 final 메소드가 있어도 된다. 

 

인터페이스와 달리 abstract 클래스는 "클래스"이기 때문에 상속처럼 extends 예약어를 사용해 구현해준다. 

그리고 상속받은 클래스에서 abstract로 선언된 메소드들을 구현해줘야 한다. 

인터페이스에서 어떤 기능들은 미리 구현해둬도 상관없을 때 abstract 클래스를 주로 사용한다.

 

인터페이스 vs abstract 클래스 vs 클래스

  인터페이스 abstract 클래스 클래스
선언 시 사용하는 예약어 interface  abstract class class
구현 안 된 메소드 포함 가능 여부 가능(필수)  가능 불가
구현된 메소드 포함 가능 여부 불가 가능 가능(필수)
static 메소드 선언 가능 여부 불가 가능 가능
final 메소드 선언 가능 여부 불가 가능 가능
상속(extends) 가능 불가 가능  가능
구현(implements) 가능 가능 불가 불가

나는 내 자식들에게 하나도 안 물려 줄꺼여

final이라는 예약어는 "마지막"이라는 뜻이다.

 

클래스에 final을 선언할 때는 접근제어자와 class 예약어 사이에 final을 넣어주면 된다.

이 final 클래스는 객체를 생성하고 선언된 메소드 사용에는 문제가 없지만 상속은 해줄 수 없다.

누군가 이 클래스를 확장하거나 내용을 변경해서는 안될 때 클래스에 final 예약어를 사용해준다.

 

메소드를 final로 선언할 때도 접근제어자와 리턴 타입 사이에 final을 넣어준다.

final로 선언한 메소드는 Overriding할 수 없게 해주기 때문에 내용을 변경하지 못하게 할 때 메소드에 final을 써준다.

 

변수를 final로 선언할 때는 자료형 앞에 final을 써준다.

변수에 final을 쓰는건 클래스와 메소드랑은 달리 "더 이상 바꿀 수 없다"라는 뜻으로 쓰인다. 

그래서 final이 붙은 인스턴스 변수나 static 변수는 선언할 때 값을 지정해줘야 다른 객체에서 중복하여 초기화하는 걸 막아준다. 

매개변수나 지역변수를 final로 선언한 경우는 매개변수는 넘어올 때 초기화되어 있을거고, 지역변수는 중괄호 내에서만 사용되기 때문에 반드시 선언할 때 초기화할 필요는 없다. 초기화 이후에 값을 변경하는 것만 안하면 된다. 

 

참조자료형에 final을 쓰면 두번 이상 값을 할당하거나, 새로 생성자를 사용하여 초기화할 수 없다.

다만 final로 만든 객체 안의 값들 중에서 final로 선언되지 않은 것들은 수정할 수 있다!

final 객체라 해서 그 안에 있는 것들도 다 final인 건 아니다. 

enum 클래스라는 상수의 집합도 있다

어떤 클래스가 상수만으로 만들어져 있을 때 enum이라는 예약어로 "이 객체는 상수의 집합이다"라는 것을 명시적으로 나타낸다.

enum은 enumeration이라는 셈, 계산, 열거, 목록, 일람표라는 영어 단어의 앞부분만 따서 만들어진 예약어이다.

enum 클래스는 "열거형" 클래스라고 불러도 무방하다

 

enum 클래스 예시

public enum OverTimeValues {
    THREE_HOUR,
    FIVE_HOUR,
    WEEKEND_FOUR_HOUR,
    WEEKEND_EIGHT_HOUR;
}

이 4개의 상수는 별도로 타입을 지정할 필요도, 값을 지정할 필요도 없다. 

예시처럼 상수들만 선언하면 가장 마지막 세미콜론은 안써줘도 된다.

 

enum을 사용하는 가장 효과적인 방법은 switch문에서 사용하는 것이다.

 

enum타입은 "enum클래스이름.상수이름"을 지정함으로써 클래스의 객체가 생성된다.

enum 클래스는 생성자를 만들 수는 있지만 생성자를 통해 객체를 생성할 수는 없다.

enum을 보다 제대로 사용하기

enum 상수들의 값을 정적으로 지정해줄 수 있다.

 

enum 클래스 예시

public enum OverTimeValue2 {
    THREE_HOUR(18000), 
    FIVE_HOUR(30000), 
    WEEKEND_FOUR_HOUR(40000),
    WEEKEND_EIGHT_HOUR(60000);
    
    private final int amount;
    OverTimeValue2(int amount) {
        this.amount = amount;
    }
    public int getAmount() {
        return amount;
    }
}

enum 클래스의 생성자는 접근제어자를 명시하지 않는 package-private이나 private만 사용이 가능하다.

즉, 각 상수를 enum 클래스 내에서 선언할 때만 생성자를 사용할 수 있다.

생성자를 구현해주지 않으면 컴파일시 자동으로 생성해준다.

 

예시의 getAmount()처럼 메소드도 일반 클래스처럼 만들어놓고 사용할 수 있다.

 

enum 클래스를 선언하면 선언 자체는 간단해지지만 구현이 복잡해진다.

enum 클래스 안의 상수들의 값이 바뀌면 자바 프로그램을 수정하고 다시 컴파일해서 다시 수행해야 한다는 단점이 존재하지만, 성능은 좋다.

enum 클래스의 부모는 무조건 java.lang.Enum이어야 해요 

enum 클래스는 무조건 java.lang.Enum 클래스의 상속을 받는다. enum으로 선언시 자동으로 extends java.lang.Enum을 컴파일러가 넣어준다.

그렇기 때문에 enum클래스 선언시 extends를 사용해 다른 클래스를 확장해주어선 안되고, 다른 enum 클래스를 extends를 이용해 선언할 수도 없다.

 

Enum 클래스의 생성자

protected Enum(String name, int ordinal) : 컴파일에서 자동으로 호출되도록 해놓은 생성자. 개발자가 이 생성자를 호출할 수는 없음

여기서 name은 enum 상수 이름이고 ordinal은 enum의 순서이며, 상수가 선언된 순서대로 0부터 증가하는 값이다.

 

Enum 클래스의 부모 클래스도 Object로 Object 내의 메소드를 사용할 수 있지만 clone(), finalize(), hahsCode(), equals() 메소드는 Enum 클래스에서 Overriding할 수 없게 막혀있다. hashCode()와 equals()는 사용할 수 있지만 clone()과 finalize()는 사용하면 안된다.

Object 클래스 메소드를 Overriding한 toString()을 호출하면 상수 이름을 출력한다 .이 메소드는 Enum 클래스에서 Overriding한 Object 클래스 메소드 중에서 유일하게 final로 선언되어 있지 않아 우리가 Overriding해서 사용할 수 잇다.

 

Enum 클래스의 메소드

메소드 내용

compare(E e) 매개 변수로 enum 타입과의 순서(ordinal) 차이를 리턴. 매개변수보다 앞에 있으면 음수, 뒤에 있으면 양수 값 리턴
getDeclaringClass() 클래스 타입의 enum을 리턴
name() 상수 이름 리턴
ordinal() 상수의 순서 리턴
valueOf(Class<T> enumType, String name) static 메소드. 첫번째 매개변수로는 클래스 타입의 enum을, 두번째 매개변수로는 상수의 이름을 넘겨줌

 

API에 명시되어 있지 않은 특수한 메소드로 values()라는 메소드가 있다.

values()는 enum 클래스에 선언되어 있는 모든 상수를 배열로 리턴해준다.

 

enum은 JDK 1.5에서부터 나온 예약어이다.


정리해 봅시다

1. 인터페이스에 선언되어 있는 메소드는 body(몸통)가 있어도 되나요?

NO

2. 인터페이스를 구현하는 클래스의 선언시 사용하는 예약어는?

interface

3. 일부만 완성되어 있는 클래스는?

abstract 클래스

4. 3번의 답에 있는 클래스에 body(몸통)가 없는 메소드를 추가하려면 어떤 예약어를 추가해야 하나요?

abstract

5. 클래스를 final로 선언하면 어떤 제약이 발생하나요?

클래스를 확장할 수 없다.

6. 메소드를 final로 선언하면 어떤 제약이 발생하나요?

override가 불가능하다.

7. 변수를 final로 선언하면 어떤 제약이 발생하나요?

기본 자료형의 경우 값을 변경할 수 없고, 참조 자료형의 경우 한번 생성한 뒤로는 다시 생성해줄 수 없다. 

따라서 변수는 대부분 선언과 동시에 값을 할당한다.

8. enum 클래스 안에 정의하는 여러 개의 상수들을 나열하기 위해서 상수 사이에 사용하는 기호는 무엇인가요?

, (콤마)

9. enum으로 선언한 클래스는 어떤 클래스의 상속을 자동으로 받게 되나요?

java.lang.Enum

10. enum 클래스에 선언되어 있지는 않지만 컴파일시 자동으로 추가되는 상수의 목록을 배열로 리턴하는 메소드는?

values()

 

728x90