깊은바다거북
개발 공부 기록
깊은바다거북
전체 방문자
오늘
어제
  • 분류 전체보기 (219)
    • JAVA (9)
    • JavaScript (15)
    • 스파르타코딩클럽 (11)
      • [내일배움단] 웹개발 종합반 개발일지 (5)
      • [내일배움캠프] 프로젝트와 트러블 슈팅 (6)
    • SQL | NoSQL (4)
    • CS 등등 (0)
    • TIL | WIL (173)
    • 기타 에러 해결 (3)
    • 내 살 길 궁리 (4)

인기 글

최근 글

최근 댓글

태그

  • DFS(깊이우선탐색)
  • 혼자 공부하는 자바스크립트
  • Linked List
  • 점화식(Recurrence Relation)
  • Trie
  • Til
  • leetcode-cli
  • tree
  • POST / GET 요청
  • Preorder Traversal(전위 순회)
  • 자료 구조
  • 시간 복잡도
  • BFS(너비우선탐색)
  • 팀 프로젝트
  • TypeScript
  • TIT (Today I Troubleshot)
  • 트러블 슈팅 Troubleshooting
  • 프로그래머스
  • BST(이진 탐색 트리)
  • Backtracking(백트래킹)
  • 최소 힙(Min Heap)
  • 자바스크립트 기초 문법
  • 01. 미니 프로젝트
  • Inorder Traversal(중위 순회)
  • 최대 힙(Max Heap)
  • Leetcode
  • 코딩테스트 연습문제
  • 재귀 함수
  • Binary Tree(이진 트리)
  • 자잘한 에러 해결
hELLO · Designed By 정상우.
깊은바다거북

개발 공부 기록

JAVA

Class literal 이란 용어를 발굴하게 된 사정

2022. 8. 25. 21:11

Class 클래스를 찾아 공식 Java 도큐먼트에 들어갔더니 Class<T>라고 소개되고 있다. 그냥 Class 클래스에 대한 페이지도 있나 찾아봤는데 없다. 다들 Class라고 소개하는 클래스는 사실 Class<T>였던 것인가..!

 

 

Class 클래스에 대하여

Class 클래스가 왜 필요한가?

내가 어떤 car1이라는 이름의 객체를 생성해서 사용하고 있는데, 얘가 속한 클래스의 이름이 뭔지 궁금할 때 쓰인다.

클래스를 동적으로 로딩하거나 디컴파일할 때 쓰이게 된다.

 

Class 클래스의 소속

java.lang.Object
	java.lang.Class<T>

위계가 이렇게 되어 있다. 즉, Object을 상속받고 lang 패키지에 속함.

 

Class 클래스는 추상 클래스인가?

아니다.

Class는 생성자를 감추고 있어서 new 연산자로 객체를 직접 만들어낼 수 없다. 이 특징이 추상 클래스같다는 생각이 들게 하지만, 다음의 2가지 이유로 아니다:

  1. 추상 클래스는 아예 인스턴스를 만들어 낼 수 없고 상속만 가능한 애들이다. Class는 인스턴스를 만들어내는 두 가지 방법이 있다.
  2. Class는 public final class Class<T> 라고 선언되어 있다. 추상 클래스의 선언 형식인 abstract class Box { … } 와 다르다.

 

그래서 Class 클래스란?

: 클래스와 인터페이스의 메타 데이터(클래스의 이름, 생성자/필드/메소드의 정보)를 관리하는 클래스를 말한다.

먼저 1) 알고 싶은 애(클래스)를 Class 인스턴스에 담아내고, 2) 만들어진 Class 인스턴스를 이용해 알고 싶은 정보를 빼내오는 형식으로 쓰면 된다.

// Class 인스턴스를 만드는 방법1: 만들어진 인스턴스가 이미 있는 경우.
Box box = new Box();
Class c = box.getClass();

// Class 인스턴스를 만드는 방법2: 만들어진 인스턴스가 없고 대신 패키지를 포함한 정확한 클래스명을 아는 경우.
Class c = Class.forName("패키지.클래스명");

클래스를 생물에 비유하자면,

1번 방식은 홍길동이라는 인간이 있을 때 거기서 인간의 DNA 설계도를 역추적하는 거고,

2번 방식은 DNA 도서관에서 “인간”이라는 이름으로 DNA 설계도를 찾는 것이다.

만들어진 Class 인스턴스 활용 간단한 예:

Class c = box.getClass();
c.getName();
c.getSimpleName();
c.getPackage().getName();

리플렉션에 사용되는 예:

Class c = box.getClass();
Constructor[] cons = c.getDeclaredConstructors();  
Field[] fields = c.getDeclaredFields(); 
Method[] methods = c.getDeclaredMethods();
// 각각 생성자, 필드, 메소드를 배열로 반환받는다.

리플렉션이란:

클래스의 생성자, 필드, 메소드 정보를 알아내는 것.

→ Class 클래스가 리플렉션을 위해 제공하는 메소드에는 getDeclared… 시리즈 외에도 getFields(), getMethods()가 있다. 상속받은 멤버까지 불러오고 싶을 때 사용한다.

 

Class.forName() 방식은 런타임 로딩이다

