[java] [L 배열 표기법-어디에서 왔습니까?

[L예를 들어 배열을 나타내는 데 유형을 사용하는 메시지를 자주 보았습니다 .

[Ljava.lang.Object; cannot be cast to [Ljava.lang.String;

(위는 내가 방금 뽑은 임의의 예입니다.) 이것이 배열을 의미한다는 것을 알고 있지만 구문은 어디에서 왔습니까? 왜 시작 [이지만 닫는 대괄호는 없습니까? 그리고 왜 L? 순전히 임의적입니까 아니면 그 뒤에 다른 역사적 / 기술적 이유가 있습니까?



답변

[Lsome.type.Here유형을 의미하는 배열을 의미합니다. 즉 사용되는 타입 설명 비슷 바이트 코드의 내부 에서 볼 Java 가상 머신 사양의 §4.3 -로 포착 가능한 간단한으로 . 유일한 차이점은 실제 설명자가 패키지를 표시 하는 /것이 아니라 사용 한다는 것 .입니다.

예를 들어 프리미티브의 경우 값은 다음과 같습니다. [Iint 배열의 경우 2 차원 배열은 다음과 같습니다 [[I..

클래스는 어떤 이름을 가질 수 있으므로 어떤 클래스인지 식별하기가 더 어렵습니다. 따라서 L클래스 이름은;

설명자는 필드 및 메서드 유형을 나타내는데도 사용됩니다.

예를 들면 :

(IDLjava/lang/Thread;)Ljava/lang/Object;

… 매개 변수가 int, double이고 Thread반환 유형이 다음과 같은 메서드에 해당합니다.Object

편집하다

java dissambler를 사용하여 .class 파일에서도 이것을 볼 수 있습니다.

C:>more > S.java
class S {
  Object  hello(int i, double d, long j, Thread t ) {
   return new Object();
  }
}
^C
C:>javac S.java

C:>javap -verbose S
class S extends java.lang.Object
  SourceFile: "S.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = Method       #2.#12; //  java/lang/Object."<init>":()V
const #2 = class        #13;    //  java/lang/Object
const #3 = class        #14;    //  S
const #4 = Asciz        <init>;
const #5 = Asciz        ()V;
const #6 = Asciz        Code;
const #7 = Asciz        LineNumberTable;
const #8 = Asciz        hello;
const #9 = Asciz        (IDJLjava/lang/Thread;)Ljava/lang/Object;;
const #10 = Asciz       SourceFile;
const #11 = Asciz       S.java;
const #12 = NameAndType #4:#5;//  "<init>":()V
const #13 = Asciz       java/lang/Object;
const #14 = Asciz       S;

{
S();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return
  LineNumberTable:
   line 1: 0


java.lang.Object hello(int, double, long, java.lang.Thread);
  Code:
   Stack=2, Locals=7, Args_size=5
   0:   new     #2; //class java/lang/Object
   3:   dup
   4:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   7:   areturn
  LineNumberTable:
   line 3: 0


}

그리고 원시 클래스 파일 (5 행 참조) :

여기에 이미지 설명 입력

참조 : JVM 사양에 대한 필드 설명


답변

JVM 배열 설명자.

[Z = boolean
[B = byte
[S = short
[I = int
[J = long
[F = float
[D = double
[C = char
[L = any non-primitives(Object)

기본 데이터 유형을 얻으려면 다음이 필요합니다.

[Object].getClass().getComponentType();

“객체”가 배열이 아닌 경우 null을 반환합니다. 배열인지 확인하려면 다음을 호출하십시오.

[Any Object].getClass().isArray()

또는

Class.class.isArray();


답변

이것은 유형을 표시하기 위해 JNI (및 일반적으로 JVM 내부적으로)에서 사용됩니다. 프리미티브는 단일 문자 (부울의 경우 Z, 정수의 경우 I 등)로 [표시되고 배열을 나타내며 L은 클래스 (a로 끝남 ;)에 사용됩니다.

여기 참조 : JNI 유형

편집 : 종료가없는 이유를 자세히 설명하기 ]위해이 코드는 JNI / JVM이 메서드와 서명을 빠르게 식별 할 수 있도록하는 것입니다. 파싱을 빠르게 (= 가능한 한 적은 문자)하기 위해 가능한 한 간결하게 만들어 졌으므로 [매우 간단한 배열에 사용됩니다 (사용하기에 더 나은 기호?). Iint도 똑같이 분명합니다.


답변

[L 배열 표기법-어디에서 왔습니까?

JVM 사양에서. 이것은 classFile 형식 및 기타 위치에 지정된 유형 이름의 표현입니다.

  • ‘[‘는 배열을 나타냅니다. 실제로 배열 유형 이름은[<typename> 여기서 <typename>배열의 기본 유형의 이름이다.
  • ‘L’은 실제로 기본 유형 이름의 일부입니다. 예 : 문자열은"Ljava.lang.String;" . 후행 ‘;’에 유의하십시오 !!

그리고 예, 표기법은 다른 곳에서도 문서화됩니다.

왜?

다음과 같은 이유로 내부 유형 이름 표현이 선택되었다는 것은 의심의 여지가 없습니다.

  • 콤팩트,
  • 자체 구분 (메서드 시그니처의 표현에 중요하며 ‘L’과 후행 ‘;’이있는 이유)
  • 인쇄 가능한 문자를 사용합니다 (가독성을 위해 … 가독성이 아닌 경우).

그러나 그들이 메소드 를 통해 배열 유형의 내부 유형 이름을 노출하기로 결정한 이유 는 명확하지 않습니다Class.getName() . 나는 그들이 내부 이름을보다 “인간 친화적”으로 매핑 했을 있다고 생각 합니다. 내 추측으로는 너무 늦을 때까지 고치지 못한 것 중 하나 일 뿐이라는 것입니다. (아무도 완벽하지 않습니다 … 가상의 “지능적인 디자이너”조차도 아닙니다.)


답변

나는 C가 char에 의해 취해 졌기 때문에 클래스의 다음 문자는 L입니다.


답변

이에 대한 또 다른 소스는 Class.getName () 문서입니다 . 물론 이러한 모든 사양은 서로 맞도록 만들어 졌기 때문에 일치합니다.


답변