@Override 애너테이션은 메서드가 부모 클래스나 인터페이스의 메서드를 재정의하고 있는지를 컴파일러에게 알려주는 역할을 한다. 이를 통해 재정의한 메서드의 오타나 잘못된 시그니처 등을 빠르게 찾을 수 있습니다.

 

상위 클래스의 메서드를 재정의하려는 모든 메서드에 @Override 애너테이션을 달아주자.

@Override 애너테이션을 코드를 깔끔하게 보기위해 생략하지 말고 모두 달아주자.

 

 

핵심 정리 : 재정의한 모든 메서드에 @Override 애너테이션을 의식적으로 달면 여러분이 실수했을 때 컴파일러가 바로 알려줄 것이다. 예외는 한 가지 뿐이다. 구체 클래스에서 상위 클래스의 추상 메서드를 재정의한 경우엔 이 애너테이션을 달지 않아도 된다(단다고 해서 해로울 것도 없다).

명명 패턴 : 변수, 메서드, 클래스 등의 이름을 일정한 패턴에 따라 지정하는 방법. 이는 주로 코드의 가독성을 높이고 일관성을 유지하기 위해 사용된다.

예를 들어, 다음과 같은 명명 패턴이 있을 수 있습니다:

  1. 변수 이름에는 camelCase를 사용: myVariable, totalAmount, userName 등
  2. 메서드 이름에는 동사로 시작하여 동작을 나타냄: calculateTotal(), getUserInfo(), sendMessage()
  3. 클래스 이름은 대문자로 시작하는 CamelCase를 사용: MyClass, UserInfo, HttpRequest 등

 

import java.lang.annotation.*;

// 애너테이션 정의
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Test {
    // 기본값을 설정하여 필수적으로 값을 지정할 필요가 없도록 함
    String value() default "";
}

public class MyClass {
    // 애너테이션을 사용하여 테스트 메서드로 지정
    @Test("This is a test method")
    public void testMethod() {
        // 테스트 로직
    }

    // 테스트 메서드가 아닌 경우
    public void normalMethod() {
        // 일반 메서드 로직
    }

    // 애너테이션이 없는 경우
    public void anotherMethod() {
        // 다른 메서드 로직
    }
}

 

핵심 정리 : 애너테이션으로 할 수 있는 일을 명명 패턴으로 처리할 이유는 없다.

https://www.acmicpc.net/problem/1436

 

1436번: 영화감독 숌

666은 종말을 나타내는 수라고 한다. 따라서, 많은 블록버스터 영화에서는 666이 들어간 제목을 많이 사용한다. 영화감독 숌은 세상의 종말 이라는 시리즈 영화의 감독이다. 조지 루카스는 스타워

www.acmicpc.net

 

 

[정답 코드]

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int N = Integer.parseInt(br.readLine());

        int count = 1;
        int number = 666;
        while (count != N) {
            number++;
            if (String.valueOf(number).contains("666")) {
                count++;
            }
        }
        System.out.println(number);
    }
}

 

[알고리즘]

- 부르트 포스

 

[풀이]

처음엔 생각보다 어려워보여서 실버 5 문제가 맞나? 라고 의심했었다. 알고보니 정말 부르트하게 풀었더니 정답이였다.

1. 666부터 1씩 증가시키며 숫자에 666이 포함됬을 경우 count를 1 증가시킨다.

2. count가 N이 됬을 경우 number를 출력한다

'코딩테스트' 카테고리의 다른 글

백준 1476: 날짜 계산[JAVA]  (0) 2024.04.09
백준 1543: 문서 검색[JAVA]  (0) 2024.04.09
백준 1251: 단어 나누기[JAVA]  (0) 2024.04.09
백준 4179: 불![JAVA]  (0) 2024.04.04
백준 2110번: 공유기 설치[JAVA]  (1) 2024.04.04

https://www.acmicpc.net/problem/1251

 

