자바가 확장한 객체 지향
abstract 키워드 - 추상 메서드와 추상 클래스
동물 클래스가 있고 동물의 울음소리를 출력하는 추상 메서드인 울어보세요() 라는 메소드가 있다고 하자.
오리, 말, 고양이, 강아지 등의 동물들은 동물 클래스를 상속받아서 울음소리를 출력해야 한다.
우리에게는 두 문제가 있다.
- 동물 객체는 어떻게 울어야 하지? / 누가 실수로 동물 객체를 만들면 어떡하지?
- 동물 참조 변수 배열로 모든 동물을 울게 하려면 하위 클래스에서 오버라이딩할 울어보세요() 메서드가 동물 클래스에 필요한데..
이 두 문제가 추상 메서드와 추상 클래스로 한 번에 해결된다.
그뿐만 아니라 만약 동물을 상속한 하위 클래스가 울어보세요() 메서드를 오버라이딩하지 않으면
컴파일 시점에서 에러가 발생한다.
abstract 키워드에 대한 내용을 정리하면 다음과 같다.
-
추상 클래스는 인스턴스, 즉 객체를 만들 수 없다.
-
추상 메서드는 하위 클래스에게 메서드의 구현을 강제한다. 오버라이딩 강제
-
추상 메서드를 하나라도 포함하고 있는 클래스는 반드시 추상 클래스여야 한다.
생성자
클래스의 인스턴스, 즉 객체를 만들 때마다 new 키워드를 사용한다.
우선 기억해야 할 자바의 특징이 있다.
- 개발자가 아무런 생성자도 만들지 않으면 자바는 인자가 없는 기본생성자를 자동으로 만들어준다.
- 인자가 있는 생성자를 하나라도 만들면 자바는 기본 생성자를 만들어주지 않는다.
생성자는 개발자가 필요한 만큼 오버로딩해서 만들 수 있다.
또한, 우리는 생성자라고 줄여서 부르지만 정확히는 객체 생성자 메서드임을 잊지 말자.
클래스 생성 시의 실행 블록, static 블록
객체가 생성자가 있는 것이지 클래스 생성자는 없다.
그러나 클래스가 스태틱 영역에 배치될 때 실행되는 코드 블록이 있다. 바로 static 블록이다.
static 블록에서 사용할 수 있는 속성과 메서드는 당연하게 static 멤버 뿐이다.
예전에 작성한 게시글을 보면 이해할 수 있다.
T 메모리를 보면 객체 멤버에 접근할 방법이 없음을 알 수 있다.
객체 멤버는 클래스가 static 영역에 자리 잡은 후에 객체 생성자를 통해 힙에 생성된다.
클래스의 static 블록이 실행되고 있을 때는 해당 클래스의 객체는 하나도 존재하지 않기 때문에
static 블록에서는 객체 멤버에 접근할 수 없다.
당연한 이야기지만 어떤 클래스에 static 블록이 있으면,
그 블록은 객체가 생성될 때 실행되고 인스턴스 여러 개가 만들어져도 static 블록은 한 번만 실행된다.
클래스가 제일 처음 사용될 떄는 다음 중 하나이다.
- 클래스의 정적 속성을 사용할 때
- 클래스의 정적 메서드를 사용할 때
- 클래스의 인스턴스를 최초로 만들 때
왜 프로그램이 실행될 때 바로 클래스들의 정보를 T 메모리의 static 영역에 로딩하지 않고
해당 클래스가 처음 사용될 때 로딩할까?
스태틱 영역도 메모리이기 때문이다. 메모리는 최대한 늦게 사용을 시작하고 최대한 빨리 반환하는 것이 정석이다.
final 키워드
final 키워드가 나타날 수 있는 곳은 딱 세 군데다.
클래스, 변수, 메서드
-
final과 클래스
상속을 허락하지 않겠다는 의미다. -
final과 변수
변경 불가능한 상수이다. -
final과 메서드
재정의, 즉 오버라이딩을 금지한다.
interface 키워드와 implements 키워드
인터페이스는 public 추상 메서드와 public 정적 상수만 가질 수 있다.
그래서 인터페이스는 메서드에 public과 abstract,
속성에 public과 static, final을 붙이지 않아도 자동으로 자바가 알아서 붙여준다.
this 키워드
this는 객체가 자기 자신을 지칭할 때 쓰는 키워드다.
아래 내용을 기억해두자.
-
지역 변수와 속성의 이름이 같은 경우 지역 변수가 우선이다.
-
객체 변수와 이름이 같은 지역 변수가 있는 경우 객체 변수를 사용하려면 this를 접두사로 사용한다.
-
정적 변수와 이름이 같은 지역 변수가 있는 경우 정적 변수를 사용하려면 클래스명을 접두사로 사용한다.
super 키워드
바로 위 상위 클래스의 인스턴스를 지칭하는 키워드다.
super 키워드로 바로 위의 상위 클래스 인스턴스에만 접근할 수 있다.
super.super 과 같은 형태는 안된다.
클래스명.객체메서드명()
객체 메서드를 호출할 때 스택 정보를 보면
객체명.객체메서드명()
이 아닌 클래스명.객체메서드명()
임을 확인할 수 있다.
만약 객체가 a[100]
처럼 요소가 100개인 배열이라면 힙 영역에 생기는 객체는 100개가 되고
메서드도 각 객체에 따라 100개가 만들어져야 한다.
하지만 메서드가 객체에 따라 달라지는 것은 아니다. 객테 멤버 메서드에서 사용하는 객체 멤버 속성의 값만 다를 뿐이다.
메서드를 힙 영역에 100개나 만드는 것은 심각한 메모리 낭비라고 할 수 있다.
그래서 JVM은 객체 멤버 메서드를 스태틱 영역에 단 하나만 보유한다.
그리고 눈에 보이지는 않지만 메서드를 호출할 때 객체 자신을 나타내는 this 객체 참조 변수를 넘긴다.