Java 반사 Java.lang.reflect.Method

35747 단어 Java 반사 시리즈
앞의 글은 Class의 구성원 변수(java.lang.reflect.Field의 상용 사용 방식과 주의사항을 다루었다.Class의 방법java.lang.reflect.Method에 대해 살펴보겠습니다.
소개하다.
방법은 실행 가능한 코드입니다. 계승된 코드일 수도 있고, 다시 불러오거나, 컴파일러에 의해 강제로 숨겨질 수도 있습니다.그러나 반대로 반사 코드는 방법의 선택을 특정한 클래스에 제한하고 부류를 고려하지 않는다. 비록 우리가 부류를 찾을 수 있지만 이것은 방법의 반사로 할 수 있는 것이 아니기 때문에 여기서 문제를 일으키기 쉽다.
Method 선언 가져오기
방법의 성명은 방법 이름, 설명자, 매개 변수, 되돌아오는 유형, 이상표를 포함한다.클래스java.lang.reflect.Method는 이러한 정보를 얻을 수 있는 방법을 제공합니다.1. 획득 방법의 명칭String getName()2.가져오는 방법의 설명자 int getModifiers() 반환값은 이전 글의 소개를 참고하십시오.3. 반환 방법의 반환값 유형Class> getReturnType()Type getGenericReturnType4.반환 방법의 매개 변수(목록)Class>[] getParameterTypes()Type[] getGenericParameterTypes()5.되돌아오는 방법의 이상 정보Class>[] getExceptionTypes()Type[] getGenericExceptionTypes()는 왜 방법의 매개 변수, 되돌아오는 값 유형과 이상표에 두 가지 방법이 있습니까?Generic가 있는 것은 성명을 되돌려주는 유형이기 때문에 이 성명의 유형이 범형이라도 범형 표지부를 되돌려주고 진정한 유형을 되돌려주지 않기 때문에 지난 글에서 말한 범형 지우개에 대한 설명이 있습니다.말로는 증거가 없으니 예를 들자.
public class MethodSpy {
    private static final String  fmt = "%24s: %s%n";

    // for the morbidly curious
     void genericThrow() throws E {}

    public static void main(String... args) {
    try {
        Class> c = Class.forName(args[0]);
        Method[] allMethods = c.getDeclaredMethods();
        for (Method m : allMethods) {
        if (!m.getName().equals(args[1])) {
            continue;
        }
        out.format("%s%n", m.toGenericString());

        out.format(fmt, "ReturnType", m.getReturnType());
        out.format(fmt, "GenericReturnType", m.getGenericReturnType());

        Class>[] pType  = m.getParameterTypes();
        Type[] gpType = m.getGenericParameterTypes();
        for (int i = 0; i < pType.length; i++) {
            out.format(fmt,"ParameterType", pType[i]);
            out.format(fmt,"GenericParameterType", gpType[i]);
        }

        Class>[] xType  = m.getExceptionTypes();
        Type[] gxType = m.getGenericExceptionTypes();
        for (int i = 0; i < xType.length; i++) {
            out.format(fmt,"ExceptionType", xType[i]);
            out.format(fmt,"GenericExceptionType", gxType[i]);
        }
        }
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    }
    }
}

이 예의 대체적인 의미는 하나의 종류를 입력하고 방법 정보를 얻으려는 방법명을 입력하는 것이다.입력 결과: 1.java.lang.Class의 getConstructor 방법
$ java MethodSpy java.lang.Class getConstructor
public java.lang.reflect.Constructor java.lang.Class.getConstructor
  (java.lang.Class>[]) throws java.lang.NoSuchMethodException,
  java.lang.SecurityException
              ReturnType: class java.lang.reflect.Constructor
       GenericReturnType: java.lang.reflect.Constructor
           ParameterType: class [Ljava.lang.Class;
    GenericParameterType: java.lang.Class>[]
           ExceptionType: class java.lang.NoSuchMethodException
    GenericExceptionType: class java.lang.NoSuchMethodException
           ExceptionType: class java.lang.SecurityException
    GenericExceptionType: class java.lang.SecurityException
  • java.lang.Class 캐스트 방법
  • $ java MethodSpy java.lang.Class cast
    public T java.lang.Class.cast(java.lang.Object)
                  ReturnType: class java.lang.Object
           GenericReturnType: T
               ParameterType: class java.lang.Object
        GenericParameterType: class java.lang.Object

    cast 방법의 반환값은 범형이고 표지부호는 'T' 이기 때문에 getGenericReturnType () 방법은 T를 되돌려주고 getReturnType () 은java를 되돌려줍니다.lang.object, 즉 일반 지우기 후의 유형입니다.3. java.io.PrintStream format 방법
    $ java MethodSpy java.io.PrintStream format
    public java.io.PrintStream java.io.PrintStream.format
      (java.util.Locale,java.lang.String,java.lang.Object[])
                  ReturnType: class java.io.PrintStream
           GenericReturnType: class java.io.PrintStream
               ParameterType: class java.util.Locale
        GenericParameterType: class java.util.Locale
               ParameterType: class java.lang.String
        GenericParameterType: class java.lang.String
               ParameterType: class [Ljava.lang.Object;
        GenericParameterType: class [Ljava.lang.Object;
    public java.io.PrintStream java.io.PrintStream.format
      (java.lang.String,java.lang.Object[])
                  ReturnType: class java.io.PrintStream
           GenericReturnType: class java.io.PrintStream
               ParameterType: class java.lang.String
        GenericParameterType: class java.lang.String
               ParameterType: class [Ljava.lang.Object;
        GenericParameterType: class [Ljava.lang.Object;

    매개변수 정보 가져오기
    우리는 매개 변수의 정보를 얻는 것은 매개 변수가 비교적 특수하기 때문에 안전과 메모리를 고려하기 위해class의 바이트 코드 파일에 매개 변수의 이름을 저장하지 않는다. 예를 들어 일부 매개 변수의 이름, 예를 들어secret이나password 등은 안전 민감 방법과 관련된 정보를 공개할 수 있다. 예를 들어 긴 매개 변수, 그 매개 변수의 이름을 저장하면 메모리가 폭증할 수 있다.물론 우리가 실행할 때 -parameters 파라미터를 추가하면 그 파라미터의 이름을 강제로 저장할 수 있으며 기본적으로 저장하지 않습니다.공식적으로 인쇄 매개 변수의 데모 코드가 있습니다.
    public class MethodParameterSpy {
    
        private static final String  fmt = "%24s: %s%n";
    
        // for the morbidly curious
         void genericThrow() throws E {}
    
        public static void printClassConstructors(Class c) {
            Constructor[] allConstructors = c.getConstructors();
            out.format(fmt, "Number of constructors", allConstructors.length);
            for (Constructor currentConstructor : allConstructors) {
                printConstructor(currentConstructor);
            }  
            Constructor[] allDeclConst = c.getDeclaredConstructors();
            out.format(fmt, "Number of declared constructors",
                allDeclConst.length);
            for (Constructor currentDeclConst : allDeclConst) {
                printConstructor(currentDeclConst);
            }          
        }
    
        public static void printClassMethods(Class c) {
           Method[] allMethods = c.getDeclaredMethods();
            out.format(fmt, "Number of methods", allMethods.length);
            for (Method m : allMethods) {
                printMethod(m);
            }        
        }
    
        public static void printConstructor(Constructor c) {
            out.format("%s%n", c.toGenericString());
            Parameter[] params = c.getParameters();
            out.format(fmt, "Number of parameters", params.length);
            for (int i = 0; i < params.length; i++) {
                printParameter(params[i]);
            }
        }
    
        public static void printMethod(Method m) {
            out.format("%s%n", m.toGenericString());
            out.format(fmt, "Return type", m.getReturnType());
            out.format(fmt, "Generic return type", m.getGenericReturnType());
    
            Parameter[] params = m.getParameters();
            for (int i = 0; i < params.length; i++) {
                printParameter(params[i]);
            }
        }
    
        public static void printParameter(Parameter p) {
            out.format(fmt, "Parameter class", p.getType());
            out.format(fmt, "Parameter name", p.getName());
            out.format(fmt, "Modifiers", p.getModifiers());
            out.format(fmt, "Is implicit?", p.isImplicit());
            out.format(fmt, "Is name present?", p.isNamePresent());
            out.format(fmt, "Is synthetic?", p.isSynthetic());
        }
    
        public static void main(String... args) {        
    
            try {
                printClassConstructors(Class.forName(args[0]));
                printClassMethods(Class.forName(args[0]));
            } catch (ClassNotFoundException x) {
                x.printStackTrace();
            }
        }
    }

    가져오는 매개 변수는 Parameter입니다. Field와 마찬가지로 getType (): 매개 변수 형식 getName (): 매개 변수 이름. 컴파일러가 매개 변수 -parameters를 추가하면 진정한 매개 변수 이름을 되돌려줍니다. 추가하지 않으면 매개 변수는argN 형식이고 N은 몇 번째 매개 변수입니다.getModifiers (): 매개 변수 식별자, 상세하게 설명하지 않습니다.isImplicit(): 암시적 선언이면 true로 돌아갑니다.예를 들어 내부 클래스는parent 구성원 변수와 구조기를 은밀하게 설명합니다.우리의 코드:
    public class MethodParameterExamples {
        public class InnerClass { }
    }

    컴파일러가 실제로 생성한 코드:
    public class MethodParameterExamples {
        public class InnerClass {
            final MethodParameterExamples parent;
            InnerClass(final MethodParameterExamples this$0) {
                parent = this$0; 
            }
        }
    }

    isNamePresent (): 이름이 -parameters와 동일할 수 있는지 여부입니다.isSynthetic (): 컴파일러가 생성한 것인지 여부입니다.예를 들어 위의 코드로 다음 유형의 메서드 정보를 얻는 경우
    public class ExampleMethods<T> {
    
        public boolean simpleMethod(String stringParam, int intParam) {
            System.out.println("String: " + stringParam + ", integer: " + intParam); 
            return true;
        }
    
        public int varArgsMethod(String... manyStrings) {
            return manyStrings.length;
        }
    
        public boolean methodWithList(List listParam) {
            return listParam.isEmpty();
        }
    
        public  void genericMethod(T[] a, Collection c) {
            System.out.println("Length of array: " + a.length);
            System.out.println("Size of collection: " + c.size()); 
        }
    
    }

    컴파일러 가-parameters의 실행 결과는 다음과 같습니다.
    Number of constructors: 1
    
    Constructor #1
    public ExampleMethods()
    
    Number of declared constructors: 1
    
    Declared constructor #1
    public ExampleMethods()
    
    Number of methods: 4
    
    Method #1
    public boolean ExampleMethods.simpleMethod(java.lang.String,int)
                 Return type: boolean
         Generic return type: boolean
             Parameter class: class java.lang.String
              Parameter name: stringParam
                   Modifiers: 0
                Is implicit?: false
            Is name present?: true
               Is synthetic?: false
             Parameter class: int
              Parameter name: intParam
                   Modifiers: 0
                Is implicit?: false
            Is name present?: true
               Is synthetic?: false
    
    Method #2
    public int ExampleMethods.varArgsMethod(java.lang.String...)
                 Return type: int
         Generic return type: int
             Parameter class: class [Ljava.lang.String;
              Parameter name: manyStrings
                   Modifiers: 0
                Is implicit?: false
            Is name present?: true
               Is synthetic?: false
    
    Method #3
    public boolean ExampleMethods.methodWithList(java.util.List)
                 Return type: boolean
         Generic return type: boolean
             Parameter class: interface java.util.List
              Parameter name: listParam
                   Modifiers: 0
                Is implicit?: false
            Is name present?: true
               Is synthetic?: false
    
    Method #4
    public <T> void ExampleMethods.genericMethod(T[],java.util.Collection)
                 Return type: void
         Generic return type: void
             Parameter class: class [Ljava.lang.Object;
              Parameter name: a
                   Modifiers: 0
                Is implicit?: false
            Is name present?: true
               Is synthetic?: false
             Parameter class: interface java.util.Collection
              Parameter name: c
                   Modifiers: 0
                Is implicit?: false
            Is name present?: true
               Is synthetic?: false

    매개변수가 없는 실행 결과:
      Number of constructors: 1
    public reflect.ExampleMethods()
        Number of parameters: 0
    Number of declared constructors: 1
    public reflect.ExampleMethods()
        Number of parameters: 0
           Number of methods: 4
    public boolean reflect.ExampleMethods.simpleMethod(java.lang.String,int)
                 Return type: boolean
         Generic return type: boolean
             Parameter class: class java.lang.String
              Parameter name: arg0
                   Modifiers: 0
                Is implicit?: false
            Is name present?: false
               Is synthetic?: false
             Parameter class: int
              Parameter name: arg1
                   Modifiers: 0
                Is implicit?: false
            Is name present?: false
               Is synthetic?: false
    public int reflect.ExampleMethods.varArgsMethod(java.lang.String...)
                 Return type: int
         Generic return type: int
             Parameter class: class [Ljava.lang.String;
              Parameter name: arg0
                   Modifiers: 0
                Is implicit?: false
            Is name present?: false
               Is synthetic?: false
    public boolean reflect.ExampleMethods.methodWithList(java.util.List)
                 Return type: boolean
         Generic return type: boolean
             Parameter class: interface java.util.List
              Parameter name: arg0
                   Modifiers: 0
                Is implicit?: false
            Is name present?: false
               Is synthetic?: false
    public  void reflect.ExampleMethods.genericMethod(T[],java.util.Collection)
                 Return type: void
         Generic return type: void
             Parameter class: class [Ljava.lang.Object;
              Parameter name: arg0
                   Modifiers: 0
                Is implicit?: false
            Is name present?: false
               Is synthetic?: false
             Parameter class: interface java.util.Collection
              Parameter name: arg1
                   Modifiers: 0
                Is implicit?: false
            Is name present?: false
               Is synthetic?: false

    획득 방법의 식별자int getModifiers 표지부를 얻으려면 여기에 예를 들면 됩니다. 상세한 소개는 하지 않겠습니다.
    public class MethodModifierSpy {
    
        private static int count;
        private static synchronized void inc() { count++; }
        private static synchronized int cnt() { return count; }
    
        public static void main(String... args) {
        try {
            Class> c = Class.forName(args[0]);
            Method[] allMethods = c.getDeclaredMethods();
            for (Method m : allMethods) {
            if (!m.getName().equals(args[1])) {
                continue;
            }
            out.format("%s%n", m.toGenericString());
            out.format("  Modifiers:  %s%n",
                   Modifier.toString(m.getModifiers()));
            out.format("  [ synthetic=%-5b var_args=%-5b bridge=%-5b ]%n",
                   m.isSynthetic(), m.isVarArgs(), m.isBridge());
            inc();
            }
            out.format("%d matching overload%s found%n", cnt(),
                   (cnt() == 1 ? "" : "s"));
        } catch (ClassNotFoundException x) {
            x.printStackTrace();
        }
        }
    }

    결과 출력:
    $ java MethodModifierSpy java.lang.Object wait
    public final void java.lang.Object.wait() throws java.lang.InterruptedException
      Modifiers:  public final
      [ synthetic=false var_args=false bridge=false ]
    public final void java.lang.Object.wait(long,int)
      throws java.lang.InterruptedException
      Modifiers:  public final
      [ synthetic=false var_args=false bridge=false ]
    public final native void java.lang.Object.wait(long)
      throws java.lang.InterruptedException
      Modifiers:  public final native
      [ synthetic=false var_args=false bridge=false ]
    3 matching overloads found
    
    $ java MethodModifierSpy java.lang.StrictMath toRadians
    public static double java.lang.StrictMath.toRadians(double)
      Modifiers:  public static strictfp
      [ synthetic=false var_args=false bridge=false ]
    1 matching overload found
    
    $ java MethodModifierSpy MethodModifierSpy inc
    private synchronized void MethodModifierSpy.inc()
      Modifiers: private synchronized
      [ synthetic=false var_args=false bridge=false ]
    1 matching overload found
    
    $ java MethodModifierSpy java.lang.Class getConstructor
    public java.lang.reflect.Constructor java.lang.Class.getConstructor
      (java.lang.Class[]) throws java.lang.NoSuchMethodException,
      java.lang.SecurityException
      Modifiers: public transient
      [ synthetic=false var_args=true bridge=false ]
    1 matching overload found
    
    $ java MethodModifierSpy java.lang.String compareTo
    public int java.lang.String.compareTo(java.lang.String)
      Modifiers: public
      [ synthetic=false var_args=false bridge=false ]
    public int java.lang.String.compareTo(java.lang.Object)
      Modifiers: public volatile
      [ synthetic=true  var_args=false bridge=true  ]
    2 matching overloads found

    실행 방법
    반사 실행 방법(Invoking Methods)을 사용하는 것은 매우 간단한 일이다. public Object invoke(Object obj,
    Object... args)
    throws IllegalAccessException,
    IllegalArgumentException,
    InvocationTargetException
    을 호출하면 된다. obj는 방법을 가진Class의 실례이고args는 방법의 매개 변수이다.주의 방법은 Illegal Access Exception, Illegal Argument Exception, Invocation Target Exception 이상을 던질 수 있습니다.
    반사된 Method 고려 사항
  • 방법을 찾을 때 c.getMethod(mName, cArg) 예외가 발생합니다.
  • 개인적인 방법이 호출될 때 Illegal Access Exception을 던지지만 이것은Accessible Object를 통과할 수 있습니다.setAccessible() 설정이 완료되면 호출할 수 있습니다.
  • 방법이 호출될 때 Illegal Argument Exception을 던집니다. 이 이상을 던진 이유는 파라미터가 비합법적이기 때문입니다.
  • 방법이 호출될 때 Invocation Target Exception을 던집니다. 이 이상은 비교적 특수하고 방법이 호출에 성공했습니다. 그러나 방법 내부에서 이상을 던집니다. 모든 invoke()는 이 이상을 던집니다. Throwable cause = Illegal Argument Exception을 통과할 수 있습니다.getCause () 와cause.getMessage에서 예외 정보를 얻었습니다.
  • 좋은 웹페이지 즐겨찾기