1251번: 단어 나누기

알파벳 소문자로 이루어진 단어를 가지고 아래와 같은 과정을 해 보려고 한다. 먼저 단어에서 임의의 두 부분을 골라서 단어를 쪼갠다. 즉, 주어진 단어를 세 개의 더 작은 단어로 나누는 것이다

www.acmicpc.net

 

 

[정답 코드]

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        String input = br.readLine();

        String left = "";
        String mid = "";
        String right = "";

        ArrayList<String> list = new ArrayList<>();

        for (int i = 1; i < input.length() - 1; i++) {
            left = input.substring(0, i);
            for (int j = i + 1; j < input.length(); j++) {
                String tmp = new String();
                mid = input.substring(i, j);
                right = input.substring(j);
                tmp += backward(left);
                tmp += backward(mid);
                tmp += backward(right);
                list.add(tmp);
            }
        }
        Collections.sort(list);
        System.out.println(list.get(0));
    }
    static String backward(String word) {
        String tmp = "";
        for (int i = word.length() - 1; i >= 0; i--) {
            tmp += word.charAt(i);
        }
        return tmp;
    }
}

 

[알고리즘]

- 부르트포스 알고리즘

- 문자열

 

[풀이]

1. 이중 for문을 돌며 String.substring()을 활용해 left, mid, right의 3단어로 나눈다.

2. 문자열을 거꾸로 치환시키는 메서드 backward로 만들어 새 문자열을 만든다.

3. 새로 만든 문자열을 ArrayList에 추가한다.

4. Collections.sort() 메서드를 활용해 사전순으로 정렬한다.

5. list의 맨 앞 문자열을 출력한다.

 

이 방법이외에도 StringBuilder 를 활용하면 Stringbuilder에 자체적으로 문자열을 뒤집는 Stringbuilder.reverse()를 활용하면 더 간단하게 풀 수 있다.

'코딩테스트' 카테고리의 다른 글

백준 1543: 문서 검색[JAVA]  (0) 2024.04.09
백준 1436: 영화감독 숌[JAVA]  (0) 2024.04.09
백준 4179: 불![JAVA]  (0) 2024.04.04
백준 2110번: 공유기 설치[JAVA]  (1) 2024.04.04
백준 1987번: 알파벳[JAVA]  (1) 2024.04.03

// 확장 가능한 열거 타입을 위한 인터페이스
interface Animal {
    void sound();
}

// 기본 열거 타입 구현
enum DefaultAnimal implements Animal {
    DOG {
        @Override
        public void sound() {
            System.out.println("Woof");
        }
    },
    CAT {
        @Override
        public void sound() {
            System.out.println("Meow");
        }
    },
    BIRD {
        @Override
        public void sound() {
            System.out.println("Tweet");
        }
    }
}

