초식 scala 반사
주어진 형식 이나 대상 인 스 턴 스 는 scala 를 통 해 실 행 될 때 반 사 됩 니 다.1)실 행 될 때 유형 정 보 를 얻 을 수 있 습 니 다.2)유형 정 보 를 통 해 새로운 대상 을 예화 한다.3)대상 에 접근 하거나 호출 하 는 방법 과 속성 등.다음은 운행 시 반사 되 는 기능 을 예 로 들 어 논술 한다.
런 타임 형식 정보 가 져 오기
scala 가 실 행 될 때 유형 정 보 는 TypeTag 대상 에 저 장 됩 니 다.컴 파일 러 는 컴 파일 과정 에서 유형 정 보 를 TypeTag 에 저장 하고 실행 기간 에 가 져 옵 니 다.우 리 는 typeTag 방법 을 통 해 TypeTag 형식 정 보 를 얻 을 수 있 습 니 다.
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> typeTag[List[Int]]
res0: reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[scala.List[Int]]
scala> res0.tpe
res1: reflect.runtime.universe.Type = scala.List[Int]
상기 scala REPL 에 따 르 면 typeTag 방법 으로 List[Int]형식의 TypeTag 대상 을 얻 을 수 있 습 니 다.이 대상 은 List[Int]의 상세 한 유형 정 보 를 포함 하고 있 습 니 다.TypeTag 대상 의 tpe 방법 을 통 해 Type 대상 이 구체 적 인 유형 정 보 를 밀봉 하면 이 Type 대상 의 유형 정 보 는 유형 매개 변수 Int 까지 정확 합 니 다.유형 정보 만 얻 는 것 이 라면 더 간편 한 방법 이 있다 면 type:Of 방법 을 통 해.
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> typeOf[List[Int]]
res0: reflect.runtime.universe.Type = scala.List[Int]
이때 어떤 사람 은 type:Tag 방법 은 구체 적 인 유형 을 전달 해 야 하 는데 유형 을 미리 알 고 TypeTag 를 해 야 무슨 소 용이 있 느 냐 고 묻는다.우 리 는 임의의 대상 의 유형 정 보 를 얻 을 수 있 는 방법 을 써 도 무방 하 다.
scala> val ru = scala.reflect.runtime.universe
ru: scala.reflect.api.JavaUniverse = scala.reflect.runtime.JavaUniverse@6dae22e7
scala> def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
getTypeTag: [T](obj: T)(implicit evidence$1: ru.TypeTag[T])ru.TypeTag[T]
scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)
scala> val theType = getTypeTag(list).tpe
theType: ru.Type = List[Int]
위의 scala REPL 에 따 르 면 방법 getTypeTag 는 임의의 대상 의 유형 정 보 를 얻 을 수 있 습 니 다.주의 방법 중의 문맥 정의
T: ru.TypeTag
는 T 에서 TypeTag[T]로 의 암시 적 전환 이 존재 한 다 는 것 을 나타 냅 니 다.앞에서 말 했 듯 이 TypeTag 대상 은 컴 파일 기간 에 컴 파일 러 에 의 해 생 성 되 었 습 니 다.이 문맥 정 의 를 추가 하지 않 으 면 컴 파일 러 는 T 에 TypeTag 대상 을 생 성하 지 않 습 니 다.물론 REPL 에 표 시 된implicit evidence$1: ru.TypeTag[T]
처럼 암시 적 인 파 라 메 터 를 통 해 문맥 정 의 를 대체 할 수도 있다.유형 정보(Type instance)를 얻 으 면 이 Type 대상 을 통 해 더 자세 한 유형 정 보 를 조회 할 수 있 습 니 다.scala> val decls = theType.declarations.take(10)
decls: Iterable[ru.Symbol] = List(constructor List, method companion, method isEmpty, method head, method tail, method ::, method :::, method reverse_:::, method mapConserve, method ++)
여기에서 TypeTag 대상 이 Type 대상 을 봉 인 했 음 을 알 수 있 습 니 다.Type 대상 을 통 해 방법 과 속성 등 상세 한 유형 정 보 를 얻 을 수 있 습 니 다.typeTag 방법 을 통 해 TypeTag 대상 을 얻 을 수 있 습 니 다.typeOf 방법 을 통 해 Type 대상 을 얻 을 수 있 습 니 다.컴 파 일 러 에 의 해 지 워 지지 않 은 완전한 scala 형식 정 보 를 포함 하고 이에 대응 하 는 곳 을 포함 합 니 다.지 운 후의 유형 정 보 를 얻 으 려 면 전통 적 인 방법 은 자바 의 반사 체 제 를 통 해 이 루어 질 수 있 지만 scala 도 이 기능 을 제공 합 니 다.classTag 방법 을 통 해 ClassTag 대상 을 얻 을 수 있 습 니 다.ClassTag 는 지 운 후의 유형 정 보 를 밀봉 하고 classOf 방법 을 통 해 Class 대상 을 얻 을 수 있 습 니 다.이것 은 자바 반사 중의 Class 대상 과 일치 합 니 다.
scala> import scala.reflect._
import scala.reflect._
scala> val clsTag = classTag[List[Int]]
clsTag: scala.reflect.ClassTag[List[Int]] = scala.collection.immutable.List
scala> clsTag.runtimeClass
res0: Class[_] = class scala.collection.immutable.List
scala> val cls = classOf[List[Int]]
cls: Class[List[Int]] = class scala.collection.immutable.List
scala> cls.[tab ]
asInstanceOf asSubclass cast desiredAssertionStatus getAnnotation
getAnnotations getCanonicalName getClassLoader getClasses getComponentType
getConstructor getConstructors getDeclaredAnnotations getDeclaredClasses getDeclaredConstructor
getDeclaredConstructors getDeclaredField getDeclaredFields getDeclaredMethod getDeclaredMethods
getDeclaringClass getEnclosingClass getEnclosingConstructor getEnclosingMethod getEnumConstants
getField getFields getGenericInterfaces getGenericSuperclass getInterfaces
getMethod getMethods getModifiers getName getPackage
getProtectionDomain getResource getResourceAsStream getSigners getSimpleName
getSuperclass getTypeParameters isAnnotation isAnnotationPresent isAnonymousClass
isArray isAssignableFrom isEnum isInstance isInstanceOf
isInterface isLocalClass isMemberClass isPrimitive isSynthetic
newInstance toString
상기 scala REPL 에서 볼 수 있 듯 이 ClassTag 대상 은 Class 대상 을 포함 하고 있 으 며,Class 대상 을 통 해 지 워 진 형식의 정보 만 얻 을 수 있 으 며,scala REPL 에서 tab 로 보완 하면 Class 대상 을 통 해 얻 을 수 있 는 정 보 를 볼 수 있다.
런 타임 형식 예화
Type 대상 을 통 해 지우 지 않 은 상세 한 유형 정 보 를 얻 을 수 있다 는 것 을 알 고 있 습 니 다.다음은 Type 대상 의 정 보 를 통 해 구조 방법 을 찾 고 유형 을 예화 하 는 대상 을 찾 습 니 다.
scala> case class Person(id: Int, name: String)
defined class Person
scala> val ru = scala.reflect.runtime.universe
ru: scala.reflect.api.JavaUniverse = scala.reflect.runtime.JavaUniverse@3e9ed70d
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
m: ru.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClassLoader@a57fc5f ...
scala> val classPerson = ru.typeOf[Person].typeSymbol.asClass
classPerson: ru.ClassSymbol = class Person
scala> val cm = m.reflectClass(classPerson)
cm: ru.ClassMirror = class mirror for Person (bound to null)
scala> val ctor = ru.typeOf[Person].declaration(ru.nme.CONSTRUCTOR).asMethod
ctor: ru.MethodSymbol = constructor Person
scala> val ctorm = cm.reflectConstructor(ctor)
ctorm: ru.MethodMirror = constructor mirror for Person.<init>(id: scala.Int, name: String): Person (bound to null)
scala> val p = ctorm(1, "Mike")
p: Any = Person(1,Mike)
위의 scala REPL 코드 와 같이 Type 대상 을 통 해 관련 정 보 를 얻 으 려 면 반드시 Mirror 를 빌려 야 한다.Mirror 는 등급 별로 구분 되 는데 ClassLoader Mirror,ClassMirror,InstanceMirror,ModuleMirror,MethodMirror,FieldMirror 가 있다.ClassLoader Mirror 를 통 해 ClassMirror,InstanceMirror,ModuleMirror,MethodMirror,FieldMirror 를 만 들 수 있다.ClassMirror,InstanceMirror 를 통 해 MethodMirror,FieldMirror 를 만 들 수 있 습 니 다.ModuleMirror 는 하나의 대상 을 처리 하 는 데 사 용 됩 니 다.보통 object 에서 정의 합 니 다.상기 코드 에서 알 수 있 듯 이 먼저 ClassLoader Mirror 를 가 져 온 다음 에 이 Mirror 를 통 해 ClassMirror 를 만 들 고 MethodMirror 를 계속 만 들 며 이 MethodMirror 를 통 해 구조 함 수 를 호출 합 니 다.하나의 Mirror 에서 다른 Mirror 를 만 들 려 면 Symbol 을 지정 해 야 합 니 다.Symbol 은 바 인 딩 이름과 하나의 실체 입 니 다.ClassSymbol,MethodSymbol,FieldSymbol 등 이 있 습 니 다.Symbol 의 획득 은 Type 대상 방법 으로 조회 합 니 다.예 를 들 어 상기 코드 에서 declaration 방법 으로 구조 함수 의 Symbol 을 조회 합 니 다.
런 타임 클래스 구성원 접근
다음 예 를 들 어 방문 실행 시 클래스 구성원 을 논술 합 니 다.마찬가지 로 저 희 는 FieldMirror 를 점차적으로 만들어 서 클래스 구성원 을 방문 해 야 합 니 다.
scala> case class Person(id: Int, name: String)
defined class Person
scala> val ru = scala.reflect.runtime.universe
ru: scala.reflect.api.JavaUniverse = scala.reflect.runtime.JavaUniverse@3e9ed70d
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
m: ru.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClassLoader@a57fc5f ...
scala> val p = Person(1, "Mike")
p: Person = Person(1,Mike)
scala> val nameTermSymb = ru.typeOf[Person].declaration(ru.newTermName("name")).asTerm
nameTermSymb: ru.TermSymbol = value name
scala> val im = m.reflect(p)
im: ru.InstanceMirror = instance mirror for Person(1,Mike)
scala> val nameFieldMirror = im.reflectField(nameTermSymb)
nameFieldMirror: ru.FieldMirror = field mirror for Person.name (bound to Person(1,Mike))
scala> nameFieldMirror.get
res0: Any = Mike
scala> nameFieldMirror.set("Jim")
scala> p.name
res2: String = Jim
위 코드 와 같이 등급 별 ClassLoader Mirror->InstanceMirror->FieldMirror 를 통 해 FieldMirror 를 얻 고 Type 대상 호출 방법
declaration(ru.newTermName("name"))
을 통 해 name 필드 의 Symbol 을 얻 으 며 FieldMirror 의get
과set
방법 으로 구성원 변 수 를 방문 하고 수정 합 니 다.이렇게 많아문 제 는 컴 파일 러 가 지 운 후의 유형 정 보 를 방문 하 느 냐,지 운 전의 유형 정 보 를 방문 하 느 냐 하 는 것 이다.지 운 후의 유형 정 보 를 방문 하 느 냐,자바 와 scala 의 반 사 를 사용 하 느 냐 하 는 것 이다.그러나 지 운 전의 유형 정 보 를 방문 하려 면 scala 의 반 사 를 사용 해 야 한다.자바 의 반 사 는 지 워 지기 전의 정 보 를 모 르 기 때문이다.
밤 을 들 어 한 걸음 한 걸음 분석 하고 먼저 하나의 기본 클래스 A 를 정의 한다.이 는 추상 적 인 유형의 구성원 T 를 포함 한 다음 에 각각 두 개의 키 클래스 B 와 C 를 파생 시킨다.
scala> class A {
| type T
| val x: Option[T] = None
| }
defined class A
scala> class B extends A
defined class B
scala> class C extends B
defined class C
현재 B 와 C 의 한 대상 을 각각 실례 화하 고 추상 적 인 유형 T 를 String 으로 구체화 한다.
scala> val b = new B { type T = String }
b: B{type T = String} = $anon$1@446344a8
scala> val c = new C { type T = String }
c: C{type T = String} = $anon$1@195bc0a4
현재 자바 의 반사 체 제 를 통 해 대상 b 와 c 의 운행 시 유형 이 부자 관계 인지 판단 합 니 다.
scala> b.getClass.isAssignableFrom(c.getClass)
res3: Boolean = false
자바 의 반사 판단 대상 c 의 운행 시 유형 이 대상 b 의 운행 시 유형의 하위 클래스 가 아 닌 것 을 볼 수 있 습 니 다.그러나 우리 의 정 의 를 보면 대상 c 의 유형 은 대상 b 의 유형의 하위 클래스 여야 한다.여기 서 우 리 는 컴 파일 러 를 생각 할 것 이다.실제 대상 b 와 c 를 예화 할 때 실제 적 으로 익명 류 를 통 해 예화 되 었 고 처음에 유형 정 보 를 컴 파일 할 때 지 워 져 익명 류 로 바 뀌 었 다.다음은 scala 의 반사 체 제 를 통 해 대상 b 와 c 의 운행 시 유형 이 부자 관계 인지 판단 한다.
scala> val ru = scala.reflect.runtime.universe
ru: scala.reflect.api.JavaUniverse = scala.reflect.runtime.JavaUniverse@3e9ed70d
scala> def isSubClass[T: ru.TypeTag, S: ru.TypeTag](x: T, y: S): Boolean = {
| val leftTag = ru.typeTag[T]
| val rightTag = ru.typeTag[S]
| leftTag.tpe <:< rightTag.tpe
| }
isSubClass: [T, S](x: T, y: S)(implicit evidence$1: ru.TypeTag[T], implicit evidence$2: ru.TypeTag[S])Boolean
scala> isSubClass(c, b)
res5: Boolean = true
상기 코드 에서 볼 수 있 듯 이 scala 의 반 사 를 통 해 얻 은 유형 정 보 는 우리 가 처음에 정의 한 것 에 부합된다.따라서 scala 에 서 는 자바 의 반 사 를 사용 하지 않 고 scala 의 반 사 를 사용 하 는 것 이 좋 습 니 다.컴 파일 후 자바 의 반 사 를 통 해 얻 은 결 과 는 생각 보다 그렇지 않 을 수 있 기 때 문 입 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.