• 1_불변 객체(Immutable Object)
    : String은 이미 불변 객체로 정의돼있다.

     
    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    // Java 의 클래스 = 레퍼런스 타입
    // : 객체는 힙에 생성된다.
    
    // Immutable Object(불변 객체)
    // 장점
    // 1. 생성자의 방어 복사 및 접근 메소드의 방어 복사가 필요없다.
    // 2. 병렬 프로그래밍을 작성할 때, 동기화 없이 객체를 공유 가능하다.
    //   "특별한 이유가 없다면 객체를 불변 객체로 설계해야 한다."
    //    : Effective Java, Effective Objective-C
    
    // 단점
    // 객체가 가지는 값마다 새로운 객체가 필요하다.
    // String s += "xxx";   // "Helloxxx"
    //  : 내용이 동일한 객체는 공유되는 메커니즘을 제공해야 한다.(Flyweight)
    //    - static factory method
    
    // 불변 클래스를 만드는 방법
    // 1. 객체를 변경하는 setter 를 제공하지 않습니다.
    // 2. 모든 필드를 final
    // 3. 가변 객체 참조 필드를 사용자가 얻을 수 없도록 해야 한다 (private)
    // 4. 상속 금지 (final class, final method, 생성자를 private 으로 정의하고 public static factory method를 제공)
    
    public class Example1 {
        public static void main(String[] args) {
            Point pos = new Point(10, 20);
    
            // Integer i;
    
            Rect r = new Rect(pos);
            // pos.setY(100);    // 공격!
    
            pos = r.getPosition();
            // pos.setX(-9999);
    
            String s = r.getName();
            s = "xxx";
    
            System.out.println(r);
        }
    }
    
    // String, Integer, Long ... : Immutable Object
    
    class Rect {
        // 캡슐화, 정보 은닉
        private final Point position;
        private String name;
    
        public Rect(Point position) {
            this.position = position.clone();
            this.name = "Tom";
        }
    
        public String getName() {
            return name;
        }
    
        public Point getPosition() {
            return position.clone();
        }
    
        @Override
        public String toString() {
            return "Rect{" +
                    "position=" + position +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
    
    class Point implements Cloneable {
        final int x;
        final int y;
    
        @Override
        public Point clone() {
            try {
                return (Point) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        public int getX() {
            return x;
        }
    
        public int getY() {
            return y;
        }
        /*
        public void setX(int x) {
            this.x = x;
        }
    
        public void setY(int y) {
            this.y = y;
        }
        */
    
        @Override
        public String toString() {
            return "Point{" +
                    "x=" + x +
                    ", y=" + y +
                    '}';
        }
    }
    

  • 2_불변 객체
    : final로 선언된 배열은 변하지 않지만, 배열 안의 데이터가 변할수 있다. -> VALUES 는 변하지 않지만 VALUE 안에 데이터가 변할수가 있다.

     
    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.Collections;
    
    public class Example2 {
        /*
        private static final Integer[] VALUES =
                { 1, 2, 3, 4, 5 };
    
        // 해결 방법 1. 방어 복사본
        public static Integer[] values() {
            return VALUES.clone();
        }
        */
    
        // 해결 방법 2. 수정불가 컬렉션 사용 - UnsupportedOperationException
        private static final Integer[] PRIVATE_VALUES = {1, 2, 3, 4, 5};
        public static final Collection<Integer> VALUES =
                Collections.unmodifiableCollection(Arrays.asList(PRIVATE_VALUES));
    
        public static void main(String[] args) {
            Collection<Integer> arr = Example2.VALUES;
            arr.add(10);
    
            for (Integer e : VALUES) {
                System.out.println(e);
            }
        }
    }
    


'Programing > Java' 카테고리의 다른 글

Effective Java - 스레드(2)  (0) 2016.03.07
Effective Java - 스레드(1)  (0) 2016.03.07
Effective Java - 객체 비교, 복제  (0) 2016.03.04
Effective Java - 객체 소멸  (0) 2016.03.04
Junit 사용하기  (0) 2016.03.03
  • 객체 비교
    - 1_equals 재정의

    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    import java.util.Objects;
    
    // 1. Object.equals()를 재정의하지 않을 경우
    // 모든 객체는 오직 자기 자신과 동일하다.
    
    // 2. 객체 동일성이 아닌 논리적 동일성의 개념을 제공하기 위해서는
    // equals()를 재정의해야 한다.
    
    class Point {
      private int mX;
      private int mY;
    
      public Point(int x, int y) {
        this.mX = x;
        this.mY = y;
      }
    
      @Override
      public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + mX;
        result = prime * result + mY;
        return result;
      }
    
      @Override
      public boolean equals(Object obj) {
        // 1. 자기 자신인지 검사 - 성능
        if (this == obj) return true;
        // 2. null 인지 체크 (모든 객체는 null과 동치 관계가 있지 않다.)
        if (obj == null) return false;
        // 3. 인자의 자료형이 정확한지 검사.
        if (!(obj instanceof Point)) return false;
        // 4. 자료형 변환
        Point p = (Point) obj;
    
        // 5. 중요 필드 점검
        return mX == p.mX && mY == p.mY;
      }
    }
    
    
    class Unit {
      private Point position;
      private Point start;
    
      // 1. 객체에 대한 참조는 null이 될 수 있다.
      // 필드가 많아지면 Objects.equal을 고려하자.(Google Guava / 1.7)
    
    
      @Override
      public boolean equals(Object obj) {
        if (obj == this) return true;
        if (obj == null) return false;
        if (!(obj instanceof Unit)) return false;
    
        Unit p = (Unit) obj;
        // if (position == null) {
        // if (p.position != null) return false;
        // } else if (!position.equals(p.position)) return false;
        // return true;
    
        return Objects.equals(position, p.position) && Objects.equals(start, p.start);
      }
    }
    
    public class Example5 {
      public static void main(String[] args) {
        Point p1 = new Point(10, 20);
        Point p2 = new Point(10, 20);
    
        if (p1.equals(p2)) {
          System.out.println("Same");
        } else {
          System.out.println("Not Same");
        }
      }
    
    }
    


    - 2_BigDecimal, 배열 비교
    : 컴퓨터는 태생적으로 부동소수점을 정확히 표현할 수 없다.(2진수로 표현하기 때문에...)
    : float, double은 == 로 비교하면 안된다. -> BigDecimal 사용
    : 배열의 내용 비교 -> Arrays.equals()

    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    import java.math.BigDecimal;
    import java.util.Arrays;
    
    // 1. float이나 double은 ==으로 비교하면 안된다.
    // 2. 정밀한 연산을 필요로 한다면 BigDecimal 을 사용해야 한다.
    public class Example6 {
      public static void main(String[] args) {
    
        double value1 = 2.0 - 1.1;
        double value2 = 0.9;
    
        // if (value1 == value2) {
        if (Math.abs(value1 - value2) < 0.001) {
          System.out.println("same");
        } else {
          System.out.println("not same");
        }
    
        BigDecimal v = new BigDecimal(2.0).subtract(new BigDecimal(1.1));
        System.out.println(v);;
    
        // 주의 사항 : BigDecimal(String)의 생성자를 사용해야 한다.
        BigDecimal v2 = new BigDecimal("2.0").subtract(new BigDecimal("1.1"));
        System.out.println(v2);;
    
        //-------------------------------------------------
        // 3. 배열 내용을 비교하려면 Object.equals() 가 아닌 Arrays.equals()
        //    사용해야 한다.
        int[] arr1 = new int[20];
        int[] arr2 = new int[20];
    
        System.out.println(arr1.equals(arr2));
    
        System.out.println(Arrays.equals(arr1, arr2));
      }
    }

  • - 3_hashCode
     : Google Guava를 사용하여 toString 재정의
    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Objects;
    
    import com.google.common.base.MoreObjects;
    
    
    // 핵심 : 같은 객체는 동일한 해시 코드 값을 가져야 한다.
    // 즉 equals를 재정의한 클래스는 반드시 hashCode도 재정의해야 한다.
    // 그래야 HashMap, HashSet, HashTable 등 hash 기반 컬렉션과 함께 사용하면 오동작 하지 않는다.
    
    public class Example7 {
      public static void main(String[] args) {
        Map<Person, String> m = new HashMap<>();
    
        m.put(new Person("Tom", 42), "Google");
    
        System.out.println(m.get(new Person("Tom", 42)));
    
        // toString()을 잘 만들어 놓으면 편리하다.
        System.out.println(new Person("IU", 42));
      }
    }
    
    
    class Person {
      private String name;
      private int age;
    
      public Person(String name, int age) {
        this.name = name;
        this.age = age;
      }
    
      @Override
      public String toString() {
        return MoreObjects.toStringHelper(this).add("name", name).add("age", age).toString();
      }
    
      @Override
      public int hashCode() {
        // equals 에 이용된 중요 필드를 이용해서 hash를 생성하면 된다.
        return Objects.hash(name, age);
      }
    
      @Override
      public boolean equals(Object o) {
        if (o == this) return true;
        if (o instanceof Person) {
          Person p = (Person) o;
          return Objects.equals(name, p.name) && age == p.age;
        }
    
        return false;
      }
    }
    
    


  • 객체 복제
    : 인자 전달 방식
     -> Call-by-Value vs. Call-by-Reference

    : 객체 복사 방식
     -> 얕은 복사(Shallow Copy) vs. 깊은 복사(Deep Copy)

    class Num {
    	public int num;
    	
    	public Num(int num) {
    		this.num = num;
    	}
    }
    
    public class CallBy {
    	
    	// 값을 복사해서 인자 전달
    	// value는 객체에 대한 레퍼런스 값, 프리미티브 타입의 값
    	public void callByValue(int a, int b) { 
    		System.out.println("callByValue in method: " + a + " " + b);
    		int swap = a;
    		a = b;
    		b = swap;
    		System.out.println("callByValue out method: " + a + " " + b);
    		
    	}
    	
    	// 해당 객체를 참조하는 객체를 복사해서 인자 전달(얕은 복사)
    	// 해당 객체의 주소값을 직접 넘기는 것이 아니라 객체를 가리키고 있는 또 다른 주소값을 만들어서 넘긴다
    	void callByReference(Num a, Num b) {
    		System.out.println("callByReference in method: " + a.num + " " + b.num);
    		Num swap = a;
    		a = b;
    		b = swap;
    		System.out.println("callByReference out method: " + a.num + " " + b.num);
    	}
    	
    	// 객체의 멤버 필드값에 대한 복사가 필요(깊은 복사)
    	void callByReference2(Num a, Num b) {
    		System.out.println("callByReference2 in method: " + a.num + " " + b.num);
    		int swap = a.num;
    		a.num = b.num;
    		b.num = swap;
    		System.out.println("callByReference2 out method: " + a.num + " " + b.num);
    	}
    	
    	public static void main(String[] args) {
    		CallBy call = new CallBy();
    		
    		int a = 5;
    		int b = 10;
    		
    		Num n1 = new Num(5);
    		Num n2 = new Num(10);
    		
    		call.callByValue(a, b);
    		System.out.println("callByValue main method: " + a + " " + b + "\n");
    		//callByValue in method: 5 10
    		//callByValue out method: 10 5
    		//callByValue main method: 5 10
    		
    		call.callByReference(n1, n2);
    		System.out.println("callByReference main method: " + n1.num + " " + n2.num + "\n");
    		//callByReference in method: 5 10
    		//callByReference out method: 10 5
    		//callByReference main method: 5 10
    		
    		call.callByReference2(n1, n2);
    		System.out.println("callByReference2 main method: " + n1.num + " " + n2.num);
    		//callByReference2 in method: 5 10
    		//callByReference2 out method: 10 5
    		//callByReference2 main method: 10 5
    		
    	}
    }
    


    - 1_clone, Cloneable
     : 객체에 대한 깊은 복사
     : 
    상속을 해주기 위한 클래스를 설계할 때, 잘 동작하는 protected clone 메소드를 그 클래스에 두지 않는다면 서브 클래스에서 Cloneable 인터페이스를 제대로 구현할 수 없다.

    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    import com.google.common.base.MoreObjects;
    
    class Point implements Cloneable {
      private int x;
      private int y;
    
      public Point(int x, int y) {
        this.x = x;
        this.y = y;
      }
    
      public int getX() {
        return x;
      }
    
      public void setX(int x) {
        this.x = x;
      }
    
      public int getY() {
        return y;
      }
    
      public void setY(int y) {
        this.y = y;
      }
    
      @Override
      public String toString() {
        return "(" + x + ", " + y + ")";
      }
    
      @Override
      public Point clone() {
        try {
          return (Point) super.clone();
        } catch (CloneNotSupportedException e) {
          e.printStackTrace();
        }
    
        return null;
      }
    }
    
    // 객체 복제 하기
    // 1. clone() 함수를 오버라이드 한다. (protected -> public)
    // : 오버라이딩할 메소드는 부모의 접근 제한자와 같거나 접근하기 더 쉬워야 한다.
    
    // 2. Cloneable 인터페이스를 구현해야 한다.
    // : 어떤 객체가 복제를 허용한다는 사실을 알리는데 쓰이는 용도이다.
    
    
    // 객체가 Cloneable 인터페이스를 구현하고 있으면, Object.clone() 은
    // 객체가 가지고 있는 모든 멤버를 복사한다.
    class Unit implements Cloneable {
      private String name;
      private int age;
    
      private Point position;
      // 중요 : 변경 가능 객체에 대한 참조를 가지고 있으면 문제가 발생한다.
    
      public Unit(String name, int age, Point pos) {
        this.name = name;
        this.age = age;
        this.position = pos;
      }
    
      public void setPos(int x, int y) {
        position.setX(x);
        position.setY(y);
      }
    
      
      // public Object clone() {
      // 공변 반환형 : 재정의 메소드의 리턴 타입은 재정의 되는 메소드의
      // 리턴 타입의 하위 클래스가 될 수 있다.(1.5)
      //  @Override
      //  public Unit clone() {
      //    try {
      //      return (Unit) super.clone();
      //    } catch (CloneNotSupportedException e) {
      //      e.printStackTrace();
      //    }
      //
      //    return null;
      //  }
    
      @Override
      public Unit clone() {
        try {
          // 1. 전체 복사 후
          Unit result = (Unit) super.clone();
    
          // 2. 변경 가능 객체 복제
          result.position = position.clone();
          return result;
    
        } catch (CloneNotSupportedException e) {
          e.printStackTrace();
        }
    
        return null;
      }
    
      @Override
      public String toString() {
        return MoreObjects.toStringHelper(this).add("name", name).add("age", age)
            .add("pos", position).toString();
      }
    }
    
    
    public class Example8 {
      public static void main(String[] args) {
        Unit p1 = new Unit("Tom", 42, new Point(0, 0));
    
        // Unit p2 = (Unit) p.clone();
        Unit p2 = p1.clone();
    
        p2.setPos(10, 20); // !!!
    
        System.out.println(p1);
        System.out.println(p2);
      }
    }
    


    - 2_생성자 방어 복사
     : 접근자를 이용하여 클라이언트가 값을 변경할 수 있다. -> 캡슐화가 깨짐
     : 객체를 복사할 때 객체의 참조를 리턴하는 것이 아니라 객체의 복사본을 리턴한다. pos.setX(9999)로 x값을 변경해도 복사한 객체의 값을 바꾸므로 기존의 객체의 값은 그대로 유지된다.

    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    import com.google.common.base.MoreObjects;
    
    public class Example9 {
      public static void main(String[] args) {
        
        // 1. 생성자 방어 복사가 필요하다.
        //  : 인자의 유효성을 검사하기 전에 복사하고 나서, 
        //    원본이 아닌 복사본의 유효성을 검사해야 한다.
        Point pos = new Point(100, 200);
        // Unit unit = new Unit(pos);
        
        
        String name = "Tom";
        Unit unit = new Unit(pos, name);
        
        pos.setX(9999);
        
        // 2. 접근자 메소드에서도 참조를 방어 복사하여 리턴해야 한다.
        pos = unit.position();
        pos.setX(9999);
    
        System.out.println(unit);
      }
    }
    
    
    class Unit {
      private Point position;
      private String name;
      
      public Unit(Point pos, String name) {
        position = pos.clone();
        // position = pos;
        this.name = name;
      }
    
      public String name() {
        return name;
      }
      
      public Point position() {
        return position.clone();
      }
    
      @Override
      public String toString() {
        return MoreObjects.toStringHelper(this)
            .add("pos", position).add("name", name).toString();
      }
    
    }
    
    
    class Point implements Cloneable {
      private int x;
      private int y;
    
      public Point(int x, int y) {
        this.x = x;
        this.y = y;
      }
    
      public int getX() {
        return x;
      }
    
      public void setX(int x) {
        this.x = x;
      }
    
      public int getY() {
        return y;
      }
    
      public void setY(int y) {
        this.y = y;
      }
    
      @Override
      public String toString() {
        return "(" + x + ", " + y + ")";
      }
    
      @Override
      public Point clone() {
        try {
          return (Point) super.clone();
        } catch (CloneNotSupportedException e) {
          e.printStackTrace();
        }
    
        return null;
      }
    }
    


'Programing > Java' 카테고리의 다른 글

Effective Java - 스레드(1)  (0) 2016.03.07
Effective Java - 불변 객체  (0) 2016.03.07
Effective Java - 객체 소멸  (0) 2016.03.04
Junit 사용하기  (0) 2016.03.03
Effective Java - 객체 생성  (0) 2016.03.03
  • 1_명시적 자원 해지

    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    import java.awt.Image;
    import java.io.IOException;
    import java.net.URL;
    
    import javax.imageio.ImageIO;
    
    // 핵심 : 객체 내부에서 비 메모리 자원을 사용한다면 명시적 종료 메소드를 제공해야 한다.
    // 이유
    // 1. 가비지 컬렉션은 메모리만 수집한다.
    // 2. 가비지 컬렉션이 수거하지 않는 비 메모리 자원에 대해서는
    // 프로그래머가 관리 해야 한다.
    
    // 3. finalize() - 종료자
    // 개념 : 더 이상 참조할 수 없는 객체의 메모리 공간을 회수 할 때 GC에 의해서 호출되는 메소드
    // 문제 : finalize()를 비 메모리 자원을 정리하는 용도로 사용하면 안된다.
    // 1. 즉시 실행된다는 보장이 없다.
    // 예) 종료자 안에서 파일 닫기. - JVM은 종료자를 천천히 실행하므로,
    // 열린 상태의 파일이 많이 남아 있을 수 있다.
    // 한번에 열 수 있는 파일의 개수에 제한이 있으므로 오류가 날 수 있다.
    // - 종료자의 실행 시점은 JVM의 구현에 의존한다.
    
    // 2. 반드시 실행된다는 보장도 없다.
    // - 자바 명세에는 종료자가 즉시 실행되어야 한다는 문구도 없지만,
    // 종료자가 반드시 실행되어야 한다는 문구도 없다.
    // 즉 종료자가 실행되지 않은 객체가 남은 상태로 프로그램이 종료할 수도 있다.
    // (동기화 객체 같은 것을 절대 종료자를 통해 반납하면 안된다)
    
    
    class WebPhoto {
      Image image;
    
      // 명시적인 종료 메소드 - OutputStream, InputStream, Socket 등
      public void release() {
        if (image != null) {
          image.flush();
        }
      }
    
      public WebPhoto(String imageUrl) {
        URL url;
        try {
          url = new URL(imageUrl);
          image = ImageIO.read(url);
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    
    
    public class Example1 {
      public static void main(String[] args) throws InterruptedException {
        // WebPhoto가 더 이상 사용되지 않는다면, 객체 내부에서 사용하고 있는
        // 자원에 대해서 정리가 필요하다.
        WebPhoto photo = new WebPhoto("http://cfs7.tistory.com/image/14/tistory/2008/08/29/04/53/48b702410053a");
    
        // photo = null;
        // photo.release();
    
        // System.gc();
      }
    }
    

  • 2_finalize

    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    import java.awt.Image;
    import java.io.IOException;
    import java.net.URL;
    
    import javax.imageio.ImageIO;
    
    // finalize()의 용도
    // : 명시적 종료 메소드 호출을 잊은 경우의 안정망을 제공할 수 있다.
    
    // 1. 그런 자원을 발견한 경우 반드시 경고 메세지를 남겨야 한다. (클라이언트 코드에 버그가 있는 것이므로)
    // 2. 부모의 종료자를 명시적으로 호출해야 한다.
    
    class WebPhoto {
      Image image;
    
      /*
      @Override
      public void finalize() {
        if (image != null) {
          System.err.println("Explicit termination method 'release' is not called");
          release();
        }
      }
      */
      
      @Override
      public void finalize() throws Throwable {
        try {
          if (image != null) {
            System.err.println("Explicit termination method 'release' is not called");
            release();
          }
        } finally {
          super.finalize();
        }
      }
      
      // 명시적인 종료 메소드 - OutputStream, InputStream, Socket 등
      public void release() {
        if (image != null) {
          image.flush();
        }
      }
    
      public WebPhoto(String imageUrl) {
        URL url;
        try {
          url = new URL(imageUrl);
          image = ImageIO.read(url);
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    
    
    public class Example2 {
      public static void main(String[] args) throws InterruptedException {
        WebPhoto photo = new WebPhoto("https://t1.daumcdn.net/cfile/tistory/2761F44856D7F79F2A");
        // System.gc();
      }
    }
    

  • 3_finalize2

    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    import java.awt.Image;
    import java.io.IOException;
    import java.net.URL;
    
    import javax.imageio.ImageIO;
    
    // 명시적 자원 해지가 필요한 클래스는 결국 중복된 코드를 작성해야 한다.
    
    // 종료자의 역활을 일반화한 클래스
    final class CloseGuard {
      public static CloseGuard get() {
        return new CloseGuard();
      }
    
      private CloseGuard() {}
    
      private Throwable site;
    
      public void open(String closer) {
        if (closer == null) throw new NullPointerException("closer == null");
    
        String message = "Explicit termination method '" + closer + "' not called";
        site = new Throwable(message);
      }
    
      public void close() {
        site = null;
      }
    
      public void warnIfOpen() {
        if (site == null) return;
    
        System.err.println(site.toString());
      }
    }
    
    
    class WebPhoto {
      private Image image;
    
      // Surface.java
      private final CloseGuard mCloseGuard = CloseGuard.get();
    
      @Override
      public void finalize() throws Throwable {
        try {
          if (mCloseGuard != null) mCloseGuard.warnIfOpen();
          release();
    
        } finally {
          super.finalize();
        }
      }
    
      public void release() {
        if (image != null) {
          image.flush();
        }
    
        if (mCloseGuard != null) mCloseGuard.close();
      }
    
      public WebPhoto(String imageUrl) {
        URL url;
        try {
          url = new URL(imageUrl);
          image = ImageIO.read(url);
    
          mCloseGuard.open("release");
    
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    
    
    public class Example3 {
      public static void main(String[] args) {
        WebPhoto photo = new WebPhoto("https://t1.daumcdn.net/cfile/tistory/2761F44856D7F79F2A");
        // System.gc();
      }
    }
    

  • 4_finalize3
    : Finalizer Guardian Idiom(종료자 보호 패턴)
    Image를 상속 받은 클래스(MyImage)의 객체 생성 -> 상위 클래스 Image 객체도 생성 -> MyImage 객체가 GC에 의해 해지 당할 때 하 상위 클래스(Image)의 guardian이란 멤버 변수도 해지 대상이 되고, 여기서 finalize() 호출

    package kr.co.ioacademy; //iocademy 윤찬식 강사님
    
    
    class Image {
    
      public void release() {
        System.out.println("Image 자원 해지");
      }
    
    //  @Override
    //  protected void finalize() throws Throwable {
    //    try {
    //      System.out.println("Image finalize!");
    //      release();
    //    } finally {
    //      super.finalize();
    //    }
    //  }
    
      // 하위 클래스가 부모 클래스의 finalize()를 잊는 문제를
      // 방지하는 방법. - (종료자 보호 패턴)Finalizer Guardian Idiom
      @SuppressWarnings("unused")
      private final Object guardian = new Object() {
        @Override
        protected void finalize() throws Throwable {
          release();
        }
      };
    }
    
    class MyImage extends Image {
    
      @Override
      protected void finalize() throws Throwable {
        System.out.println("MyImage finalize!");
        // 잊었다.!!!
        // super.finalize();
      }
    }
    
    
    public class Example4 {
      public static void main(String[] args) throws InterruptedException {
        MyImage image = new MyImage();
        image = null;
    
        System.gc();
    
        Thread.sleep(10000);
      }
    }
    


'Programing > Java' 카테고리의 다른 글

Effective Java - 불변 객체  (0) 2016.03.07
Effective Java - 객체 비교, 복제  (0) 2016.03.04
Junit 사용하기  (0) 2016.03.03
Effective Java - 객체 생성  (0) 2016.03.03
Java Reference와 GC  (0) 2016.02.29

+ Recent posts