🟨 목 차 🟨
1. 메소드 내용이 없는 interface
1-1. 분석
1-2. 설계
1-3. 개발 및 테스트
1-4. 시스템 릴리즈
1-5. 인터페이스, abstract 클래스를 사용해야 하는 이유
2. 인터페이스를 직접 만들어보자
2-1. 인터페이스를 제대로 사용하는 방법
3. 일부 완성되어 있는 abstract 클래스
3-1. 인터페이스와 abstract클래스, 클래스의 차이(중요)
4. 나는 내 자식들에게 하나도 안물려 줄꺼야(final)
4-1. 클래스에 final을 선언 할 때
4-2. 메소드를 final로 선언하는 이유는?
4-3. 변수에서 final을 써보자.
5. enum 클래스라는 상수의 집합도 있다.
5-1. enum을 보다 제대로 사용하기
5-2. enum 클래스의 부모는 무조건 java.lang.enum 이어야 해요.
6. 인터페이스, abstract 클래스, enum 총 정리
◼️ 1. 메소드 내용이 없는 interface ◼️
자바에서 .class 파일을 만들 수 있는것은 클래스 뿐만 아니라 interface와 abstract 클래스라는 것이 있다.
abstract 클래스에 대해서 제대로 이해하기 위해선 시스템을 만드는 절차가 어떻게 되는지 알아야한다.
어떤 시스템을 개발하든 간에 "방법론"이라는 것을 사용하여 개발한다. 방법론이라는 것은 시스템을 어떻게 만들 것인지에 대한 절차를 설명하고, 어떤 문서를 작성해야 하는지를 정리해 놓은 공동 절차라고 보면 된다.
일반적인 절차는 다음과 같다.
- 분석
- 설계
- 개발 및 테스트
- 시스템 릴리즈
◼️ 1-1. 분석
시스템을 분석하는 단계에서는 시스템을 만들어 달라고 한 사람들에게 어떻게 개발하기를 원하는지 물어본다. 이러한 일련의 과정을 요구사항 분석이라고 한다. 그 외에도 분석에서 하는 일은 여러 가지이다. 그 중 주된 작업이 요구 사항 분석이라고 보면 된다.
◼️ 1-2. 설계
설계 단계에서는 분석 단계에서 만든 대략적인 그림을 프로그램으로 만들 수 있도록 설계하는 작업을 수행한다.
이 단계에서 어떤 메소드를 만들 것인지, 데이터는 어떻게 저장할 지 등등의 세부적인 것들을 정리한다.
◼️ 1-3. 개발 및 테스트
설계에서 만들기로 한 것들을 개발하는 단계다. 실제 시스템에서 제공해야 하는 기능들을 이때 만든다.
이 만드는 작업을 개발이라고 한다. 필요한 기능들이 제대로 동작하는지 확인하는 "테스트"작업을 수행한다.
◼️ 1-4. 시스템 릴리즈
시스템을 드디어 사용자에들에게 제공하는 단계다. 프로그램은 사람이 만들기 때문에 절대 완벽한 시스템은 없다.
따라서, 시스템을 오픈한 이후에는 운영/유지보수 단계를 거치면서 문제가 있는 부부들을 고쳐나간다.
◼️ 1-5. 인터페이스, abstract 클래스를 사용해야 하는 이유
인터페이스와 abstract 클래스를 설명하는데 방법론을 이야기 한 이유가 뭘까 ?
==> 설계 단계에서 프로그램을 어떻게 만들 것인지를 정리한다고 했다. 이 정리하는 작업을 할 때 그냥 워드나 엑셀 같은 문서를 만드는 것이 아니라 어떤 클래스를 만들지, 어떤 메소드를 만들지, 어떤 변수를 만들지를 정리하는 작업도 같이한다.
그런데, 내용들을 문서에만 정리하면 나중에 메소드 관련 내용들이 변경되면 문서도 수정해야 하므로, 2중 3중의 일이 된다.
그래서, 이 설계 단계에서 인터페이스라는 것을 만들어 두면 개발할 때 메소드의 이름을 어떻게 할 지, 매개변수를 어떻게 할지를 일일이 고민하지 않아도 된다. 또한 개발자의 역량에 따라서 메소드 이름과 매개변수 이름이 천차만별일 수가 있는데 격차를 줄이는 데 큰 역할을 한다.
또 다른 인터페이스나 abstract 클래스를 사용해야 하는 이유를 알아보자.
예를 들어, 어느 학원의 회원 정보를 확인 하는 MemberDAO라는 인터페이스를 만든다고 생각해본다. 필요한 기능으로 회원의 전화번호를 매개변수로 넘겨주면 회원의 상세정보를 제공하든지, 이름을 넘겨주면 동명이인을 포함한 정보들의 목록을 보여준다는지 여러 종류의 메소들이 존재할 것이다.
이러한 메소드들은 어떠한 DBMS를 사용해도 상관 없도록 만들어져 있을 것이다. 즉, 이 인터페이스를 구현해서 Oracle을 사용하든, MongoDB를 사용하든 간에 작성한 메소드에서 결과만 제대로 넘겨주면 된다.
==> 즉, 인터페이스를 정해 놓으면 선언과 구현을 구분 할 수 있다.
인터페이스와 abstract 클래스를 사용하는 이유
- 설계시 선언해 두면 개발할 때 기능을 구현하는 데에만 집중할 수 있다.
- 개발자의 역량에 따른 메소드의 이름과 매개 변수 선언의 격차를 줄일 수 있다.
- 공통적인 인터페이스와 absract 클래스를 선언해 놓으면, 선언과 구현을 구분할 수 있다.
◼️ 2. 인터페이스를 직접 만들어보자 ◼️
MemberDTO를 관리하는, MemberManagerImpl이라는 클래스를 만들어야 한다고 가정하자.
실제 코드는 만들지 않더라도 어떤 메소드들이 있어야 하는지를 정의하려고 할 때 인터페이스를 사용하면 된다.
[EX]
package part13;
import part8.MemberDTO;
public interface MemberManager {
public boolean addMember(MemberDTO member);
public boolean removeMember(String name, String phone);
public boolean updateMember(MemberDTO member);
}
==> 위의 코드를 보게 되면 인터페이스 선언부는 public class로 시작하지 않고, public interface로 시작한다.
또한 인터페이스 내부에 선언된 메소드들은 몸통(body)이 있으면 안된다. 즉, 메소드 선언 이후에 중괄호를 열고, 닫거나, 중괄호 안에 한 줄의 코드도 있으면 안된다. (쉽게, 중괄호는 인터페이스 선언을 위한 가장 상위의 중괄호만 있어야 된다고 생각하면 된다.)
위에서 만든 인터페이스를 이용해보자.
[EX]
package part13;
public class MemberManagerImpl implements MemberManager{
}
==> 여기서 인터페이스를 적용할때는 예약어 중에 가장 긴 implements를 사용하고 인터페이스들을 나열하면 된다. 인터페이스는 여러개 implements 할 수 있다.
자바에서는 extedns를 "상속한다" 라고 말을 하고 implements를 "구현한다"라고 말을 한다.
즉, implements 한다고 해서 상속 받는것이 아니라 해당 클래스에서 구현해야 하는 인터페이스들을 정의함으로써 클래스에 짐(숙제)를 지어주는 것이다.
위의 코드의 결과는 컴파일 에러가 난다. 왜냐하면 인터페이스를 implements를 하면 그 인터페이스안에 있는 짐(메소드)을 정의해줘야 하는데 정의 해주지 않았기 때문이다.
==> 우리가 인터페이스를 구현할 경우(implements)에는 반드시 인터페이스에 정의된 메소드들의 몸통을 만들어 주어야만 한다.
[EX]
package part13;
import part8.MemberDTO;
public class MemberManagerImpl implements MemberManager{
@Override
public boolean addMember(MemberDTO member) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean removeMember(String name, String phone) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean updateMember(MemberDTO member) {
// TODO Auto-generated method stub
return false;
}
}
==> 컴파일이 정상적으로 수행된다.
여기서 개발자들이 해야 하는 일은 대충 return false만 적어 놓은 메소드들이 실제로 Member 정보를 저장하고, 삭제하고, 수정하는 일을 할 수 있도록 제대로 된 코드를 만드는 것이다. 바로 이 작업이 개발 프로세스 중에서 "개발"에 해당한다.
[정리]
설계 단계에서 인터페이스만 만들어 놓고, 개발 단계에서 실제 작업을 수행하는 메소드를 만들면 설계 단계의 산풀물과 개발 단계의 산출물이 보다 효율적으로 관리된다.
그런데 이렇게 설계에서만 사용하려고 인터페이스를 만드는것은 아니다.
인터페이스의 또 다른 용도는 외부에 노출되는 것을 정의해 놓고자 할 때 사용한다. 다시 말해서 MemberManagerImpl이라는 클래스가 있는데, 이 클래스가 "나한테 직접 이야기 하지 말고 공식적인 것은 대변인을 통해 말해달라"라고 했을때 대변인이 바로 인터페이스이다.
인터페이스에는 구현 되어 있는 코드가 없다. 따라서 만들어지는 파일이 .class의 확장자를 가진다고 해서 인터페이스를 그대로 사용할 수 없다.(생성자도 없고, 메소드의 내용 중 아무것도도 채워져 있지 않기 때문이다.)
인터페이스는 static이나 final 메소드가 선언되어 있으면 안된다.
◼️ 2-1. 인터페이스를 제대로 사용하는 방법
아무것도 구현되어 있지 않은 인터페이스의 객체를 만들게 되면 컴파일러가 아무것도 구현해 놓지 않았다면서 에러가 난다.
인터페이스 객체를 어떻게 사용할까? 아래 예시를 보면서 이해하자.
[EX]
package part13;
import part8.MemberDTO;
public interface MemberManager {
public static void main(String[] args) {
MemberManager member = new MemberManagerImpl();
}
public boolean addMember(MemberDTO member);
public boolean removeMember(String name, String phone);
public boolean updateMember(MemberDTO member);
}
[MemberManagerImpl을 사용하기 위해 임포트를 하고 진행한다.]
==> 위의 코드를 보면 겉으로 보기엔 member 타입은 MemberManager이다. 그리고 MemberManagerImpl 클래스에는 인터페이스에 선언되어 있는 모든 메소드들이 구현되어 있다. 따라서, 실제 member의 타입은 MemberManager가 되기 때문에, member에 선언된 메소드들을 실행하면 MemberManagerImpl에 있는 메소드들이 실된다.
◼️ 3. 일부 완성되어 있는 abstract 클래스 ◼️
인터페이스도 아닌 클래스도 아닌 absract클래스에 대해서 알아본다.
absract의 뜻은 "추상적인"의 의미이다.
자바에서는 absract 클래스는 자바에서 마음대로 초기화하고 실행할 수 없도록 되어 있다. 그래서, 그 absract 클래스를 구현해 놓은 클래스로 초기화 및 실행이 가능하다.
[EX]
package part13;
import part8.MemberDTO;
public abstract class MemberManagerAbstract {
public abstract boolean addMember(MemberDTO member);
public abstract boolean removeMember(String name, String phone);
public abstract boolean updateMember(MemberDTO member);
public void printLog(String data) {
System.out.println("Data="+data);
}
}
==> abstract 클래스는 선언시 class라는 예약어 앞에 abstract이라는 예약어를 사용한다.
인터페이스와 동일하게 몸통이 없는 메소드를 명시한 것을 볼 수 있다.
abstract 클래스는 abstract로 선언한 메소드가 하나라도 있을 때 선언한다.
또한 인터페이스와 달리 구현되어 있는 메소드가 있어도 상관이 없다.
[정리]
- abstract 클래스는 클래스 선언시 abstract이라는 예약어가 클래스 앞에 추가되면 된다.
- abstract 클래스 안에는 absract으로 선언된 메소드가 0개 이상 있으면 된다.(없어도 된다는 말)
- abstract으로 선언된 메소드가 하나라도 있으면 그 클래스는 반드시 absract으로 선언되어야만 한다.
- abstract 클래스는 몸통이 있는 메소드가 0개 이상 있어도 전혀 상관 없으며, static이나 final 메소드가 있어도 된다.
(인터페이스는 static이나 final 메소드가 선언되어 있으면 안된다.) - abstract 클래스는 인터페이스처럼 Implements 예약어를 사용해서 구현하는게 아니라 클래스 이기 때문에 extends를 이용해서 상속받는다.
[EX]
package part13;
public class MemberManagerImpl2 extends MemberManagerAbstract {
}
==> 위의 코드를 보게 되면 extends를 이용하여 memberManagerAbstract를 상속받는것이다.
결과를 보면 컴파일 오류가 뜬다. 이유는 absract으로 선언되어 있는 메소드들을 구현하지 않았기 때문이다.
[ 자바에서 인터페이스나 abstat 클래스의 상속을 받으면 구현되지 않은 메소드들을 구현하는 작업이 상속세를 내는 것과 동일하다고 볼 수 있다. ]
abstract메소드를 구현해보자.
[EX]
package part13;
import part8.MemberDTO;
public class MemberManagerImpl2 extends MemberManagerAbstract {
@Override
public boolean addMember(MemberDTO member) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean removeMember(String name, String phone) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean updateMember(MemberDTO member) {
// TODO Auto-generated method stub
return false;
}
}
==> 왜 이런 abstract 클래스를 만들었을까?
왜냐하면 인터페이스를 선언할때 어떤 메소드는 미리 만들어 놓아도 전혀 문제가 없는 경우가 발생한다. 그렇다고 해당 클래스를 만들기는 좀 애매하기는 하고 말이다. 특히 아주 공통적인 기능을 미리 구현해 놓으면 많은 도움이 된다. 이럴때 사용하는 것이 바로 abstract 클래스이다.
◼️ 3-1. 인터페이스와 abstract클래스, 클래스의 차이
==> 중요한 것은 언제 인터페이스를 사용해야 할지, abstract 클래스를 사용할지를 구분해 내는 것이다.
또한 인터페이스와 abstract 클래스를 구현하는 방법과 이유를 알고 있어야 한다.
또한 extends 뒤에는 클래스가 단 하나만 존재 할 수 있고, implements 뒤에는 인터페이스가 여러 개 존재 할 수 있다는 것을 알아야한다
◼️ 4. 나는 내 자식들에게 하나도 안물려 줄꺼야 ◼️
상속과 관련하여 알아두어야 하는 예약어 하나 더는 final 이다.
final은 클래스, 메소드, 변수에 선언할 수 있다.
◼️ 4-1. 클래스에 final을 선언 할 때
클래스 선언시 final을 접근 제어자와 class 예약어 사이에 추가 할 수 있다.
[EX]
package part13;
public final class FinalClass {
}
==> 이렇게 클래스가 final로 선언되어 있으면 상속을 해 줄 수 없다.
◼️ 4-2. 메소드를 final로 선언하는 이유는?
메소드의 경우도 클래스에 final로 선언하는 경우와 비슷한 이유로 사용한다.
메소드를 final로 선언하면 더 이상 Overriding 할 수 없다.
[EX]
package part13;
public abstract class FinalMethodClass {
public final void printLog(String data) {
System.out.println("Data="+data);
}
}
package part13;
public class FinalMethodChildClass extends FinalMethodClass{
public void printLog(String data) {
System.out.println("Data="+data);
}
}
==> 위의 코드를 실행해보면 오류가 난다. 왜냐하면 final로 선언된 메소드를 Overriding했기 때문이다.
즉, 우리가 힘들게 만든 메소드를 누가 변경 하지 못하도록 하려면 final로 만등ㄹ어 다른 개발자가 그 메소드를 덮어 쓰는 것을 간단하게 막을 수 있다.
◼️ 4-3. 변수에서 final을 써보자.
클래스나 메소드에 final을 사용하면 더 이상 상속을 못 받게 하고, 더 이상 Override 할 수 없게 하는 것이다.
하지만, 변수에 final을 사용하는 것은 "더 이상 바꿀 수 없다."라는 말이다. 그래서 인스턴스 변수나 static으로 선언된 클래스 변수는 선과 함께 값을 지정해야만 한다.
[EX]
package part13;
public class FinalVariable {
final int instanceVariable;
}
==> 위의 final 변수를 실행시키면 에러가 발생한다. 그 이유는 final로 선언된 인스턴스변수, 클래스 변수는 변수 생성과 동시에 초기화를 해야만 컴파일 시 에러가 발생하지 않는다.
[EX]
package part13;
public class FinalVariable {
// final int instanceVariable;
public void method(final int parameter) {
final int localVariable;
localVariable=2;
localVariable=3;
parameter=4;
}
}
==> 위의 코드는 매개변수나 지역 변수를 final로 선언하는 경우이다. 오류가 난다.
매개변수나 지역변수를 final로 선언할 때 초기화 할 필요는 없다.(매개변수는 이미 초기화가 되어서 넘어 왔고, 지역 변수는 메소드를 선언하는 중괄호 내에서만 참조되기 때문)
하지만 final 변수를 초기화한 값을 또 다시 초기화하면 안된다 그렇기 때문에 오류가 났던 것이다.
기본자료형에 대한 final선언에 대해 알아보았다. 참조 자료형에 대한 final 선언에 대해 알아보자.
[EX]
package part13;
import part8.MemberDTO;
public class FinalReferenceType {
final MemberDTO dto=new MemberDTO();
public static void main(String[] args) {
FinalReferenceType referenceType = new FinalReferenceType();
}
public void checkDTO() {
System.out.println(dto);
dto = new MemberDTO();
}
}
==> 위 코드를 실행시켜보면 dto = new MemberDTO(); 부분에서 컴파일 오류가 난다.
그 이유는 dto라는 객체(참조차료형)가 final인데 값을 할당했기 때문이다.(초기화해줘서) [ 참조자료형 dto도 인스턴스 변수이기 때문에 final로 선언한 동시에 초기화해야만 한다.]
그러면 final로 선언된 객체에 선언되어 있는 변수들을 사용해보자.
[EX]
package part13;
import part8.MemberDTO;
public class FinalReferenceType {
final MemberDTO dto=new MemberDTO();
public static void main(String[] args) {
FinalReferenceType referenceType = new FinalReferenceType();
}
public void checkDTO() {
System.out.println(dto);
// dto = new MemberDTO();
dto.name="Sangmin";
System.out.println(dto);
}
}
==> 위의 코드를 실행시켜보면 컴파일 오류가 나지 않는다.
즉, final로 선언된 클래스변수, 인스턴스 변수는 두 번 이상 할당하거나 생성자로 초기화할 수 없다. 하지만 그 객체들의 변수는 사용가능하다.
◼️ 4. enum 클래스라는 상수의 집합도 있다. ◼️
final로 String 같은 문자열이나 숫자들을 나타내는 기본 자료형의 값을 고정시킬 수 있는데, 이것을 상수라고 한다. (영어로 constant)
어떤 클래스가 상수만으로 만들어져 있을 경우에는 반드시 class로 선언할 필요는 없다.
==> 이 경우에 class라고 선언하는 부분에 enum이라고 선언하면 "이 객체는 상수의 집합이다"라는 것을 명시적으로 나타낸다.
enum클래스는 어떻게 보면 타입이지만, 클래스의 일종이다. 그렇기에 enum 클래스라고 부르면 된다. (열거형이다.)
[EX]
package part13;
public enum OverTimeValues {
THREE_HOUR,
FIVE_HOUR,
WEEKEND_FOUR_HOUR,
WEEKEND_EIGHT_HOUR;
}
==> 위의 코드는 평일 3시간이상~5시간 미만일 때 야근 수당과 5시간 이상일 때의 야근 수당이 다르고, 주말 4시간 이상~ 8시간 미만일 때의 휴일 근무 수당과 8시간 이상일 때의 야근 수당이 있다고 하자.
enum 클래스에 있는 상수들은 신기하기 타입과 값을 지정할 필요도 없다. 그냥 상수들의 이름만 콤마로 구분하여 나열해주면 된다.(열거형)
이렇게 설정을 학 enum 클래스를 사용하여 보자.
[EX]
package part13;
public class OverTimeManager {
public int getOverTimeAmout(OverTimeValues value) {
int amount = 0;
System.out.println(value);
switch(value) {
case THREE_HOUR:
amount=18000;
break;
case FIVE_HOUR:
amount = 30000;
break;
case WEEKEND_FOUR_HOUR:
amount = 40000;
break;
case WEEKEND_EIGHT_HOUR:
amount = 60000;
break;
}
return amount;
}
}
==> 위의 코드를 보게되면 getOverTimeAmout()메소드를 보게되면 OerTimeValues라는 enum 타입을 매개변수로 받고, 변수명은 value이다. 야근수당은 amount 라는 int 타입을 선언하고 그 값을 마지막에 리턴한다.
여기서 드는 의문점은 OverTimeValues라는 enum 타입을 어떻게 getOverTimeAmout() 메소드에 전달할까? 아래 코드를 보면 이해가 갈 것이다.
[EX]
public static void main(String[] args) {
OverTimeManager manager = new OverTimeManager();
int myAmount = manager.getOverTimeAmout(OverTimeValues.FIVE_HOUR);
System.out.println(myAmount);
}
==> 위의 코드에서 OverTimeValues.FIVE_HOUR을 보게 되면 enum 타입은 "enum클래스이름.상수이름"을 지정함으로써 클래스의 객체 생성이 완료된다고 생각하면 된다.
즉, 이해하기 쉽게 enum타입인 OverTimeValues.FIVE_HOUR의 코드를 풀어서 쓰면
OverTimeValues value = OverTimeValues.THREE_HOUR;
int myAmount = manager.getOverTimeAmount(value);
◼️ 4-1. enum을 보다 제대로 사용하기
앞에서 보듯 enum 타입은 항상 switch로 확인해야 할까? 그냥 각 상수의 값을 지정할 수 없을까?
==> enum 상수 값을 지정하는 것은 가능하다. 단, 값을 동적으로 할당하는 것은 불가능하다.
[EX]
package part13;
public enum OverTimeValues2 {
THREE_HOUR(18000),
FIVE_HOUR(30000),
WEEKEND_FOUR_HOUR(40000),
WEEKEND_EIGHT_HOUR(60000);
private final int amount;
private OverTimeValues2(int amount) {
this.amount = amount;
}
public int getAmount() {
return amount;
}
}
==> 위의 코드를 보면 각 상수들에 값이 지정되었고, amount라는 변수는 final로 선언되어 있다.
enum 클래스도 생성자를 사용할 수 있지만, public이라고 되어 있지 않다. 즉, enum클래스의 생성자는 아무것도 명시하지 않은 package-private와 private만 접근제어자로 사용할 수 있다.
즉, enum 클래스에서 각 상수를 enum 클래스 내에서 선언할때 package-private을 사용한다.
위에서 만든 OverTimeValues2 enum 클래스를 사용해보자.
[EX]
package part13;
public class OverTimeManager2 {
public static void main(String[] args) {
OverTimeValues2 values2 = OverTimeValues2.FIVE_HOUR;
System.out.println(values2);
System.out.println(values2.getAmount());
}
}
FIVE_HOUR
30000
enum 클래스를 이용하는 2가지 방법을 알려주었다.
- 첫번째 보여주었던 방법은,
enum 클래스 선언 자체는 간단하지만, 추후 사용할때 구현이 약간 복잡해진다. 메소드를 호출하여 switch로 값을 간단히 할당하기는 햇지만, 3시간 근무할 경우의 야근수당이 2000원 오르면 어떻게 될까? 이 값이 항상 바뀔 수 있는 경우에는 원격 서버에 있는 값을 읽어오도록 하면 큰 문제가 없다.(어차피 enum 클래스에 값이 없고 원하는 값을 내가 조절하기 때문) - 두번째 보여주었던 방법은,
만약 야근 수당이 2000원 오르면 자바 프로그램을 수정한 후(enum 클래스에 값을 정해주어 내용을 수정해야 하기 때문) 다시 컴파일에서 실행중인 자바 프로그램을 중지했다가 다시 시작해야 한다는 단점이 존재하지만 성능을 훨 좋을 것이다.
◼️ 4-2. enum 클래스의 부모는 무조건 java.lang.enum 이어야 해요.
자바에서는 다중 상속은 허용되지 않지만, 일반 클래스들은 상속에 상속을 거쳐서 여러 부모 클래스를 가질 수 있다. 하지만, enum 클래스는 무조건 java.lang.Enum이라는 클래스의 상속을 받는다.
즉, extends java.lang.Enum이라는 문장을 enum 클래스를 선언할 때 사용하지는 않지만, 컴파일러가 알아서 이 문장을 추가해서 컴파일한다.
==> 그렇기 때문에 enum을 선언하여 사용할 때 마음대로 extends 하면 안된다.
Enum이라는 모든 enum 클래스의 부모가 어떻게 되어 있는지 살펴보자.
Enum클래스의 생성자는 다음과 같이 선언되어 있다.
==>여기서 name은 enum 상수의 이름이다. ordinal은 enum의 순서이며, 상수가 선언된 순서대로 0부터 증가한다.
Enum 클래스의 부모 클래스는 Object 클래스이기 때문에, Object 클래스의 메소드들은 모두 사용할 수 있다. 하지만, Enum 클래스는 개발자들이 Object 클래스 중 4개의 메소드를 Overriding하지 못하도록 막아놓았다.
clone()과 finalize()메소드는 사용하면 안되지만, hashCode()와 equals()메소드는 사용가능하다.
Enum 클래스에 선언되어 있는 메소드들은 아래와 같다.
위의 메소드에서 compareTo() 메소드가 그나마 많이 사용된다.
compareTod() 메소드를 사용하는 예시를 보자.
[EX]
package part13;
public class OverTimeManager2 {
public static void main(String[] args) {
OverTimeValues2 values2 = OverTimeValues2.FIVE_HOUR;
System.out.println(values2);
System.out.println(values2.getAmount());
OverTimeValues2 values3 = OverTimeValues2.THREE_HOUR;
System.out.println(values2.compareTo(values3));
}
}
FIVE_HOUR
30000
1
==> Enum이 선언된 순서대로 각 상수들의 순서가 정해지는데 compareTo() 메소드는 이 순서가 같은지, 다른지를 비교하는데 사용된다. 만약 같은 상수라면 0,그렇지 않고 다르다면 순서의 차이를 출력한다. [매개변수로 넘기는 상수 기준으로 앞에 있으면 음수(-)를, 뒤에 있으면 양수(+)를 리턴한다.]
결과를 보게되면 1이 나왔다. 당연하다 왜냐하면 THREE_HOUR는 FIVE_HOUR 바로 앞에 선언되어 있기 때문이다.
즉, FIVE_HOUR는 THREE_HOUR 하나 뒤에 있으니 1을 결과로 출력한다.
그런데 필자가 어떻게 Enum 클래스에 있는 메소드들이 있는지 어떻게 알았을까?
==> 바로 API라는 문서에 이러한설명들이 다 나와있다.
enum 클래에스에는 API 문서에 없는 특수한 메소드가 하나 있다. 바로 values()라는 메소드다.
이 메소드를 호출하면 enum 클래스에 선언되어 있는 모든 상수를 배열로 리턴한다. 어떤 상수가 어떤 순서로 선언되었는지 확인하기 어려운 경우에 이 메소드를 사용하면 많은 도움이 될 것이다.
[EX]
package part13;
public class OverTimeManager3 {
public static void main(String[] args) {
OverTimeValues2 []valueList = OverTimeValues2.values();
for(OverTimeValues2 value:valueList) {
System.out.println(value);
}
}
}
THREE_HOUR
FIVE_HOUR
WEEKEND_FOUR_HOUR
WEEKEND_EIGHT_HOUR
◼️ 5. 인터페이스, abstract 클래스, enum 총 정리 ◼️
인터페이스와 abstract 클래스는 클래스의 골격을 잡아주고, 메소드를 선언해 놓을 때 매우 유용하게 사용할 수 있다.
인터페이스와 absract 클래스, 클래스의 차이점은 반드시 기억해야한다.
enum이라는 열거형 클래스는 이름대로 열거되어 있는 데이터나 상수를 처리할 때 사용하므로, 고정되어 있는 값을 처리할 때 많은 도움이 될 것이다.
'JAVA > 자바의신 1' 카테고리의 다른 글
15장 String (0) | 2022.09.10 |
---|---|
14장 다 배운 것 같지만, 예외라는 중요한 것이 있어요.(예외 처리 try-catch) (1) | 2022.09.09 |
12장 모든 클래스의 부모 클래스는 Object에요 (1) | 2022.09.08 |
11장 매번 만들기 귀찮은데 누가 만들어 놓은 거 쓸 수 없나요? (0) | 2022.09.08 |
10장 자바는 상속이라는 것이 있어요 (1) | 2022.09.07 |