이 기사는 Java 반사 메커니즘에 대한 포괄적 인 소개를 제공하는 것을 목표로합니다. 이 기사를 통해 Java Reflection의 관련 내용에 대한 포괄적 인 이해가 있기를 바랍니다.
이 기사를 읽기 전에 " Java Generics를 재 inderving " 을 참조하십시오.
머리말
Java 반사 메커니즘은 매우 강력한 기능입니다. Spring 및 Mybatis와 같은 많은 대규모 프로젝트에서 반사를 볼 수 있습니다. 반사 메커니즘을 통해 작동 중에 객체 유형 정보를 얻을 수 있습니다. 이 기능을 사용하여 공장 모드 및 프록시 모드와 같은 설계 패턴을 구현할 수 있으며 Java Generic Erasure와 같은 고통스러운 문제를 해결할 수도 있습니다. 이 기사에서는 실제 응용의 관점에서 Java 반사 메커니즘을 적용 할 것입니다.
반사 기준
추신 :이 기사에서는 독자들이 반사 메커니즘 API에 대해 어느 정도 이해해야합니다. 전에 노출되지 않은 경우 공식 문서의 빠른 시작을 먼저 살펴 보는 것이 좋습니다.
반사 메커니즘을 적용하기 전에 먼저 반사 Class 객체에 해당하는 방법을 살펴 보겠습니다. Java에는 객체의 반사 클래스를 얻는 세 가지 방법이 있습니다.
getclass 메소드에 의해
Java에서는 각 Object 에는 getClass 메소드가 있습니다. GetClass 메소드를 통해이 개체의 해당 반사 클래스를 얻을 수 있습니다.
문자열 s = "ziwenxie"; class <?> c = s.getClass ();
또한 Class 클래스의 정적 메소드 forName 호출 할 수도 있습니다.
class <?> c = class.forname ( "java.lang.string");
또는 .class 직접 사용할 수 있습니다.
클래스 <?> c = string.class;
이 기사의 시작 부분에서, 우리는 반사의 주요 이점 중 하나는 작동 중에 객체 유형 정보를 얻을 수 있다는 것입니다. 예제와 함께 자세히 살펴 보겠습니다.
먼저 typeinfo.interfacea 패키지 아래에 새 인터페이스 A 만듭니다.
package typeinfo.interfacea; public interface a {void f (); } 그런 다음 typeinfo.packageaccess 패키지 아래에 새 인터페이스 C 만듭니다. 인터페이스 C 인터페이스 A 에서 상속하고 테스트를위한 몇 가지 다른 방법을 만들었습니다. 다음 방법의 권한은 다릅니다.
package typeinfo.packageAccess; import typeinfo.interfacea.a; 클래스 C는 {public void f () {system.out.println ( "public cf ()"); } public void g () {system.out.println ( "public cg ()"); } protected void v () {system.out.println ( "Protected CV ()"); } void u () {system.out.println ( "package cu ()"); } private void w () {system.out.println ( "private cw ()"); }} public class hiddenc {public static a makea () {return new C (); }} callHiddenMethod() 메소드에서 getDeclaredMethod() 메소드 이름에 따라 객체를 참조하는 메소드를 얻는 데 사용되는 몇 가지 새로운 API를 사용한 다음 invoke() 메소드를 호출하여 객체의 관련 메소드를 트리거 할 수 있습니다.
Package TypeInfo; import typeinfo.interfacea.a; import typeinfo.packageaccess.hiddenc; import java.lang.reflect.method; public class hiddenimplementation {public static void main (String [] args) 예외 {a = hiddenc.makea (); af (); System.out.println (a.getClass (). getName ()); // 죄송합니다! 반사는 여전히 우리가 g ()를 호출 할 수있게 해줍니다 : callhiddenmethod (a, "g"); // 접근성이 떨어지는 메소드까지도! CallHiddenMethod (a, "u"); CallHiddenMethod (A, "V"); CallHiddenMethod (a, "w"); } static void CallHiddenMethod (Object A, String MethodName) Exception {Method g = a.getClass (). getDeclaredMethod (MethodName); g.setAccessible (true); g.invoke (a); }} 출력 결과에서 public , default , protect 또는 pricate 방법이든 반사 클래스를 통해 자유롭게 호출 할 수 있음을 알 수 있습니다. 물론, 우리는 단지 강력한 반사의 힘을 보여 주어야하며,이 기술은 실제 개발에서 권장되지 않습니다.
public cf () typeinfo.packageaccess.cpublic cg () package cu () protected cv () private cw () private cw ()
우리는 다음과 같은 비즈니스 시나리오를 가지고 있습니다. 일반 컬렉션 클래스 List<Class<? extends Pet>> . 우리는이 컬렉션 클래스에 얼마나 많은 특정 Pet 있는지 계산해야합니다. Java Generic 삭제로 인해 List<? extends Pet> 컴파일러가 정적 유형 검사를 수행 한 후 JVM은 컬렉션의 모든 물체를 실행 중에 Pet List<? extends Pet> 취급하지만 Pet Cat 인지 개 Dog 나타내는 지 알 수 없으므로 실행 중에 물체의 유형 정보가 실제로 손실됩니다. 추신 : 일반 삭제에 대해 : 이전 기사에 자세한 설명이 있습니다. 관심있는 친구들을 볼 수 있습니다.
위의 예제를 구현하기 위해 먼저 여러 클래스를 정의합니다.
Public Class PET 확장 개인 {public Pet (String Name) {super (name); } public pet () {super (); }} public class cat은 pet {public cat (문자열 이름) {super (name); } public cat () {super (); }} public class dog 확장 pet {public dog (문자열 이름) {super (name); }} 공공 계급 이집트 마우는 고양이 {public egyptianmau (문자열 이름) {super (name); } public EgyptianMau () {super (); }} public class mutt 확장 개 {public mutt (문자열 이름) {super (name); } public mutt () {super (); }} Pet 클래스는 Individual 으로부터 상속됩니다. Individual 클래스의 구현은 조금 더 복잡합니다. Comparable 인터페이스를 구현하고 클래스 비교 규칙을 재정의했습니다. 우리가 잘 이해하지 못하면 중요하지 않습니다. 우리는 그것을 추상화 했으므로 구현 원칙을 이해하지 못하더라도 중요하지 않습니다.
공개 클래스 개별 구현 비슷한 <개인> {private static long counter = 0; 개인 최종 긴 ID = 카운터 ++; 개인 문자열 이름; // 이름은 선택적 공개 개인 (문자열 이름) {this.name = 이름; } public plubly () {} public String toString () {return getClass (). getSimplename () + (name == null? "": "" + name); } public long id () {return id; } public boolean equals (Object o) {return o instance of incians && id == ((개인) o) .id; } public int hashcode () {int result = 17; if (name! = null) {result = 37 * result + name.hashcode (); } result = 37 * result + (int) id; 반환 결과; } public int compareto (개인 arg) {// 클래스 이름별로 비교 : String first = getClass (). getSimplename (); 문자열 argfirst = arg.getClass (). getSimplename (); int firstCompare = first.compareto (Argfirst); if (firstCompare! = 0) {return firstompare; } if (name! = null && arg.name! = null) {int secondarycompare = name.compareto (arg.name); if (secendcompare! = 0) {return secondarycompare; }} return (arg.id <id? -1 : (arg.id == id? 0 : 1)); }} 아래는 추상적 인 클래스 PetCreator 입니다. 앞으로 arrayList() 메소드를 호출하여 관련 Pet 클래스 모음을 직접 얻을 수 있습니다. 여기에서는 위에서 언급하지 않은 newInstance() 메소드를 사용합니다. 클래스 클래스가 실제로 언급하는 클래스의 인스턴스를 반환합니다. 이것이 무엇을 의미합니까? 예를 들어, new Dog().getClass().newInstance() 와 Direct new Dog() 선언하는 것은 동일합니다.
공개 초록 클래스 Petcreator {Private Random Rand = New Random (47); // 생성 할 애완 동물의 다른 게티프 목록 : 공개 초록 목록 <class <? PET를 확장하십시오 >> getTypes (); public pet randompet () {// 하나의 임의의 pet int n = rand.nextint를 만듭니다 (gettypes (). size ()); {return getTypes (). get (n) .newinstance (); } catch (InstantiationException e) {throw new runtimeexception (e); } catch (delegalaccessexception e) {throw new runtimeexception (e); }} public pet [] CreateArray (int size) {pet [] result = new Pet [size]; for (int i = 0; i <size; i ++) {result [i] = randompet (); } 반환 결과; } public arraylist <Pet> arrayList (int size) {arrayList <Pet> 결과 = new ArrayList <Pet> (); collections.addall (결과, CreateArray (size)); 반환 결과; }} 다음으로 위의 추상 클래스를 구현하고 다음 코드를 설명해 봅시다. 다음 코드에서는 두 가지 컬렉션 클래스, allTypes 및 types 선언합니다.이 중 allTypes 에는 위에 선언 된 모든 클래스가 포함되어 있지만 특정 유형은 실제로 Mutt 와 EgypianMau 두 가지 유형에 불과하므로 실제로 new 얻는 데 필요한 애완 동물은 types 에 포함 된 유형입니다. 앞으로 getTypes() 호출하여 types 에 포함 된 유형을 얻을 수 있습니다.
공개 클래스 LeteralPetCreator는 Petcreator {@suppresswarnings ( "확인되지 않은") 공개 정적 최종 목록 <class <? PET를 확장하십시오 >> Alttypes = collections.unmodifiablelist (Arrays.Aslist (pet.class, dog.class, cat.class, mutt.class, Egyptianmau.class)); 개인 정적 최종 목록 <class <? PET 확장 >> 유형 = AltTypes.Sublist (Alttypes.indexof (Mutt.class), Alttypes.size ()); 공개 목록 <class <? PET를 확장하십시오 >> getTypes () {return type; }} 전체 논리가 완료되었으며, 마지막으로 세트의 관련 Pet 클래스 수를 계산하는 데 사용되는 TypeCounter 클래스를 구현합니다. 반사 클래스가 반사 클래스의 서브 클래스 또는 간접 하위 클래스임을 결정할 수있는 isAssignalbeFrom() 메소드를 설명하십시오. 이름에서 알 수 있듯이 getSuperclass() 반사 클래스의 상위 클래스를 얻는 것입니다.
공개 클래스 타이프 카운터는 Hashmap <class <?>, integer> {private class <?> BaseType을 확장합니다. public typecounter (class <?> basetype) {this.baseType = baseType; } public void count (object obj) {class <?> type = obj.getClass (); if (! baseType.isAssignableFrom (type)) {wrach new runtimeexception (OBJ + "잘못된 유형" + type + "는" + Basetype의 유형 또는 하위 유형이어야합니다); } countclass (유형); } private void countclass (class <?> type) {정수 수량 = get (type); put (유형, 수량 == NULL? 1 : 수량 + 1); class <?> superclass = type.getSuperClass (); if (superclass! = null && baseType.isAssignableFrom (superclass)) {countclass (SuperClass); }} @override public String toString () {StringBuilder result = new StringBuilder ( "{"); for (map.entry <class <?>, integer> pair : entryset ()) {result.append (pair.getKey (). getSimplename ()); result.Append ( "="); result.append (pair.getValue ()); result.append ( ","); } result.delete (result.length () -2, result.length ()); result.Append ( "}"); return result.toString (); }}요약
위의 내용은 Java Reflection 메커니즘의 예제 코드 공유에 대한이 기사의 모든 내용이며, 모든 사람에게 도움이되기를 바랍니다. 관심있는 친구들은이 사이트를 계속 참조 할 수 있습니다.
Java 프로그래밍 및 인쇄 쇼핑 영수증 구현 코드
Java의 참조 및 동적 프록시 구현에 대한 자세한 설명
Lunar Eclipse의 간단한 코드 공유를 구현하기위한 Java 프로그래밍
단점이 있으면 메시지를 남겨 두십시오. 이 사이트를 지원해 주신 친구들에게 감사드립니다!