// 새로운 열거 타입을 추가하기 위해 Animal을 구현하는 열거 타입 정의
enum CustomAnimal implements Animal {
    LION {
        @Override
        public void sound() {
            System.out.println("Roar");
        }
    },
    ELEPHANT {
        @Override
        public void sound() {
            System.out.println("Trumpet");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // 기본 열거 타입 사용
        DefaultAnimal.DOG.sound();  // 출력: Woof
        DefaultAnimal.CAT.sound();  // 출력: Meow

        // 새로운 열거 타입 사용
        CustomAnimal.LION.sound();  // 출력: Roar
        CustomAnimal.ELEPHANT.sound();  // 출력: Trumpet
    }
}

 

이 예시 코드에서는 Animal 인터페이스를 정의하여 열거 타입이 구현하도록 하였다. 그리고 DefaultAnimal이라는 기본 열거 타입과 CustomAnimal이라는 새로운 열거 타입을 정의하고 각각의 상수에 대해 다른 동작을 구현하였다. 클라이언트는 Animal 인터페이스를 사용하여 두 열거 타입의 인스턴스를 다룰 수 있다.

 

 

핵심 정리 : 열거 타입 자체는 확장할 수 없지만, 인터페이스와 그 인터페이스를 구현하는 기본 열거타입을 함께 사용해 같은 효과를 낼 수 있다. 이렇게 하면 클라이언트는 이 인터페이스를 구현해 자신만의 열거 타입(혹은 다른 타입)을 만들 수 있다. 그리고 API가 (기본 열거 타입을 직접 명시하지 않고) 인터페이스 기반으로 작성되었다면 기본 열거 타입의 인스턴스가 쓰이는 모든 곳을 새로 확장한 열거 타입의 인스턴스를 대체해 사용

ordinal 인덱싱 : 열거형 상수가 선언된 순서에 따라 숫자를 매기는 것을 말한다. 열거형의 첫 번째 상수는 0부터 시작하여 상수가 선언된 순서대로 1씩 증가하는 값을 가지게 된다.

 

EnumMap : 열거형을 키로 사용하는 맵이다. 이 맵은 열거형의 모든 상수를 키로 사용할 수 있으며, 각 상수에 대한 값에 접근하기 위해 배열을 사용한다. 열거형을 키로 사용하기 때문에 EnumMap은 해시 테이블 대신 배열을 사용하여 효율적으로 구현된다.

 

배열의 인덱스를 얻기위해 EnumMap을 사용한 예시 코드 : 

import java.util.EnumMap;

// 예시 Enum 타입
enum Weekday {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
}

public class Main {
    public static void main(String[] args) {
        // EnumMap 생성
        EnumMap<Weekday, Integer> indexMap = new EnumMap<>(Weekday.class);

        // 각 Enum 상수에 대한 인덱스 할당
        indexMap.put(Weekday.MONDAY, 0);
        indexMap.put(Weekday.TUESDAY, 1);
        indexMap.put(Weekday.WEDNESDAY, 2);
        indexMap.put(Weekday.THURSDAY, 3);
        indexMap.put(Weekday.FRIDAY, 4);

        // 각 Enum 상수에 대한 인덱스 조회
        System.out.println("Index of MONDAY: " + indexMap.get(Weekday.MONDAY));
        System.out.println("Index of TUESDAY: " + indexMap.get(Weekday.TUESDAY));
        System.out.println("Index of WEDNESDAY: " + indexMap.get(Weekday.WEDNESDAY));
        System.out.println("Index of THURSDAY: " + indexMap.get(Weekday.THURSDAY));
        System.out.println("Index of FRIDAY: " + indexMap.get(Weekday.FRIDAY));
    }
}

 

다차원 관계를 표현한 예시 코드 : 

import java.util.EnumMap;

// 요일 Enum 타입
enum Weekday {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY
}

// 시간대 Enum 타입
enum TimeOfDay {
    MORNING, AFTERNOON, EVENING, NIGHT
}

public class Main {
    public static void main(String[] args) {
        // 다차원 관계를 표현하기 위해 EnumMap<Weekday, EnumMap<TimeOfDay, String>> 사용
        EnumMap<Weekday, EnumMap<TimeOfDay, String>> schedule = new EnumMap<>(Weekday.class);

        // 각 요일과 시간대에 해당하는 일정 추가
        schedule.put(Weekday.MONDAY, new EnumMap<>(TimeOfDay.class));
        schedule.get(Weekday.MONDAY).put(TimeOfDay.MORNING, "Meeting");
        schedule.get(Weekday.MONDAY).put(TimeOfDay.AFTERNOON, "Workout");

        schedule.put(Weekday.TUESDAY, new EnumMap<>(TimeOfDay.class));
        schedule.get(Weekday.TUESDAY).put(TimeOfDay.MORNING, "Gym");
        schedule.get(Weekday.TUESDAY).put(TimeOfDay.AFTERNOON, "Study");

        // 일정 조회 예시
        String mondayMorningSchedule = schedule.get(Weekday.MONDAY).get(TimeOfDay.MORNING);
        System.out.println("Monday morning schedule: " + mondayMorningSchedule);
    }
}

 

핵심정리 : 배열의 인덱스를 얻기 위해 ordinal을 쓰는 것은 일반적으로 좋지 않으니, 대신 EnumMap을 사용하라.

다차원 관계는 EnumMap<..., EnumMap<...>>으로 표현하라. ("애플리케이션 프로그래머는 Enum.ordinal을 사용하지 말아야한다" 는 일반 원칙의 특수한 사례다.)

 

비트 필드 : 정수 상수의 집합을 표현하는 방법 중 하나로, 각 비트를 특정 상수에 대응시키는 방식. 하지만 비트 필드는 가독성이 낮고, 오류가 발생하기 쉽다.

 

public class FontExample {
    // 글꼴 종류를 비트 필드로 표현
    public static final int PLAIN    = 1 << 0;  // 0001
    public static final int BOLD     = 1 << 1;  // 0010
    public static final int ITALIC   = 1 << 2;  // 0100
    public static final int UNDERLINE= 1 << 3;  // 1000

