Java로 알고리즘 풀 때 Overriding 해 본 equals이다. equals를 재정의 하면 안되는 조건에 대해 소개해준다. 각 인스턴스가 본질적으로 고유하다. Object는 기본적으로 equals 메소드의 비교를 레퍼런스가 같은지를 확인한다. Thread와 같이 값을 표현하는 것이 아닌 동작하는 개체를 표현하는 클래스는 재정의 하지 않는 것이 좋다. 인스턴스의 논리적 동치성(logical equality)을 검사할 일이 없다. 두 인스턴스가 물리적으로 같은지가 아닌 논리적으로 같은지를 확인해야 할 때 재정의가 필요하다. 클라이언트 코드에서 이를 호출할 일도 없고 필요도 없다면 굳이 재정의할 필요가 없다. 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는다. 설계를 완벽하게 해서 ..
자바 라이브러리에는 InputStream, OutputStream, java.sql.Connection과 같이 자원을 할당받고 회수해야 하는 친구들이 많다. I/O 작업과 관련 된 녀석들이 그런 것 같다. 클래스 내부로직에서 Exception이 발생해 close 메소드를 호출하지 못할 수 있다. 따라서 전통적으로 try-finally 블록을 통해 모든 로직의 끝에는 항상 close를 호출하게 구현을 했었다. static String firstLineOfFile(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br..
난생처음 보는 메소드들이다. 현재 finalizer는 Java 9 버전 이상에서 deprecated 됐다. 어차피 쓰지도 않을 녀석들이니 어떠한 사유로 deprecated 됐는지 이유를 가볍게 알아보고 넘어가면 좋을 것 같다. finalizer는 gc가 발생하기 이전 실행 돼야 할 전처리를 담당하는 메소드이다. 이는 C++의 소멸자(destructor)와 다르다. C++은 클래스 내부에서 heap 영역에 메모리를 동적 할당하고 할당된 메모리 해제와 관련한 로직을 직접 작성해야 한다. #include using namespace std; class testClass { public: testClass() { cout
Java에서는 C나 C++에서 처럼 메모리 관리에 대한 고민을 할 필요가 없다. 가비지 콜렉터가 판단해 사용되지 않는 메모리를 해제해 주기 때문이다. 오호 이제 메모리 관리는 신경을 쓰지 않아도 되겠군!이라고 생각했다면 만만의 콩떡이다. package effectivejava.chapter2.item7; import java.util.*; // 코드 7-1 메모리 누수가 일어나는 위치는 어디인가? (36쪽) public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = new Object[DEF..
객체를 매번 생성하기보다 재사용하는 경우가 좋을 때가 많다. String t = new String("bikini"); // 1 String s = "bikini"; // 2 String cmpStr = "bikini" if(t == s) ... t = t.intern(); if(t == s) ... Java 처음 배울 때 무조건 하는 예시이다. 1번 코드처럼 String 객체를 생성자로 생성하면 Heap 영역에 새로운 String 객체가 생성이 된다. 2번 코드와 같이 String 객체를 리터럴로 생성하면 Java의 String Pool 안에 생성된다. 이후에 cmpStr와 같이 리터럴로 String 객체를 생성하면 String Pool 안에서 bikini 객체를 찾고, 예전에 생성되어 있는 bikin..
매우 쉬운 내용이다. 코드 안에 어떤 객체를 박아두고 쓰지 말자는 이야기이다. // 부적절한 static 유틸리티 사용 예 - 유연하지 않고 테스트 할 수 없다. public class SpellChecker { private static final Lexicon dictionary = ...; private SpellChecker() {} // 객체 생성 방지 public static boolean isValid(String word) {...} public static List suggestions(String typo) {...} } // 부적절한 싱글톤 사용 예 - 유연하지 않고 테스트 할 수 없다. public class SpellChecker { private final Lexicon dict..
이건 그렇게 어렵지 않은 내용이다. 이따금 static 메소드나 static 필드만을 담은 클래스를 만들고 싶다. 이런 클래스를 사용하는 용도에는 premitive 타입이나 배열 관련 메소드들 (Object를 상속받지 못해 타입마다 하나하나 만들어야 한다), 객체를 생성하는 static 메소드, final 클래스 관련 메소드들을 모은 클래스를 만들 수 있다. 이런 친구들은 인스턴스를 생성하지 않고 static 메소드 또는 필드를 사용하기 위해 설계된 클래스들이다. 생성자를 명시하지 않으면 자동으로 public 생성자를 만들어 주기 때문에 명시적으로 private 생성자를 만들어 줘 외부에서 인스턴스 생성을 막을 수 있다. package effectivejava.chapter2.item4; // 코드 4-..
내가 좋아하는 싱글톤이다. 주의해서 사용한다면 메모리를 폭발적으로 아낄 수 있다. 책에서 싱글톤의 단점부터 소개한다. 클래스를 싱글톤으로 만들면 클라이언트에서 테스트 코드를 작성하기 어렵다고 한다. 일단 이건 무슨 말인지 모르겠으니 그렇구나 하고 넘어가기로 하자. 싱글톤을 만드는 두 가지 방법 중 첫 번째를 소개한다. private static final 필드를 사용하고 생성자를 private으로 감춘다. package effectivejava.chapter2.item3.field; // 코드 3-1 public static final 필드 방식의 싱글턴 (23쪽) public class Elvis { public static final Elvis INSTANCE = new Elvis(); private..
static 팩토리 메소드와 생성자에는 똑같은 제약이 있다. 이는 입력 받는 파라미터의 개수가 많다면 코드를 알아보기 힘든 매우 화가 나는 상황이 생긴다. 전통 적으로 점층적 생성자(telescoping constructor) 패턴을 사용했다. public class NutritionFacts { private final int servingSize; // (mL, 1회 제공량) 필수 private final int servings; // (회, 총 n회 제공량) 필수 private final int calories; // (1회 제공량당) 선택 private final int fat; // (g/1회 제공량) 선택 private final int sodium; // (mg/1회 제공량) 선택 priva..
어떤 객체의 인스턴스를 얻기 위해 보통 public 생성자를 통해 객체를 생성한다. 이러한 방법 말고 public static 팩토리 메소드를 사용해 해당 클래스의 인스턴스를 만들 수 있다. static 팩토리 메소드에는 다음과 같은 장단점이 있다. 장점 1. 이름을 가질 수 있다. public class Person { String name; String address; int age; public Person(String name, String address,int age) { this.name = name; this.address = address; this.age = age; } public static Person 김꺽정() { return new Person("김꺽정", "북한",32); } ..