Java가 확장한 객체지향 - (2)

이 글에서는 자바가 객체 지향을 확장하기 위해 어떠한 방법을 사용했는지 키워드 중심으로 살펴볼 것이다.

이 포스팅은 스프링 입문을 위한 자바 객체 지향의 원리와 이해(저자: 김종민)를 공부하면서 작성한 글이다.


5. instanceof 연산자


instanceof 연산자 : 만들어진 특정 객체가 특정 클래스의 인스턴스인지 물어보는 연산자이다.

  • 리턴값 : true 또는 false를 리턴한다.

  • 사용법 : ( 객체참조변수 instanceof 클래스명 )

다음은 instanceof의 예제이다.

package instanceOf01;

class 동물 {
   
}

class 조류 extends 동물 {
   
}

class 펭귄 extends 조류 {
   
}

public class Driver {
   public static void main(String[] args) {
      동물 동물객체 = new 동물();
      동물 조류객체 = new 조류();
      동물 펭귄객체 = new 펭귄();
      
      System.out.println(동물객체 instanceof 동물);

      System.out.println(조류객체 instanceof 동물);
      System.out.println(조류객체 instanceof 조류);
      
      System.out.println(펭귄객체 instanceof 동물);
      System.out.println(펭귄객체 instanceof 조류);
      System.out.println(펭귄객체 instanceof 펭귄);
      
      System.out.println(펭귄객체 instanceof Object);
   }
}

실행 결과는 모두 true이다. instanceof는 객체 참조 변수의 타입이 아닌 실제 객체 타입에 의해 처리하기 때문이다. 또한 instanceof를 자주 쓰는 코드는 좋지 않을 코드일 수 있기 때문에 리팩토링의 대상이 아닌지 점검 해봐야할 필요가 있다.

instanceof 연산자는 클래스들의 상속 관계 뿐만 아니라 인터페이스의 구현 관계에서도 동일하게 적용된다.


6. package 키워드


package 키워드는 네임스페이스(이름공간)를 만들어주는 역할을 한다.

네임스페이스(이름공간)에 대한 예제

회사의 서로 다른 사업부(고객 사업부, 마케팅 사업부)에서 이름이 동일한 Customer 클래스를 사용할 때 고객 사업부에서는 고객사업부.Customer를 사용하고 마케팅 사업부에서는 마케팅사업부.Customer로써 사용하면 Customer 클래스간에 구별이 가능해서 혼선을 없앨 수 있다 (매우 유용)


7. interface 키워드와 implements 키워드


인터페이스는 public 추상 메서드와 public 정적 상수만 가질 수 있다.

interface speakable {
   double PI = 3.14159;
   final double absoluteZeroPoint = -275.15;
   
   void sayYes();
}

그렇다면 위의 코드는 컴파일 에러를 발생시키는가? 그렇지 않다. 인터페이스는 추상 메서드와 정적 상수만 가질 수 있기에 따로 메서드에 public과 abstract, 속성에 public과 static, final을 붙이지 않아도 자동으로 컴파일러가 붙여준다.

결국 위의 예제 코드는 다음의 예제 코드와 동일하다.

interface Speakable {
   public static final double PI = 3.14159;
   public static final double absoluteZeroPoint = -275.15;
   
   public abstract void sayYes();
}

참고 : 자바 8 부터 인터페이스는 디폴트 메서드라고 하는 객체 구상 메서드와 정적 추상 메서드 또한 지원할 수 있게 언어 스펙이 바뀌었다.

[자바 8 관련 추가 정보]

람다(Lambda)

2014년 오라클에서 빅데이터와 병렬성 지원을 강화한 자바 8의 기능 중 하나이다. 람다란 함수를 의미하고, 변수에 할당할 수있다. 함수는 로직이다. 이를 삼단 논법으로 전개해 보면 결국 람다는 변수에 저장할 수 있는 로직이다. 변수는 값을 저장할 수 있고, 메서드의 인자로 쓰일 수 있고, 메서드의 반환값으로 사용할 수 있다. 결국 람다로 인해 변수에 로직을 저장할 수 있고, 로직을 메서드의 인자로 쓸 수 있고, 로직을 메서드의 반환값으로 사용할 수 있다는 결론에 도달한다.

이러한 특징들은 함수형 언어의 특징이기 때문에 자바 8이 함수형 언어의 특징 또한 추가했다는 것을 의미한다.


8. this 키워드

this는 객체가 자기 자신을 지칭할 때 쓰는 키워드이다.

예제 안에서 this가 어떻게 쓰이는지 참고 해 보자.

package This;

class 펭귄 {
   int var = 10;
   
   void test() {
      int var = 20;  // 7번째 줄
      
      System.out.println(var);   // 9번째 줄
      System.out.println(this.var); // 10번째 줄
   }
}

public class Driver {
   public static void main(String[] args) {
      펭귄 뽀로로 = new 펭귄();
      뽀로로.test();
   }
}

7번째 줄이 끝난 후의 T 메모리 스냅샷은 다음과 같다.

9번째 줄에서는 test() 메서드 내부의 지역 변수 var에 우선권이 있다. 하지만 지역 변수의 이름과 객체 변수의 이름이 같은 경우 this.var라고 하면 객체 변수 var에 저장한 값을 사용하게 된다.

이와 관련된 규칙은 다음과 같다 (꼭 기억하자!!)

  • 지역 변수와 속성(객체 변수, 정적 변수)의 이름이 같은 경우 지역 변수가 우선한다.

  • 객체 변수와 이름이 같은 지역 변수가 있는 경우 객체 변수를 사용하려면 this를 접두사로 사용한다.

  • 정적 변수와 이름이 같은 지역 변수가 있는 경우 정적 변수를 사용하려면 클래스명을 접두사로 사용한다.


9. super 키워드


단일 상속만 지원하는 자바에서 super는 바로 위 슈퍼 클래스의 인스턴스를 지칭하는 키워드이다.

서브 클래스의 인스턴스가 생성되면 슈퍼 클래스의 인스턴스 또한 생성되기 때문에 서브 클래스의 인스턴스를 참조할 때는 this, 바로 위 슈퍼 클래스의 인스턴스를 참조할 때는 super를 사용하면 된다.

package Super;

class 동물 {
   void method() {
      System.out.println("동물");
   }
}

class 조류 extends 동물 {
   void method() {
      super.method();   // 11번째 줄
      System.out.println("조류");
   }
}

class 펭귄 extends 조류 {
   void method() {
      super.method();   // 18번째 줄
      System.out.println("펭귄");
   }
}

public class Driver {
   public static void main(String[] args) {
      펭귄 뽀로로 = new 펭귄();
      뽀로로.method();
   }
}

11번째 줄과 18번째 줄에서 super 키워드를 이용해 바로 위 슈퍼 클래스의 인스턴스 메서드를 호출하고 있음을 볼 수 있다.

super를 사용할 때 한가지 주의해야 될 점은 super.super 형태로 상위의 상위 클래스의 인스턴스에 접근하는건 불가능하다는 점을 주의해야한다.