이펙티브 자바 아이템3 용어 정리

이창호·2022년 4월 9일
0

이펙티브자바

목록 보기
5/12

Reflection API

Spring Framework에서 제공하는 기능이다.
코드에서 처럼 Object를 참조한 person은 getter, setter가 있어도 접근 할 수 없다.
reflection을 사용하여 class를 가져온 후 field를 찾는다.
여기서 field를 조작할 수 도 있다.
spring framework에서 bean factory에 등록한 bean을 관리하는 것도 reflection을 활용 한 것이다.

public class ReflectionExample {
    static class Person {
        private String name;
        private int age;
    }

    public static void main(String[] args) {
        givenObject_whenGetsFieldNamesAtRuntime_thenCorrect();
    }

    public static void givenObject_whenGetsFieldNamesAtRuntime_thenCorrect() {
        // All object(ex -> Person) are sub-class of Object
        Object person = new Person();
        // Now using reflect to find Person's fields.
        // Returns the runtime class of this Object.
        // And returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object.
        Field[] fields = person.getClass().getDeclaredFields();
        List<String> actualFieldNames = getFieldNames(fields);

        // List extends Collection extends Iterable.forEach(Consumer<? super T> action)
        // Using MessageFormat for thread-safe
        actualFieldNames.forEach(s -> System.out.println(MessageFormat.format("{0}", s)));
    }

    private static List<String> getFieldNames(Field[] fields) {
        List<String> fieldNames = new ArrayList<>();
        for (Field field : fields) {
            fieldNames.add(field.getName());
        }
        return fieldNames;
    }
}

유일한 instance를 반환하던 factory method가 호출하는 thread별로 다른 instance를 넘겨주게 할 수 있다.

아래 코드는 다른 thread가 접근하여도 똑같은 instance를 받는다.

public class Test {
	private static final Test INSTANCE = new Test();
    private Test() { ... }
    public static Test getInstance() { return INSTANCE; }
    
    ...
}

아래 코드는 thread 별로 다른 instance를 받는다.

public class Test {
    private Test() { ... }
    public static Test getInstance() { return new Test(); }
    
    ...
}

Generic Singleton Factory

Generic Type을 사용하는 singleton factory다.

public class GenericSingletonFactory {
    private static class SetFactory {
        private static final Set EMPTY_SET = new HashSet();

        private static <T> Set<T> emptySet() {
            return (Set<T>) EMPTY_SET;
        }
    }

    public static void main(String[] args) {
        Set<String> stringSet = SetFactory.emptySet();

        stringSet.add("hello");

        System.out.println(stringSet);
    }
}

Suppier

static factory method의 method reference를 supplier로 사용 할 수 있다.
supplier는 functional이기 때문에 lazy하게 처리 할 수 있다.

// Supplier 코드
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

// Supplier를 사용한 random한 숫자 받기
public class SupplierTest {
    public static void main(String[] args) {
        Supplier<Double> randomValue = new Supplier<Double>() {
            @Override
            public Double get() {
                return Math.random();
            }
        };

        Supplier<Double> randomValue2 = () -> Math.random();

        Supplier<Double> randomValue3 = Math::random;

        System.out.println(randomValue.get());
    }
}

// Supplier를 반환하는 static method factory
public class CarFactory {
    private static Map<String, Supplier<Car>> cars;

    static {
        cars = new HashMap<>();
        cars.put("Kia", KiaCar::new);
        cars.put("Hyundai", HyundaiCar::new);
    }

    public static Car create(final String carName) {
        try {
            return cars.get(carName).get();
        } catch (NullPointerException e) {
            throw new IllegalArgumentException("해당하는 차가 없습니다!");
        }
    }
}

Serialization, Deserialization

Serialization한 class를 Deserialization하면 Signleton이 부셔진다!
여기참고

public class Test {
	private static final Test INSTANCE = new Test();
    private Test() { ... }
    public static Test getInstance() { return INSTANCE; }
    
    // Deserialization 막기!
    private Object readResolve() {
    	// 진짜 Test를 반환하고 가짜 Test는 GC에 맡긴다.
    	return INSTANCE;
	}
}

Enum for singleton

원소가 하나 뿐인 enum을 쓰는게 singleton을 하기엔 가장 좋다.
하지만! enum 외에 다른 것을 상속해야 한다면 다른 방법이 좋다.
그런데, enum에서 interface를 구현하는 방법은 가능하다.

    public enum Test implements Test2 {
        INSTANCE;

        @Override
        public void a() {
            
        }
    }

    public static interface Test2 {
        void a();
    }

참고

https://huisam.tistory.com/entry/FactoryMethod

profile
이타적인 기회주의자

0개의 댓글