로드타임 동적 로딩: 하나의 클래스를 로딩하는 과정에서 필요한 다른 클래스들을 또 로딩해오는 것.

런타임 동적 로딩: (지금 실행한) 클래스를 로딩할 때 어떤 클래스도(뭐가 올지 알지 못해서) 읽어오지 않고 안의 코드가 실행되는 순간에 필요한 클래스가 로딩되는 것.

 

동적 객체 생성

: 런타임 시에 인스턴스를 만들어 내는 것을 뜻한다.

런타임 동적 로딩 방식과 짝지어져 사용된다. 즉, 코드를 작성할 때 클래스 이름을 알 수 없고 런타임 시에 클래스 이름(=타입)이 확정되게 되는 경우, 그 클래스의 객체를 만들어야 하는 경우 똑같이 동적으로 생성하는 것이다. new 연산자를 사용하지 않는다.

Class.forName() 메소드로 Class 객체를 얻은 다음, newInstance() 메소드를 호출하면 해당하는 인스턴스를 만들어낼 수 있다.

try {
	Class c = Class.forName("런타임 시 결정되는 클래스 이름"); // 만약 Box라면,
	결정된_클래스_타입 new_box = c.newInstance();
} catch { ... }

 

Class literal에 대하여

Class<T> 도큐먼트의 개괄 말미에 이런 표현이 있다.

box.getClass().getName();
Box.class.getName(); 
// box 아니고 Box인 것에 주의.

DNA 도서관에서 “인간”의 DNA를 찾는 방식인 2번 방식을, class literal을 이용해서 오른쪽과 같이 써도 무방하다고. 참고하라는 *15.8.2 of The Java™ Language Specification* 에서는 별달리 도움 되는 내용을 찾지 못하고, The Java Tutorials - Class Literals as Runtime-Type Tokens 에서 약간의 유용한 내용을 찾았다:

  • Java 5부터 제네릭이 도입되고, 그로 인해 Class가 Class<T>로 바뀐 것이었음.
  • String.class의 타입은 Class<String>이다. 즉, .class를 하면 String클래스에 대한 정보를 담고 있는 Class(타입)이 된다.
  • Class.newInstance() 메소드가 정확히 T 타입을 반환하게 되어서 활용시에 더 견고한 타입 제어를 할 수 있게 되었다.
  • class literal을 가장 잘 쓰는 방법은 런타임 타입 토큰으로 쓰는 것이다.

 

그래서 Class literal이란

: 클래스와 인터페이스와 등등의 자료형들에 대한 정보를 담은 클래스 Class 인스턴스를 만드는 것. 클래스.class 와 같이 .class를 붙여서 Class<해당 클래스> 타입으로 만들어버리는 것이다. 그렇게 해놓고 Class 클래스의 메소드를 이용해 정보를 캐내는 거지. 자바에 존재하는 거의 모든 자료형에 대해 가능하다고 한다.

구체적으로는,

  • 클래스.class, 인터페이스.class, 배열.class ⇒ Class<클래스/인터페이스/배열>
  • 원시타입.class ⇒ Class<해당 래퍼클래스>
  • void.class ⇒ Class<void>

이렇게 변환된다.

 

가장 도움되는 class literal 참고 문서:

구글링 끝에 또다른 참고 문서를 찾았다. (눈물이…)

The Java™ Tutorials - Retrieving Class Objects(Class 인스턴스를 얻어내는 방법) 이라는 페이지에 .class의 용법이 가장 명시적으로 나와있다. (공식 문서라랍시고 레퍼런스된 저 위의 두 개 문서보다 설명의 간결함과 명확성이 백배는 낫다.)

클래스의 인스턴스가 만들어지지 않은 경우, 마치 클래스 변수처럼 그냥 클래스(타입).class 해서 거기에 해당하는 Class<클래스(타입)> 인스턴스를 얻는 것이다!

예를 들면,

Class c = boolean.class;  // Boxing conversion에 의해 자동으로 래퍼클래스로 변환됨.

Class c = java.io.PrintStream.class;

Class c = int[][][].class;

String.class.getName() => "java.lang.String"

byte.class.getName()   => "byte"

이런 식으로 쓰면 된다.

아 그래서 인터페이스.class도 가능한거였구만? 그 인터페이스가 “무슨 (추상)메소드를 가지고 있는지에 대한 정보를 담은” Class 인스턴스가 생성되는 거니까. 인터페이스 자체를 인스턴스화하는 게 아니니까.


 

결론

class literal은 Class<> 인스턴스를 얻어내는 가장 간단한 하나의 방법이다.

 

 

 


주 참고문헌:

자바 튜토리얼 https://docs.oracle.com/javase/tutorial/reflect/class/classNew.html

자바 도큐먼트 - Class<T> https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#newInstance--

자바 Language Specification https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.8.2

Kephi Javatory의 포스팅 https://kephilab.tistory.com/97

    'JAVA' 카테고리의 다른 글
    • 배열 ↔ 리스트 형변환 모음
    • [프로그래머스 Lv1] 신고 결과 받기
    • 왜 Iterator가 clutter라는 걸까?
    • 책 [GOOD JAVA] 정리
    깊은바다거북
    깊은바다거북

    티스토리툴바