An enum type is a special data type that enables for a variable to be a set of predefined constants. enum type은 미리 정의된 상수의 집합이 될 수 있도록 하는 특별한 데이터 타입이다.
The variable must be equal to one of the values that have been predefined for it. 변수는 미리 정의된 값 중 하나와 같아야 합니다.
Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week. 일반적인 예로는 나침반 방향(NORTH, SOUTH, EAST 및 WEST 값)과 요일이 포함됩니다.
enum Color {
RED(3),
YELLOW(4),
BLUE(5);
private final int value;
Color(int value) { this.value = value; }
public int getValue() { return value; }
}
System.out.println(Color.RED.name()); // RED
System.out.println(Color.RED.value()); // 3
1. 자바에서 상수 정의하기:: static final
상수를 정의하는 방법에는 enum이 나타나기 전에 static final을 사용하는 방법이 있었다.
static final을 사용하는 방법 예시는 다음과 같다.
예시 상황으로 사용자는 1에서 100사이의 값만 입력할 수 있는 프로그램이 있다고 하자. 여기서 1과 100을 상수로 선언할 것이다. static final을 활용한 코드는 아래와 같다.
public class Application {
private static final int MIN_SIZE = 1;
private static final int MAX_SIZE = 100;
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
int userInput = parseInt(in.readLine());
if(userInput >= MIN_SIZE
&& userInput <= MAX_SIZE) {
System.out.println("good");
}
}
}
이러한 static final 이 존재하였는데 왜 enum 이라는 열거형이 나왔을까?
Why created the enum?
final static으로 상수를 선언하는 경우 상수 이름과 상수 값 자체는 관련이 없게된다.
이름의 충돌이 발생할 수 있다.
다음 예시를 통해 배경을 더 정확히 이해해보자!
final static으로 상수를 선언하는 경우 상수 이름과 상수 값 자체는 관련이 없게된다.
public class Application {
private static final String SPRING = "봄";
private static final String SUMMER = "여름";
private static final String AUTUMN = "가을";
private static final String WINTER = "겨을";
public static void main(String[] args) {
System.out.println(SPRING); // 봄
System.out.println(SUMMER); // 여름
System.out.println(AUTUMN); // 가을
System.out.println(WINTER); // 겨울
String season = "봄";
if (season == SPRING) {
System.out.printf("season is %s", SPRING); // season is 봄
}
}
}
이름의 충돌이 발생할 수 있다.
public class Framework {
public static final int SPRING = 1;
public static final int VUE = 2;
public static final int NESTJS = 3;
}
public class Season {
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int AUTUMN = 3;
public static final int WINTER = 4;
}
// Season.SPRING Framework.SPRING 충돌
Advantages of using Enum instead of static final
코드가 단순해지고, 가독성이 좋아진다.
인스턴스 생성과 상속을 방지한다.
enum 키워드 사용을 통해서 구현 의도가 열거형임을 분명하게 나타낼 수 있다.
static final 사용
private static final String SPRING = "봄";
private static final String SUMMER = "여름";
private static final String AUTUMN = "가을";
private static final String WINTER = "겨을";
enum 사용
public enum Season {
SPRING("봄"),
SUMMER("여름"),
AUTUMN("가을"),
WINTER("겨울");
private final String value;
Seson(String value) { this.value = value; }
public String getValue() {
return value;
}
}
final static 을 사용하여 선언한 상수보다 enum 을 사용한 상수 선언이 가독성 면에서 더 좋다.
자바에서 Get/Set Method를 굳이 일반 메소드와 구분하여 사용하는 이유가 무엇일까?
Why use Getter/Setter Method in JAVA?
자바는 대표적인 객체지향프로그래밍 언어이다.
객체지향프로그래밍에서는 객체의 데이터에 객체 외부가 직접적은로 접근하는 것을 막는다. (캡슐화)
외부에서 객체의 데이터를 직접적으로 읽고 변경하게 된다면 객체 무결성이 깨질 수 있기 때문이다.
자바에서는 이렇게 "민감한 데이터를 사용자에게서 숨기도록" 캡슐화를 위하여 멤버변수를 private으로 선언하여 get/set method를 통해서 멤버변수에 접근할 수 있도록 한다.
즉, 캡슐화를 위해서 get/set을 사용한다.
캡슐화 예시
사람 객체가 있다고 가정하자.
사람은 모두 이름과 나이, 성별, 생년월일, 주민등록번호를 가진다.
간단하게 예시만 들 것이기 때문에 이름과 주민번호를 멤버변수로 갖는 객체를 선언할 것이다.
이를 객체로 표현하면 다음과 같다.
class Person {
public String name; // 이름
public String personId; // 주민번호
}
여기서 접근제어자를 모두 public으로 선언하였는데, 주민번호는 개인정보이기 때문에 private으로 선언해줘야 알맞다. 이를 수정해준다.
class Person {
public String name;
private String personId;
}
이제 우리가 사람의 주민번호를 알고 싶을때 Person.personId로 접근할 수 없게 되었다. 특정 사람의 주민번호를 알기 위한 get method와 주민등록을 변경할 경우를 대비해 set method를 같이 선언해준다.
class Person {
public String name;
private String personId;
public String getPersonId() {
return this.personId;
}
public void setPersonId(String newPersonId) {
Pattern id = Pattern.compile("/^\d{2}[0-1]\d{1}[0-3]\d{1}\-[1-4]\d{6}$/");
if (id.matcher(newPersonId).matches()) {
this.personId = newPersonId;
}
}
}
이렇게 get/set 메소드를 활용하면 외부로부터 값을 보호하고, set 메소드를 통해서 수정하고자 하는 값이 올바른 값이 맞는지 확인하는 과정을 거칠 수 있다.
생성자는 클래스로부터 객체를 생성할 때 자동으로 호출되는 메소드를 말한다. 객체의 멤버 변수 초기화를 담당하는 특수한 목적의 메소드이다.
생성자의 개념과 특징
메소드 이름이 클래스 이름과 동일하다.
리턴 타입이 없으며, void조차 허용하지 않는다.
객체 생성 시 자동으로 호출되며, 일반 메소드처럼 참조 변수를 통해 호출할 수 없다.
생성되는 객체의 멤버 변수 초기화를 담당한다.
생성자가 하나도 정의되지 않은 클래스에는 기본 생성자가 자동으로 제공된다.
하나의 클래스에 여러 개의 생성자를 오버로딩 할 수 있다.
this() 형태의 특수한 생성자가 있다.
기본 생성자
기본 생성자는 매개변수가 없는 생성자를 의미한다.
생성자의 가장 중요한 기능이 멤버 변수의 초기화인데, 기본 생성자는 매개변수를 가질 수 없기 때문에 멤버 변수를 기본값으로 초기화한다.
그래서 기본 생성자라는 이름을 갖게 된 것이다.
기본 생성자의 또 다른 특징으로는 클래스에 생성자가 하나도 없을 때 기본으로 제공된다는 것이다. 따라서 다음 두 클래스는 동일한 코드라고 볼 수 있다.
public class Student {
String name;
int score;
}
public class Student {
String name;
int score;
Student() {}
}
생성자를 통해서 객체의 멤버변수를 초기화 하기
// 1. 클래스 선언부
public class Student {
public String name;
public int score;
public boolean isPassed;
public String major;
public Student() {}
public Student(String stdName, int stdScore, boolean stdIsPassed, String stdMajor) {
name = stdName;
score = stdScore;
isPassed = stdIsPassed;
major = stdMajor;
}
public void printInfo() {
System.out.println(name + "의 전공 : " + major + " 점수 : " + score + " 시험 통과 여부 : " + isPassed);
}
}
public Student() {} 는 기본생성자이고, 그 아래에 매개변수를 가지고 있는 public Student( ... ) {} 는 멤버변수 값을 초기화 해주는 오버로딩된 생성자이다.
기본 생성자로 객체를 선언하게 되면 멤버변수값들이 아래와 같이 기본값으로 초기화가 된다. int type의 score 는 0, boolean 타입의 isPassed는 false, 참조 변수 타입인 name, major는 null 값을 갖게 된다.
public class Main {
public static void main(String[] args) {
Student millpre = new Student();
millpre.printInfo();
}
}
아래와 같이 매개변수를 넣어 선언하게 되면 매개변수에 맞게 멤버변수 값들이 초기화 되는 것을 확인할 수 있다.
public class Main {
public static void main(String[] args) {
Student millpre = new Student("millpre", 90, true, "cs");
millpre.printInfo();
}
}
this() 생성자
생성자의 이름은 반드시 클래스의 이름과 동일해야 한다. 그런데 생성자 중에 클래스의 이름을 사용하지 않는 this() 라는 독특한 생성자가 존재한다.
this() 생성자를 이용하면 같은 클래스에 있는 다른 생성자를 호출할 수 있다. 이를 통해 생성자 내의 코드 중복을 제거할 수 있다.
코드를 보면 바로 이해할 수 있을 것이다.
// 1. 클래스 선언부
public class Student {
public String name;
public int score;
public boolean isPassed;
public String major;
public Student() {}
public Student (String stdName, int stdScore) {
name = stdName;
score = stdScore;
}
public Student(String stdName, int stdScore, boolean stdIsPassed, String stdMajor) {
this(stdName, stdScore);
isPassed = stdIsPassed;
major = stdMajor;
}
public void printInfo() {
System.out.println(name + "의 전공 : " + major + " 점수 : " + score + " 시험 통과 여부 : " + isPassed);
}
}