자바가 생각보다 똑똑한 놈이라는 사실을 알게 해준 이번 챕터..
1. class 생성자 : 없으면 기본, 있으면 없음.
생성자는 곧 new 키워드이다. 인스턴스를 생성하기 위해선 new 클래스명(); 메쏘드를 호출하여 객체를 생성한 뒤 참조 변수에 이 주소를 할당해주어야 한다.
package oopStudy05;
public class NewMethod {
// Basic : 기본 생성자
MyClass c = new MyClass();
}
class MyClass {
String name;
}
위 코드를 살펴보면, 클래스 MyClass에서 MyClass() method를 설정하지 않았는데 new MyClass()를 호출할 수 있는 것을 알 수 있다. 자바는 class 설정 시에 생성자 메쏘드를 설정해주지 않으면 자동으로 기본 생성자를 생성해준다는 것을 알 수 있다. 아마 MyClass() {} 한 줄을 추가해주는 것이겠지.
그러나 아래 코드를 보자.
package oopStudy05;
public class NewMethod {
// ERROR! 다른 생성자가 있으면 기본 생성자는 만들어지지 않는다
// MyClass c = new MyClass();
MyClass c = new MyClass("c");
}
class MyClass {
String name;
MyClass(String name) {
this.name = name;
}
}
내가 MyClass(String name)이라는 생성자를 따로 정의했다. name이라는 인자 하나를 받아서 property를 설정해주는 간단한 생성자다. 그러나 그와 동시에 MyClass()라는 기본 생성자는 이용이 불가능하게 되었다.
생성자가 없으면 자바는 기본으로 빈 생성자를 만들어주지만, 생성자가 하나라도 설정되어있을 경우 자바는 기본 생성자를 만들어주지 않는다.
생성자와 관련한 자바의 특성 중 하나이다.
생성자는 개발자가 원하는 만큼, 필요한 만큼 여러 개 오버로딩 할 수 있다. MyClass() {} 기본 생성자를 개발자가 직접 추가하면 위 코드도 정상 동작될 것이라는 소리다.
2. static 블록 : class가 필요할 때 한 번만 실행된다.
class 선언 시에 class 내부에 static 블록을 설정할 수 있다.
package oopStudy05;
public class StaticBlock {
public static void main(String[] args) {
StaticBlockClass s1 = new StaticBlockClass();
StaticBlockClass s2 = new StaticBlockClass();
}
}
class StaticBlockClass {
static {
System.out.println("클래스가 스태틱 영역에 올라갈 때 한 번만 출력됩니다.");
}
}
sout 안에 설명한 그대로다. 자바에서 코드를 실행하며, 어떤 클래스의 변수 값이 필요하거나 인스턴스를 생성할 필요가 있을때 해당 클래스가 스태틱 영역에 올라가게 된다. 그 때 단 한 번만 실행되는 코드가 class 선언부의 static 블록 내부 코드이다. '한 번만 실행된다'가 포인트이므로, 위 예에서 s1과 s2 총 2개의 인스턴스를 만들었다 해도 결과로 출력되는 것은 한 줄이라는 것을 예상할 수 있다.
클래스의 인스턴스를 만드는 상황이 아니더라도 스태틱 영역에 클래스가 올라가는 상황이라면 결국 static 블록이 실행된다.
package oopStudy05;
public class StaticBlock {
public static void main(String[] args) {
System.out.println("starting main method..");
System.out.println(StaticBlockClass.staticNum);
}
}
class StaticBlockClass {
static int staticNum = 0;
static {
System.out.println("클래스가 스태틱 영역에 올라갈 때 한 번만 출력됩니다.");
}
}
위 코드의 결과는 아래와 같다.
starting main method..
클래스가 스태틱 영역에 올라갈 때 한 번만 출력됩니다.
0
3. final 키워드 : 더이상의 수정은 naver...
클래스, 변수, method 앞에 final 키워드가 붙을 수 있다. 각각의 기능은 아래와 같다.
클래스 : 상속을 허락하지 않음
변수 : 변경 불가능한 상수로 취급
메서드 : 오버라이딩 금지
셋 다 final 키워드가 붙은 무언가에 대해 추가 작업을 하는 것을 금지한다고 볼 수 있다. final 키워드가 붙은 클래스를 상속받거나, 변수에 다른 값을 할당하거나, 메소드를 재정의 할 경우 컴파일러가 오류 메세지를 준다.
4. instanceof 연산자 : 실제 객체 타입에 따라 처리
instanceof는 어떤 객체 참조 변수가 특정 클래스의 인스턴스인지 여부를 알려주는 연산자이다. 하위 클래스 타입을 갖는 객체는 상위 클래스의 인스턴스로 역시 취급된다. 이 때, 객체 참조 변수의 타입이 아닌 힙에 실제로 생성된 인스턴스의 타입에 따라 true/false를 반환한다는 것을 명심해야한다.
아래 예시에서 결과물이 모두 true임을 천천히 보며 이해하면 될 것이다. a2의 참조 변수 타입은 MyAnimal이지만 실제 생성된 인스턴스는 MyAnimal_2이므로 instanceof 연산 결과가 true이다.
package oopStudy05;
public class InstanceOf {
public static void main(String[] args) {
MyAnimal a0 = new MyAnimal();
MyAnimal_1 a1 = new MyAnimal_1();
MyAnimal a2 = new MyAnimal_2();
System.out.println(a0 instanceof MyAnimal);
System.out.println(a1 instanceof MyAnimal);
System.out.println(a1 instanceof MyAnimal_1);
System.out.println(a2 instanceof MyAnimal);
System.out.println(a2 instanceof MyAnimal_1);
System.out.println(a2 instanceof MyAnimal_2);
}
}
class MyAnimal {
}
class MyAnimal_1 extends MyAnimal {
}
class MyAnimal_2 extends MyAnimal_1 {
}
5. abstract class : 상위 클래스에서
동물 클래스를 만들고, 여러가지 종들에게 상속시켜 클래스 구현을 시키고 싶다. 그래서 먼저 Animal class를 설계했는데,
package oopStudy05;
public class Animal {
public void speak() {
System.out.println("동물이 우는 법?");
}
}
class Dog extends Animal {
@Override
public void speak() {
System.out.println("멍멍");
}
}
class Cat extends Animal {
@Override
public void speak() {
System.out.println("야옹");
}
}
동물이 우는 법이 뭘까? 애매하다.
여기서 나오는 것이 abstract 키워드이다. 추상 클래스와 메소드를 만들어 주는 키워드로, 하위 클래스들에게 구현해야할 메쏘드 자체를 정해놓되 상위 클래스 자체에서는 실제 구현을 하지 않는 형태로 위와 같이 애매한 문제를 해결해준다.
처음 코드를 아래와 같이 수정하면 깔끔하다.
package oopStudy05;
public abstract class Animal {
public abstract void speak();
}
class Dog extends Animal {
@Override
public void speak() {
System.out.println("멍멍");
}
}
class Cat extends Animal {
@Override
public void speak() {
System.out.println("야옹");
}
}
참고로 추상 클래스는 인스턴스를 생성할 수 없다. 실제 구현내용이 없는 클래스의 인스턴스를 사전에 생성하지 못하게 해놓은 것이다.
추상 클래스를 상속받은 하위 클래스는 추상 클래스 안에 설정된 abstact method를 전부 구현해야한다. 만약 하나라도 구현하지 않으면 상속받은 클래스 역시 abstract class가 된다.
6. this : 자기 자신 인스턴스, super : 상위 인스턴스
자바에서 this는 자기 자신을, super은 한 단계 상위 클래스의 인스턴스를 가리킨다. this는 클래스 내부 메소드에서 새로 정의한 지역변수와 클래스의 객체변수를 구분하는데 주로 이용하고, super은 메쏘드 오버라이딩 등에서 상위 클래스의 논리를 재사용할 때 이용된다.
package oopStudy05;
public class ThisAndSuper extends SuperClass {
int property = 1;
void someMethod() {
int property = 2;
System.out.println(property);
System.out.println(this.property);
System.out.println(super.superProperty);
super.superMethod();
}
}
class SuperClass {
int superProperty = 0;
void superMethod() {
System.out.println("상위 클래스 method");
}
}
위와 같은 클래스가 있다고 할 때, ThisAndSuper 인스턴스를 하나 생성한 뒤 someMethod()를 호출했을 때 결과가 어떻게 나올지 생각하면 this와 super을 잘 이해했다고 볼 수 있겠다.