    // 비트 필드로 표현된 글꼴 스타일 설정 메서드
    public void setStyle(int style) {
        // 스타일 설정
    }

    // 비트 필드로 표현된 글꼴 스타일 반환 메서드
    public int getStyle() {
        // 스타일 반환
        return 0;
    }
}

 

EnumSet : 열거형(Enum)을 기반으로 하는 집합(Set) 구현체 중 하나. 이 클래스는 열거 상수(Enum 상수) 집합을 효율적으로 저장하고 다룰 수 있도록 최적화되어 있다.

import java.util.EnumSet;

public class FontExample {
    // 글꼴 종류를 열거형으로 정의
    public enum Style {
        PLAIN, BOLD, ITALIC, UNDERLINE
    }

    // EnumSet으로 표현된 글꼴 스타일 설정 메서드
    public void setStyle(EnumSet<Style> styles) {
        // 스타일 설정
    }

    // EnumSet으로 표현된 글꼴 스타일 반환 메서드
    public EnumSet<Style> getStyle() {
        // 스타일 반환
        return EnumSet.noneOf(Style.class);
    }
}

 

결론 : 열거할 수 있는 타입을 한데 모아 집합 형태로 사용한다고 해도 비트 필드를 사용할 이유는 없다. EnumSet 클래스가 비트 필드 수준의 명료함과 성능을 제공하고 열거 타입의 장점까지 선사하기 때문이다. EnumSet의 유일한 단점이라면 불변 EnumSet을 만들 수 없다는 것이다.

ordinal() 메서드 : 열거 상수가 선언된 순서에 따라 0부터 시작하는 정수 값을 반환해준다. 그러나 이 값은 열거 상수의 순서를 나타내는 데에만 사용되며, 일반적으로 이 값을 외부에서 직접 참조하는 것은 권장되지 않는다. 대신 열거 상수마다 고유한 의미있는 값을 갖는 인스턴스 필드를 추가하는 것이 좋다.

 

열거 상수마다 고유한 의미있는 값을 갖는 인스턴스 필드를 추가한 예시 코드 : 

enum Season {
    SPRING("March", "April", "May"),
    SUMMER("June", "July", "August"),
    AUTUMN("September", "October", "November"),
    WINTER("December", "January", "February");

    private final String[] months;

    Season(String... months) {
        this.months = months;
    }

    public String[] getMonths() {
        return months;
    }
}

public class Main {
    public static void main(String[] args) {
        Season currentSeason = Season.SUMMER;
        String[] months = currentSeason.getMonths();
        System.out.println("Months in summer: " + Arrays.toString(months)); // 출력: Months in summer: [June, July, August]
    }
}

 

 

결론 : ordinal 메서드는 절대 사용하지말자!

+ Recent posts