자바에서 객체란?
변수들의 콜렉션이다. 개체와, 메서드들의 모음을 나타내기 때문이다. 쉽게 말하면, 객체에는 상태와 행위가 있다.
원시 타입을 제외하면, 자바 언어의 다른 모든 변수들은 참조 타입 이다.
가장 중요한 차이점은 빈 객체를 의미하는 표현인 null이 존재한다는 것이다.
즉, 객체 내의 변수들은 null로 설정될 수 있으며 메서드 또한 null을 반환할 수 있다.
그러나 Null 참조에 대한 관련 메스들 호출할 수는 없으며, 호출하려고 하면 NullPointerException이 발생한다.
예를 들어 String 은 참조 변수이며, String으로 선언된 변수가 null일 경우, 기본 메소드인 length() 를 사용하려고 할 경우 NullPointerException이 발생한다.
참조 타입이란?
원시 타입은 int i =42 로 변수가 선언되면, 42라는 값이 특정 메모리에 할당 된다.
또다른 변수 j가, int j = i 로 i에 의해 값이 할당 되면, 메모리에서 i와는 다른 위치에 같은 값을 할당한다.
즉, 한 번 할당하고 나면 i는 j의 값에 영향을 미칠 수 없다.
반대로 참조타입, 예를 들어 new ArrayList(20) 같은 구문을 생각해보자.
List list = new ArrayList(20) 구문으로 생성된 객체는, list 가 할당된 메모리 위치를 가리킨다.
표면적으로 원시 타입의 메모리 할당과 같아 보이지만, 원시 타입의 메모리 할당과 달리 영향을 끼칠 수 있다.
인스터스라고 불리는 변수가 동일한 속성으로 생성된 객체에 할당될 경우, 같은 메모리 위치를 가리키기 때문이다.
즉, 한 인스턴스에 변경이 생기면 다른 인스턴스가 접근했을 때 영향을 미치는 것이다.
예를 들어, List<String> list1 = new ArrayList<>(20) 으로 list1 객체를 만들었다.
이후 List list2 = list1 으로, list2 객체가 list1과 동일한 속성을 할당받았다고 가정한다.
이후 list2.add("Hello") 와 같이 값을 추가한 후, list1.size() 는 무엇을 리턴할까?
같은 메모리에 위치한 곳에 값을 추가했기 때문에, list2에 값을 추가했지만 list1의 size는 1이 되어 버린다.
접근제어자
클래스의 캡슐화된 상태(변수)와 메서드의 접근을 제어하는 역할을 한다.
네 개의 정의를 이용해 가시성을 제한한다.
하나는 public으로, 어디서든 접근 가능하다.
두번째는 <none>, 즉 접근제어자를 쓰지 않는 것으로, 해당 패키니 내 모든 하위 클래스에서 접근 가능하다.
세번째는 protected로, protected된 변수, 메소드는 동일 패키지내의 클래스 또는 해당 클래스를 상속받은 외부 패키지의 클래스에서 접근이 가능하다.
네번째는 private로, private가 붙은 변수, 메소드는, 해당 변수, 메소드가 선언된 같은 클래스 내에서만 접근 가능하다.
static이 붙은 정적 메서드와 정적 변수는 클래스 내부에 정의하지만, 인스턴스에는 속하지 않는다.
대개 특정 인스턴스보다는 클래스 이름을 통해 무언갈 사용할 때 사용한다.
다형성과 상속
이 둘은 객체 지향 개발의 두 가지 핵심 개념이다.
다형성 : 메소드에 여러 타입에 대한 정의를 만들 수 있게 하고, 메소드를 구현하는 수많은 다른 클래스들을 갖게 한다.
상속: 부모 클래스의 변수나 메서드를 가져다 사용할 수 있게 해준다. 새로운 클래스를 정의할 때, 이전에 정의된 클래스에서 변수와 메서드를 상속할 수 있고, 새로운 메서드를 추가하거나 새로운 변수에 대한 메서드를 오버라이드 할 수 있다.
오버라이드
JVM 상에서 실행되는 모든 클래스는 java.lang.Object를 상속하므로, final 메서드를 제외한 public이나 protected 메서드는 오버라이드 될 수 있다.
예를 들어 자바의 equals(Object other) 메서드는 두 객체의 참조가 논리적으로 같은지 확인하는데 사용된다.
java.util.TreeSet 이나 java.util.HashMap 같은 컬렉션 클래스에서는 객체가 이미 컬렉션 안에 있는지 확인하기 위해 객체에 equals 메서드를 실행하고, 메모리 상의 객체 위치를 비교한다. 즉, 두 개의 객체가 같은 메모리 위치에 있으면 실제로 같은 객체라는 의미다. 그래서 오버라이드되게 하려면 두 객체의 메모리 위치가 같아야 한다.