velog에서 이전한 글 입니다.

23.5.2 ~ 23.5.19 사전 캠프 기간의 TIL 기록입니다!
TIL: Today I Learned

정규표현식(regex)

public class Main {
    public static void main(String[] args) {
        String t = "^[0-9]*$";
        String res = "1597asd123".replaceAll(t, "yes");
        System.out.println(res);

        String res2 = "".replaceAll(t, "yes");
        System.out.println(res2);

        String res3 = "1235512".replaceAll(t, "yes");
        System.out.println(res3);
    }
}
결과
1597asd123
yes
yes

[0-9]* : 0~9까지 숫자가 여러개 또는 0개로 이루어져있다.
^ X $ : 시작과 끝이 모두 X를 만족해야 한다.
\w : 알파벳 대소문자 + 숫자 + "_"
\\w+@\\w+\\.\\w+(\\.\\w+)

  • java에서 \은 escape sequence로 \가 나온 다음 문자를 인식해 처리한다.
    그래서 \w가 아닌 \\w를 사용한다.
  • 정규표현식에선 \ 다음에 오는 문자를 일반 문자로 취급한다.
    \. == .이고 java에서 \는 이스케이프 시퀀스로 동작하므로 \\. 이처럼 사용한다.

자바에서 regex \표현을 2개로 생각하고 작성하면 된다.

Generics

public class Main {
    public static void main(String[] args) {
        Map<String, Integer> t = new HashMap();
        t.put("a", 1); t.put("b", 2);
        Iterator<Map.Entry<String, Integer>>it = t.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry<String, Integer> entry = it.next();
            System.out.printf("%s, %d\n", entry.getKey(), entry.getValue());
        }
    }
}

형변환 보단 제너릭을 잘 이용하자.
위의 코드에서 Iterator의 제네릭을 지정하지 않으면 (Map.Entry<String, Integer>) it.next()로 형변환이 필요해진다.

타입 변수<T>

public class Main {
    public static void main(String[] args) {
        new Hello<Cat>(new Cat());
    }
}

class Hello<E> {
    public Hello(E o){
        System.out.println(o);
    }
}

class Cat{
    public String toString(){
        return "냐옹";
    }
}

냐옹

타입 변수를 받는 클래스를 제네릭 클래스라고 말한다.
타입 변수 T는 인스턴스 변수로 간주되고 static 멤버는 이를 참조할 수 없다.

 

컴파일 후엔 제네릭 타입이 제거된 Hello로 바뀐다.
chat-gpt 왈) 자바의 제네릭은 컴파일 시에 타입 체크를 위한 도구로 사용되며, 컴파일된 바이트코드에는 제네릭 타입 정보가 포함되지 않는다.

 

타입 안정성을 높인다
의도하지 않은 타입의 객체 저장을 막고 객체를 꺼내올 때 원래 타입과 다른 타입으로 형변환되어 발생할 수 있는 오류를 줄여준다는 뜻이다.

제한된 제네릭 클래스

class Hello<E extends Dog> {
    public Hello(E o){
        System.out.println(o);
    }
}

Dog 클래스와 그 자손들만 타입으로 지정가능하다.

class Hello<E extends Dog & Hi> {
    public Hello(E o){
        System.out.println(o);
    }
}

interface Hi{
    void hi();
}

interface도 구현할 수 있다. implements가 아닌 extends를 사용한다.
위 코드는 Hi interface 를 구현한 Dog 타입이어야 한다.

class Hello<E extends Dog & Cat> {
    public Hello(E o) {
        System.out.println(o);
    }
}

Dog 또는 Cat 타입으로 제한하고 싶으면 위와 같이 쓸 수 없다.
&는 Dog 와 Cat을 모두 충족한다는 거고 Dog와 Cat은 상속관계가 아니기 때문에 불가능하다. ( or연산은 없는 듯 하다. )

class Hello<E extends Animal> {
    public Hello(E o) {
        System.out.println(o.CustomString());
    }
}

interface Animal{
    String CustomString();
}

class Cat implements Animal{
    public String CustomString() {
        return "냐옹";
    }
}

class Dog implements Animal{
    public String CustomString() {
        return "멍멍";
    }
}

위 코드처럼 공통 타입/인터페이스로 제한할 수 있다.

class Dog implements Animal{
    public String CustomString() {
        return "멍멍";
    }
}

class Dog2 extends Dog implements Animal{

}

상속한 클래스에서 이미 인터페이스를 구현했다면 새로 오버라이딩하지 않아도 오류 없다.


생성자에서 메서드를 오버라이딩 할 방법은 없다? 아마도
생성자는 객체를 만들 때 실행되고 오버라이딩은 클래스 정의에서 이루어진다.
메서드 속 메서드가 가능한 형태가 있다면 모르겠다