ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JAVA] 자바 mid1 4 - 6 강 요약
    자바 2024. 12. 29. 17:41

    4. 래퍼, Class 클래스

    기본형의 한계

    자바는 객체 지향 언어이다 그런데 자바 안에 객체가 아닌 것이 있다

    바로 int, double 같은 기본형(Primitive Type)이다

     

    기본형은 객체가 아니기 때문에 다음과 같은 한계가 있다

    • 객체가 아님 : 기본형 데이터는 객체가 아니기 때문에, 객체 지향 프로그래밍의 장점을 살릴 수 없다 예를 들어 객 체는 유용한 메서드를 제공할 수 있는데, 기본형은 객체가 아니므로 메서드를 제공할 수 없다 추가로 객체 참조가 필요한 컬렉션 프레임워크를 사용할 수 없다. 그리고 제네릭도 사용할 수 없다
    • null 값을 가질 수 없음 : 기본형 데이터 타입은 null 값을 가질 수 없다 때로는 데이터가 없음이라는 상태를 나타내야 할 필요가 있는데, 기본형은 항상 값을 가지기 때문에 이런 표현을 할 수 없다

     

     

    래퍼 클래스 - 자바 래퍼 클래스

    래퍼 클래스란 특정 기본형을 감싸서(Wrap) 만드는 클래스이다

    래퍼 클래스는 기본형을 객체로 감싸서 더 편리하게 사용하도록 도와주기 때문에 상당히 유용하다

    쉽게 이야기해서 래퍼 클래스는 기본형의 객체 버전이다

     

     

    자바가 제공하는 기본 래퍼 클래스 특징

    • 불변이다
    • equals로 비교해야 한다

     

    래퍼 클래스 생성 - 박싱(Boxing)

    // 미래에 삭제 예정, 대신에 valueOf() 사용
    Integer newInteger = new Integer(10);
    // -128 ~ 127 자주 사용하는 숫자 값 (재사용, 불변)
    Integer integerObj = Integer.valueOf(10);

    기본형을 래퍼 클래스로 변경하는 것을 마치 박스에 물건을 넣은 것 같다고 해서 박싱(Boxing) 이라 한다

    자주 사용하는 -128 ~ 127 범위의 Integer 클래스를 미리 생성해준다

    해당 범위의 값을 조회하면 미리 생성된 Integer 객체를 반환한다 해당 범위의 값이 없으면 new Integer()를 호출한다

     

     

    intValue() - 언박싱(Unboxing)

    int intValue = integerObj.intValue();

    래퍼 클래스에 들어있는 기본형 값을 다시 꺼내는 메서드이다

    박스에 들어있는 물건을 꺼내는 것 같다고 해서 언박싱(Unboxing)이라 한다

     

     

    비교는 equals() 사용

    래퍼 클래스는 객체이기 때문에 == 비교를 하면 인스턴스의 참조값을 비교한다

    래퍼 클래스는 내부의 값을 비교하도록 equals()를 재정의 해두었다

    따라서 값을 비교하려면 equals() 사용

    참고로 래퍼 클래스는 객체를 그대로 출력해도 내부에 있는 값을 문자로 출력하도록 toString()을 재정의했다

     

     

    래퍼 클래스 - 오토 박싱

    오토 박싱 - Autoboxing

    오토 박싱과 오토 언박싱은 컴파일러가 개발자 대신 valueOf, xxxValue() 등의 코드를 추가해 주는 기능이다

    public class AutoboxingMain1 {
        public static void main(String[] args) {
            // Primitive -> Wrapper
            int value = 7;
            Integer boxedValue = Integer.valueOf(value);
            
            // 오토 박싱(Auto-boxing)
            Integer boxedValue = value;
        
            // Wrapper -> Primitive
            int unboxedValue = boxedValue.intValue();
            
            // 오토 언박싱(Auto-Unboxing)
            int unboxedValue = boxedValue; 
            
            System.out.println("boxedValue = " + boxedValue);
            System.out.println("unboxedValue = " + unboxedValue);
        }
    }
    • 박싱: valueOf()
    • 언박싱: xxxValue()

     

     

    래퍼 클래스 - 주요 메서드
    public class WrapperUtilsMain {
        public static void main(String[] args) {
            // 숫자, 래퍼 객체 반환
            Integer i1 = Integer.valueOf(10);
            // 문자열, 래퍼 객체 반환
            Integer i2 = Integer.valueOf("10");
            // 문자열 전용, 기본형 반환
            int intValue = Integer.parseInt("10");
            
            // 비교
            int compareResult = i1.compareTo(20);
            System.out.println("compareResult = " + compareResult);
            
            // 산술 연산
            System.out.println("sum: " + Integer.sum(10, 20));
            System.out.println("min: " + Integer.min(10, 20));
            System.out.println("max: " + Integer.max(10, 20));
        }
    }
    • valueOf() : 래퍼 타입을 반환하며 숫자, 문자열을 모두 지원
    • parseInt() : 문자열을 기본형으로 변환
    • compareTo() : 내 값과 인수로 넘어온 값을 비교한다 (내 값이 크면 1, 같으면 0, 작으면 -1 반환 )
    • Integer.sum(), Integer.min(), Integer. max() : static 메서드, 간단한 덧셈 등 값 연산 수행

     

     

    parseInt() vs valueOf()

    원하는 타입에 맞는 메서드를 사용하면 된다

    • valueOf("10")는 래퍼 타입 반환
    • parseInt("10")는 기본형 반환

     

     

    래퍼 클래스와 성능

    기본형은 메모리에서 단순히 그 크기만큼의 공간을 차지한다

    래퍼 클래스의 인스턴스는 내부에 필드로 가지고 있는 기본형의 값뿐만 아니라 자바에서 객체 자체를 다루는데 필요한 객체 메타데이터를 포함하므로 더 많은 메모리를 사용한다

    > 기본형 연산이 래퍼 클래스보다 빠르다

     

     

    기본형, 래퍼 클래스 어떤 것을 사용?

    기본형이든 래퍼 클래스든 이것을 1회로 환산하면 둘 다 매우 빠르게 연산이 수행된다

    일반적인 애플리케이션을 만드는 관점에서 보면 이런 부분을 최적화해도 사막의 모래알 하나 정도의 차이가 날 뿐이다

    일반적인 경우라면 코드를 유지보수하기 더 나은 것을 선택하면 된다

     

     

    Class 클래스

    Class 클래스는 클래스의 정보(메타데이터)를 다루는 데 사용된다. Class 클래스를 통해 개발자는 실행 중인 자바 애플리케이션 내에서 필요한 클래스의 속성과 메서드에 대한 정보를 조회하고 조작할 수 있다

     

     

    Class 클래스 주요 기능

    • 타입 정보 얻기 : 클래스의 이름, 슈퍼클래스, 인터페이스, 접근 제한자 등과 같은 정보를 조회할 수 있다
    • 리플렉션 : 클래스에 정의된 메서드, 필드, 생성자 등을 조회하고, 이들을 통해 객체 인스턴스를 생성하거나 메서드를 호출하는 등의 작업을 할 수 있다
    • 동적 로딩과 생성 : Class.forName() 메서드를 사용하여 클래스를 동적으로 로드하고, newInstance() 메서드를 통해 새로운 인스턴스를 생성할 수 있다
    • 애노테이션 처리 : 클래스에 적용된 애노테이션(annotation)을 조회하고 처리하는 기능을 제공한다

    예를 들어, String.class는 String 클래스에 대한 Class 객체를 나타내며, 이를 통해 String 클래스에 대한 메타데이터를 조회하거나 조작할 수 있다.

     

     

    public class ClassMetaMain {
        public static void main(String[] args) throws Exception {
        
            // Class 조회
            // 1.클래스에서 조회
            Class clazz = String.class;
            // 2.인스턴스에서 조회
            // Class clazz = new String().getClass();
            // 3.문자열로 조회
            // Class clazz = Class.forName("java.lang.String");
            
            // 모든 필드 출력
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                System.out.println("Field: " + field.getType() + " " +  
                field.getName());
            }
            
            // 모든 메서드 출력
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                System.out.println("Method: " + method);
            }
            
            // 상위 클래스 정보 출력
            System.out.println("Superclass: " + clazz.getSuperclass().getName());
    
            // 인터페이스 정보 출력
            Class[] interfaces = clazz.getInterfaces();
            for (Class i : interfaces) {
                System.out.println("Interface: " + i.getName());
            }
        }
    }

    Class 클래스의 주요 기능

    • getDeclaredFields() : 클래스의 모든 필드를 조회한다
    • getDeclaredMethods() : 클래스의 모든 메서드를 조회한다
    • getSuperclass() : 클래스의 부모 클래스를 조회한다
    • getInterfaces() : 클래스의 인터페이스들을 조회한다

     

     

    클래스 생성하기
    public class Hello {
        public String hello() {
            return "hello!";
        }
    }
    public class ClassCreateMain {
        public static void main(String[] args) throws Exception {
            // Class helloClass = Hello.class;
            Class helloClass = Class.forName("lang.clazz.Hello");
            Hello hello = (Hello) helloClass.getDeclaredConstructor().newInstance();
            String result = hello.hello();
            System.out.println("result = " + result);
        }
    }

    getDeclaredConstructor().newInstance()

    • getDeclaredConstructor() : 생성자를 선택
    • newInstance() : 선택된 생성자를 기반으로 인스턴스를 생성

     

     

    리플렉션 - reflection

    Class를 사용하면 클래스의 메타 정보를 기반으로 클래스에 정의된 메서드, 필드, 생성자 등을 조회하고, 이들을 통해 ` 객체 인스턴스를 생성하거나 메서드를 호출하는 작업을 할 수 있다 이런 작업을 리플렉션이라 한다 추가로 애노테이션 정보를 읽어서 특별한 기능을 수행할 수 도 있다

     

     

     

     

     

    5. 열거형 - ENUM

    열거형이 생겨난 이유

    [ 비즈니스 요구사항 ]

    고객은 3등급으로 나누고, 상품 구매 시 등급별로 할인을 적용한다 할인 시 소수점 이하는 버린다

    • BASIC -> 10% 할인
    • GOLD -> 20% 할인
    • DIAMOND -> 30% 할인

     

    EX1. 문자열을 입력하는 방식

    public class DiscountService {
        public int discount(String grade, int price) {
            int discountPercent = 0;
            
            if (grade.equals("BASIC")) {
                discountPercent = 10;
            } else if (grade.equals("GOLD")) {
                discountPercent = 20;
            } else if (grade.equals("DIAMOND")) {
                discountPercent = 30;
            } else {
                System.out.println(grade + ": 할인X");
            }
            return price * discountPercent / 100;
        }
    }
    public class StringGradeEx0_1 {
        public static void main(String[] args) {
            int price = 10000;
            
            DiscountService discountService = new DiscountService();
            int basic = discountService.discount("BASIC", price);
            int gold = discountService.discount("GOLD", price);
            int diamond = discountService.discount("DIAMOND", price);
            
            System.out.println("BASIC 등급의 할인 금액: " + basic);
            System.out.println("GOLD 등급의 할인 금액: " + gold);
            System.out.println("DIAMOND 등급의 할인 금액: " + diamond);
            
            // 존재하지 않는 등급
            int vip = discountService.discount("VIP", price);
            System.out.println("VIP 등급의 할인 금액: " + vip);
            
            // 오타
            int diamondd = discountService.discount("DIAMONDD", price);
            System.out.println("DIAMONDD 등급의 할인 금액: " + diamondd);
            
            // 소문자 입력
            int gold = discountService.discount("gold", price);
            System.out.println("gold 등급의 할인 금액: " + gold);
        }
    }
    • 타입 안정성 부족 : 문자열은 오타가 발생하기 쉽고, 유효하지 않은 값이 입력될 수 있다
    • 데이터 일관성 : "GOLD", "gold", "Gold" 등 다양한 형식으로 문자열을 입력할 수 있어 일관성이 떨어진다

     

    String 사용 시 타입 안정성 부족 문제

    • 값의 제한 부족 : String으로 상태나 카테고리를 표현하면, 잘못된 문자열을 실수로 입력할 가능성이 있다
    • 컴파일 시 오류 감지 불가 : 이러한 잘못된 값은 컴파일 시에는 감지되지 않고, 런타임에서만 문제가 발견되기 때문에 디버깅이 어려워질 수 있다

     

    EX2. 문자열 상수 사용하는 방식

    public class StringGrade {
        public static final String BASIC = "BASIC";
        public static final String GOLD = "GOLD";
        public static final String DIAMOND = "DIAMOND";
    }
    public class DiscountService {
        public int discount(String grade, int price) {
            int discountPercent = 0;
            if (grade.equals(StringGrade.BASIC)) {
                discountPercent = 10;
            } else if (grade.equals(StringGrade.GOLD)) {
                discountPercent = 20;
            } else if (grade.equals(StringGrade.DIAMOND)) {
                discountPercent = 30;
            } else {
                System.out.println(grade + ": 할인X");
            }
            
            return price * discountPercent / 100;
        }
    }
    public class StringGradeEx1_1 {
        public static void main(String[] args) {
            int price = 10000;
            
            DiscountService discountService = new DiscountService();
            int basic = discountService.discount(StringGrade.BASIC, price);
            int gold = discountService.discount(StringGrade.GOLD, price);
            int diamond = discountService.discount(StringGrade.DIAMOND, price);
            
            System.out.println("BASIC 등급의 할인 금액: " + basic);
            System.out.println("GOLD 등급의 할인 금액: " + gold);
            System.out.println("DIAMOND 등급의 할인 금액: " + diamond);
            
            // 존재하지 않는 등급
            int vip = discountService.discount("VIP", price);
            System.out.println("VIP 등급의 할인 금액: " + vip);
            
            // 오타
            int diamondd = discountService.discount("DIAMONDD", price);
            System.out.println("DIAMONDD 등급의 할인 금액: " + diamondd);
            
            // 소문자 입력
            int gold = discountService.discount("gold", price);
            System.out.println("gold 등급의 할인 금액: " + gold);
        }
    }

    문자열 상수를 사용해도, 지금까지 발생한 문제들을 근본적으로 해결할 수는 없다

    왜냐하면 어떤 문자열이든 입력할 수 있기 때문이다

    어떤 개발자가 실수로 StringGrade에 있는 문자열 상수를 사용하지 않고, 다음과 같이 직접 문자열을 사용해도 막을 수 있는 방법이 없다

     

     

    EX3. 타입 안전 열거형 패턴 - Type-Safe Enum Pattern

    enum은 enumeration의 줄임말인데 열거라는 뜻이고 어떤 항목을 나열하는 것을 뜻한다

    중요한 것은 타입 안전 열거형 패턴을 사용하면 이렇게 나열한 항목만 사용할 수 있다는 것이 핵심이다

    public class ClassGrade {
        public static final ClassGrade BASIC = new ClassGrade();
        public static final ClassGrade GOLD = new ClassGrade();
        public static final ClassGrade DIAMOND = new ClassGrade();
    }
    • 먼저 회원 등급을 다루는 클래스를 만들고, 각각의 회원 등급별로 상수를 선언한다
    • 이때 각각의 상수마다 별도의 인스턴스를 생성하고, 생성한 인스턴스를 대입한다
    • 각각을 상수로 선언하기 위해 static(상수를 메서드 영역에 선언), final(참조값을 변경할 수 없음)을 사용한다

     

    public class DiscountService {
        public int discount(ClassGrade classGrade, int price) {
            int discountPercent = 0;
            if (classGrade == ClassGrade.BASIC) {
                discountPercent = 10;
            } else if (classGrade == ClassGrade.GOLD) {
                discountPercent = 20;
            } else if (classGrade == ClassGrade.DIAMOND) {
                discountPercent = 30;
            } else {
                System.out.println("할인X");
            }
            
            return price * discountPercent / 100;
        }
    }
    public class ClassGradeEx2_1 {
        public static void main(String[] args) {
            int price = 10000;
            
            DiscountService discountService = new DiscountService();
            int basic = discountService.discount(ClassGrade.BASIC, price);
            int gold = discountService.discount(ClassGrade.GOLD, price);
            int diamond = discountService.discount(ClassGrade.DIAMOND, price);
     
            System.out.println("BASIC 등급의 할인 금액: " + basic);
            System.out.println("GOLD 등급의 할인 금액: " + gold);
            System.out.println("DIAMOND 등급의 할인 금액: " + diamond);
            
            //  외부에서 임의로 ClassGrade의 인스턴스를 생성할 수 있다는 문제 발생
            ClassGrade newClassGrade = new ClassGrade();
            int result = discountService.discount(newClassGrade, price);
            System.out.println("newClassGrade 등급의 할인 금액: " + result);
        }
    }

    외부에서 임의로 ClassGrade의 인스턴스를 생성할 수 있다는 문제 발생

    > 외부에서 ClassGrade 생성할 수 없도록 막아야한다

    > 기본 생성자를 private으로 변경

     

     

    public class ClassGrade {
        public static final ClassGrade BASIC = new ClassGrade();
        public static final ClassGrade GOLD = new ClassGrade();
        public static final ClassGrade DIAMOND = new ClassGrade();
        
        // private 생성자 추가
        private ClassGrade() {}
    }

    private 생성자 덕분에 ClassGrade의 인스턴스를 생성하는 것은 ClassGrade 클래스 내부에서만 할 수 있다

    ClassGrade 인스턴스를 사용할 때는 ClassGrade 내부에 정의한 상수를 사용해야 한다

    그렇지 않은 면 컴파일 오류가 발생한다

     

     

    타입 안전 열거형 패턴"(Type-Safe Enum Pattern)의 장점

    • 타입 안정성 향상 : 정해진 객체만 사용할 수 있기 때문에, 잘못된 값을 입력하는 문제를 근본적으로 방지할 수 있다
    • 타입 안전성 : 이 패턴을 사용하면, 잘못된 값이 할당되거나 사용되는 것을 컴파일 시점에 방지할 수 있다 예를 들어, 특정 메서드가 특정 열거형 타입의 값을 요구한다면, 오직 그 타입의 인스턴스만 전달할 수 있다
    • 제한된 인스턴스 생성 : 클래스는 사전에 정의된 몇 개의 인스턴스만 생성하고, 외부에서는 이 인스턴스들만 사용할 수 있도록 한다 이를 통해 미리 정의된 값들만 사용하도록 보장한다
    • 데이터 일관성 : 정해진 객체만 사용하므로 데이터의 일관성이 보장된다

     

     

    열거형 - Enum Type

    자바는 타입 안전 열거형 패턴(Type-Safe Enum Pattern)을 매우 편리하게 사용할 수 있는 열거형(Enum Type)을 제공한다

    Enumeration은 일련의 명명된 상수들의 집합을 정의하는 것을 의미하며, 프로그래밍에서는 이러한 상수들을 사용하여 코드 내에서 미리 정의된 값들의 집합을 나타낸다

    자바의 enum은 타입 안전성을 제공하고, 코드의 가독성을 높이며, 예상 가능한 값들의 집합을 표현하는 데 사용된다

     

    public enum Grade {
        BASIC, GOLD, DIAMOND
    }
    public class EnumRefMain {
        public static void main(String[] args) {
            System.out.println("class BASIC = " + Grade.BASIC.getClass());
            System.out.println("class GOLD = " + Grade.GOLD.getClass());
            System.out.println("class DIAMOND = " + Grade.DIAMOND.getClass());
            
            // class BASIC = class enumeration.ex3.Grade
            // lass GOLD = class enumeration.ex3.Grade
            // class DIAMOND = class enumeration.ex3.Grade
    
            System.out.println("ref BASIC = " + refValue(Grade.BASIC));
            System.out.println("ref GOLD = " + refValue(Grade.GOLD));
            System.out.println("ref DIAMOND = " + refValue(Grade.DIAMOND));
            
            // ref BASIC = x001
            // ref GOLD = x002
            // ref DIAMOND = x003
        }
        
        private static String refValue(Object grade) {
            return Integer.toHexString(System.identityHashCode(grade));
        }
    }
    • 실행 결과를 보면 상수들이 열거형으로 선언한 타입인 Grade 타입을 사용하는 것을 확인할 수 있다 그리고 각각의 인스턴스도 서로 다른 것을 확인할 수 있다
    • 열거형도 클래스이다 열거형을 제공하기 위해 제약이 추가된 클래스라 생각하면 된다

     

    public class DiscountService {
        public int discount(Grade grade, int price) {
            int discountPercent = 0;
            // enum switch 변경 가능
            if (grade == Grade.BASIC) {
                discountPercent = 10;
            } else if (grade == Grade.GOLD) {
                discountPercent = 20;
            } else if (grade == Grade.DIAMOND) {
                discountPercent = 30;
            } else { 
                System.out.println("할인X");
            }
    
            return price * discountPercent / 100;
        }
    }
    public class EnumEx3_1 {
        public static void main(String[] args) {
            int price = 10000;
            
            DiscountService discountService = new DiscountService();
            int basic = discountService.discount(Grade.BASIC, price);
            int gold = discountService.discount(Grade.GOLD, price);
            int diamond = discountService.discount(Grade.DIAMOND, price);
     
            System.out.println("BASIC 등급의 할인 금액: " + basic);
            System.out.println("GOLD 등급의 할인 금액: " + gold);
            System.out.println("DIAMOND 등급의 할인 금액: " + diamond);
        }
    }
    • 열거형의 사용법이 앞서 타입 안전 열거형 패턴을 직접 구현한 코드와 같은 것을 확인할 수 있다
    • 참고로 열거형은 switch 문에 사용할 수 있는 장점도 있다

     

    열거형(ENUM)의 장점

    • 타입 안정성 향상 : 열거형은 사전에 정의된 상수들로만 구성되므로, 유효하지 않은 값이 입력될 가능성이 없다. 이런 경우 컴파일 오류가 발생한다
    • 간결성 및 일관성 : 열거형을 사용하면 코드가 더 간결하고 명확해지며, 데이터의 일관성이 보장된다
    • 확장성 : 새로운 회원 등급을 타입을 추가하고 싶을 때, ENUM에 새로운 상수를 추가하기만 하면 된다
    • 열거형을 사용하는 경우 static import를 적절하게 사용하면 더 읽기 좋은 코드를 만들 수 있다 

     

     

    ENUM - 주요 메서드
    • values() : 모든 ENUM 상수를 포함하는 배열을 반환한다
    • valueOf(String name) : 주어진 이름과 일치하는 ENUM 상수를 반환한다
    • name() : ENUM 상수의 이름을 문자열로 반환한다
    • ordinal() : ENUM 상수의 선언 순서(0부터 시작)를 반환한다 ( 가급적 사용하지 않는 것이 좋다)
    • toString() : ENUM 상수의 이름을 문자열로 반환한다 name() 메서드와 유사하지만, toString()은 직접 오버라이드 할 수 있다

     

     

    열거형 정리

    • 열거형은 java.lang.Enum를 자동(강제)으로 상속받는다
    • 열거형은 이미 java.lang.Enum을 상속받았기 때문에 추가로 다른 클래스를 상속을 받을 수 없다
    • 열거형은 인터페이스를 구현할 수 있다
    • 열거형에 추상 메서드를 선언하고, 구현할 수 있다

     

    열거형 - 리팩토링 1
    public class ClassGrade {
        public static final ClassGrade BASIC = new ClassGrade(10);
        public static final ClassGrade GOLD = new ClassGrade(20);
        public static final ClassGrade DIAMOND = new ClassGrade(30);
        private final int discountPercent;
        
        private ClassGrade(int discountPercent) {
            this.discountPercent = discountPercent;
        }
        
        public int getDiscountPercent() {
            return discountPercent;
        }
    }
    • 할인율 필드 추가
    • 생성자를 통해서만 discountPercent 설정 가능하며 불변으로 설계
    public class DiscountService {
        public int discount(ClassGrade classGrade, int price) {
            return price * classGrade.getDiscountPercent() / 100;
        }
    }
    public class ClassGradeRefMain1 {
        public static void main(String[] args) {
            DiscountService discountService = new DiscountService();
            int basic = discountService.discount(ClassGrade.BASIC, price);
            int gold = discountService.discount(ClassGrade.GOLD, price);
            int diamond = discountService.discount(ClassGrade.DIAMOND, price);
            System.out.println("BASIC 등급의 할인 금액: " + basic);
            System.out.println("GOLD 등급의 할인 금액: " + gold);
            System.out.println("DIAMOND 등급의 할인 금액: " + diamond);
        }
    }

     

     

    열거형 - 리팩토링 2
    public enum Grade {
        BASIC(10), GOLD(20), DIAMOND(30);
        
        private final int discountPercent;
    
        Grade(int discountPercent) {
            this.discountPercent = discountPercent;
        }
        
        public int getDiscountPercent() {
            return discountPercent;
        }
    }
    • discountPercent 필드를 추가하고, 생성자를 통해서 필드에 값을 저장한다
    • 열거형은 상수로 지정하는 것 외에 일반적인 방법으로 생성이 불가능
    public class DiscountService {
        public int discount(Grade grade, int price) {
            return price * grade.getDiscountPercent() / 100;
        }
    }
    public class EnumRefMain2 {
        public static void main(String[] args) {
            int price = 10000;
            DiscountService discountService = new DiscountService();
            int basic = discountService.discount(Grade.BASIC, price);
            int gold = discountService.discount(Grade.GOLD, price);
            int diamond = discountService.discount(Grade.DIAMOND, price);
            System.out.println("BASIC 등급의 할인 금액: " + basic);
            System.out.println("GOLD 등급의 할인 금액: " + gold);
            System.out.println("DIAMOND 등급의 할인 금액: " + diamond);
        }
    }

     

     

    열거형 - 리팩토링 3
    public enum Grade {
        BASIC(10), GOLD(20), DIAMOND(30);
        private final int discountPercent;
        
        Grade(int discountPercent) {
            this.discountPercent = discountPercent;
        }
        
        public int getDiscountPercent() {
            return discountPercent;
        }
        
        //추가
        public int discount(int price) {
            return price * discountPercent / 100;
        }
    }
    • Grade 내부에 discount() 메서드 추가
    public class DiscountService {
        public int discount(Grade grade, int price) {
            return grade.discount(price);
        }
    }
    • 할인율 계산은 이제 Grade가 스스로 처리 > 제거 가능
    public class EnumRefMain3_1 {
        public static void main(String[] args) {
            int price = 10000;
            Grade[] grades = Grade.values();
            for (Grade grade : grades) {
                 printDiscount(grade, price);
            }
        }
        
        private static void printDiscount(Grade grade, int price) {
            System.out.println(grade.name() + " 등급의 할인 금액: " + grade.discount(price));
        }
    }

     

     

     

     

     

     

    6. 날짜와 시간

    - 필요할 때 찾아보기

     

     

     

     


    김영한의 실전자바 -중급 1편 ( 4 강 - 6 강)

    728x90
Designed by Tistory.