Effective Java 독서 노트 - 제2장 객체 만들기 및 파괴

7661 단어
개인 독서 노트는 일부 읽지 못한 지식이 간단하게 요약되거나 부족할 수 있으므로 나중에 반복해서 읽고 보완해야 한다.

제2장 창설 및 파괴 대상


제1조: 구조기 대신 정적 공장 방법 사용


정적 공장 방법의 장점.
1. 이름이 있어 읽기가 편합니다.2. 매번 호출할 때마다 새 대상을 만들지 않아도 된다(구조기가 필요하다).3. 원래 되돌아오는 유형의 모든 하위 유형의 대상을 되돌릴 수 있다(더 유연하다).4. 매개 변수화 유형의 실례를 만들어서 코드를 더욱 간결하게 한다.예:
public static  HashMap newInstance() {
        return new HashMap<>();
}
    
Map> m =Singleton.newInstance();

정적 공장 방법의 나쁜 점.
1. 클래스는 공유되거나 보호된 구조기가 없으면 이불로 분류할 수 없다.2. 정적 방법과 다를 바 없다(읽기 불편하다?)

제2조: 여러 개의 구조기를 만났을 때 구축기를 고려해야 한다


클래스에는 여러 개의 매개 변수가 있는데 일반적으로 사용하는 중첩 구조기(telescoping constructor) 모드가 좋지 않은 점이 있다. 예를 들어 설정하고 싶지 않은 매개 변수도 어쩔 수 없이 값을 전달해야 한다.
해결 방법은 자바빈스 모드와 Builder 모드를 언급했다.
javaBeans 모드:
public class NutritionFacts {
    private int servingSize = -1;
    private int servings = -1;
    private int calories = 0;
    private int fat = 0;
    private int sodium = 0;
    private int carbohydrate = 0;

    public NutritionFacts() {
    }

    public void setServingSize(int servingSize) {
        this.servingSize = servingSize;
    }

    public void setServings(int servings) {
        this.servings = servings;
    }

    public void setCalories(int calories) {
        this.calories = calories;
    }

    public void setFat(int fat) {
        this.fat = fat;
    }

    public void setSodium(int sodium) {
        this.sodium = sodium;
    }

    public void setCarbohydrate(int carbohydrate) {
        this.carbohydrate = carbohydrate;
    }
}

Builder 모드:
public class NutritionFacts {
   
    private int servingSize;
    private int servings;
    private int calories;
    private int fat;
    private int sodium;
    private int carbohydrate;

    public static class Builder {
        private final int servingSize;
        private final int servings;

        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder setCalories(int calories) {
            this.calories = calories;
            return this;
        }

        public Builder setFat(int fat) {
            this.fat = fat;
            return this;
        }

        public Builder setSodium(int sodium) {
            this.sodium = sodium;
            return this;
        }

        public Builder setCarbohydrate(int carbohydrate) {
            this.carbohydrate = carbohydrate;
            return this;
        }
    }

    private NutritionFacts(Builder builder) {
        servingSize=builder.servingSize;
        servings=builder.servings;
        calories=builder.calories;
        fat=builder.fat;
        sodium=builder.sodium;
        carbohydrate=builder.carbohydrate;
    }
}

Builder 모드 호출 코드:
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
                    .setCalories(100)
                    .setSodium(35)
                    .setCarbohydrate(27)
                    .build();

클래스 구조기나 정적 플랜트에 여러 매개변수가 있는 경우 Builder 모드를 권장합니다.

제3조: 개인 구조기나 매거 유형으로singleton 속성 강화


Singleton은 단지 한 번만 실례화된 종류를 가리킨다.
java 1.5 이전에 Singleton을 실현하는 두 가지 방법:
public class Elvis {
    private static final Elvis INSTANCE = new Elvis();

    private Elvis() {}
    
    private static Elvis getInstance(){
        return INSTANCE;
    }

    public void leaveTheBuilding() {}
}

또는:
public class Elvis2 {
    private static Elvis2 ourInstance = new Elvis2();

    public static Elvis2 getInstance() {
        return ourInstance;
    }

    private Elvis2() {
    }
    public void leaveTheBuilding() {}
}

두 번째 방법은 더욱 유연하다.범형우량(제27조)java1.5를 사용한 후singleton을 실현하는 세 번째 방법:
public enum Elvis3 {
    INSTANCE;
    public void leaveTheBuilding() {}
}

제4조: 사유구조기를 통해 실례화할 수 없는 능력을 강화


일부 도구류는 실례화를 원하지 않고, 클래스를 추상류로 만들어서 이 클래스가 실례화되지 못하도록 강요하는 것은 통하지 않는다.
이 클래스에 개인 구조기를 포함시킬 수 있습니다.
public class UtilityClass {
    private UtilityClass() {
        throw new AssertionError();
    }
}

이 방법의 부작용: 한 종류를 이불로 분류할 수 없게 한다.

제5조: 불필요한 대상을 만드는 것을 피한다


필요할 때마다 같은 기능을 가진 새로운 대상을 만드는 것이 아니라 대상을 다시 사용하는 것이 좋다.극단적 예:
String s = new String("stringette");

이러한 쓰기 방식이 반복에 사용되는 경우 불필요한 String 인스턴스가 수천 개 생성됩니다.일반 쓰기:
String s = "stringette";

수정되지 않을 것으로 알려진 일부 가변 대상도 다시 사용할 수 있다.이전 예제 재사용:
class Person{
    private final Date birthDate;

    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }

    /*
     *        
     * */
    public boolean isBabyBoomer() {
        Calendar gmtCal=Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
        Date boomStart=gmtCal.getTime();
        gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
        Date boomEnd=gmtCal.getTime();
        return birthDate.compareTo(boomStart) >= 0 &&
                birthDate.compareTo(boomEnd) < 0;
    }
}

재사용 후 예(호출 속도가 현저히 빨라짐):
class Person{
    private final Date birthDate;

    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }
    /*
     *      (  250 )
     * */
    private static final Date BOOM_START;
    private static final Date BOOM_END;
    static {
        Calendar gmtCal=Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
        BOOM_START=gmtCal.getTime();
        gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
        BOOM_END=gmtCal.getTime();
    }

    public boolean isBabyBoomer2() {
        return birthDate.compareTo(BOOM_START) >= 0 &&
                birthDate.compareTo(BOOM_END) < 0;
    }
}    

컨테이너 기본 유형이 아닌 기본 유형을 우선적으로 사용하려면 무의식적으로 자동 컨테이너를 조심해야 한다.
예:
public static void main(String[] args) {
        Long sum=0L;
        for (long i = 0; i < Integer.MAX_VALUE; i++) {
            sum += i;
        }
        System.out.println(sum);
    }

sum의 성명은 롱이 아니라 롱이다. 이것은 프로그램이 많은 여분의 롱 실례를 구성했다는 것을 의미한다.운행 시간이 크게 떨어지다.

제6조: 기한이 지난 대상의 응용을 없애다


메모리 유출이 있는 프로그램:
public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0) {
            throw new EmptyStackException();
        }
        //         
        return elements[--size];
        /*
        *        
        * */
        //Object result = elements[--size];
        //elements[size]=null;
        //return result;
    }

    private void ensureCapacity() {
        if (elements.length == size) {
            elements = Arrays.copyOf(elements, 2 * size + 1);
        }
    }
}

코드에서 만료된 애플리케이션을 비워 메모리 누수를 해결하려면:
Object result = elements[--size];
    elements[size]=null;
    return result;

제7조: 기한이 지난 방법의 사용을 피한다


종결 방법(finalizer)은 통상적으로 예측할 수 없으며, 일반적인 상황에서는 불필요하다.종결 방법을 사용하면 성능 손실도 있을 수 있다.

좋은 웹페이지 즐겨찾기