A Method provides information about, and access to, a single method on a class or interface. The reflected method may be a class method or an instance method (including an abstract method).
方法提供有关类或接口上单个方法的信息和对该方法的访问。反射的方法可以是类方法或实例方法(包括抽象方法)。
A Method permits widening conversions to occur when matching the actual parameters to invoke with the underlying method’s formal parameters, but it throws an IllegalArgumentException if a narrowing conversion would occur.
方法允许在将要调用的实际参数与基础方法的形式参数相匹配时发生加宽转换(例如要求传入people类型,传入实际参数时people的父类对象teacher),但如果发生缩小转换,则会引发IllegalArgumentException。
以下所有说明都以User类为例,了解如何获取Method对象,看看Method对象从哪里来的。
package com.longma.study;
import java.math.BigDecimal;
/**
* @author wanglong
* @time 2022/6/22/
* @ref
*/
public class User {
private int age;
private String name;
private long salary;
private BigDecimal price;
public User() {
}
public void test() throws NullPointerException{
System.out.println("test UserService");
}
private Integer getInt(String str, long[] arr) {
System.out.println("str: " + str);
for(long l : arr) {
System.out.println("l: " + l);
}
return 1;
}
public Integer getStr(String str) {
System.out.println("str: " + str);
return 1;
}
protected Integer getLong( long[] arr) {
for(long l : arr) {
System.out.println("l: " + l);
}
return 1;
}
}
public Method[] getDeclaredMethods() throws SecurityException
返回一个数组,该数组包含反映该类对象所表示的类或接口的所有声明方法的方法对象,包括public、protected、default(package)access和private方法,但不包括继承的方法。
public static void main(String[] args) throws ClassNotFoundException {
User user = new User();
Class<User> userServiceClass = User.class;
Method[] methods = userServiceClass.getDeclaredMethods(); //获取该User类所有声明的方法对象
for(Method method : methods) {
System.out.println("method: " + method.toString());
}
}

public Method[] getMethods() throws SecurityException
返回一个数组,其中包含反映该类对象所表示的类或接口的所有公共方法的方法对象,包括由类或接口声明的方法对象以及从超类和超接口继承的方法对象
public static void main(String[] args) throws ClassNotFoundException {
User user = new User();
Class<User> userServiceClass = User.class;
Method[] methods = userServiceClass.getMethods(); //获取当前User类所有的公共的方法对象
for(Method method : methods) {
System.out.println("method: " + method.toString());
}
}

其中,红色框中为自定义方法,其余为继承的方法。
public Method getMethod(String name, Class<?>... parameterTypes)
返回一个指定名称和形参类型的公共方法的对象
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class<User> userServiceClass = User.class;
Method method1 = userServiceClass.getMethod("getStr", String.class);
System.out.println("method1: " + method1);
Method method2 = userServiceClass.getMethod("getLongArr", long[].class);
System.out.println("method2: " + method2);
Method method3 = userServiceClass.getMethod("getStr", null);
System.out.println("method3: " + method3);
Method method4 = userServiceClass.getMethod("test", null);
System.out.println("method3: " + method4);
}

public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
获取一个指定名称和形参类型的方法
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class<User> userServiceClass = User.class;
Method method1 = userServiceClass.getDeclaredMethod("getStr", String.class);
System.out.println("method1: " + method1);
Method method2 = userServiceClass.getDeclaredMethod("getLongArr", long[].class);
System.out.println("method2: " + method2);
Method method3 = userServiceClass.getDeclaredMethod("getStr", null);
System.out.println("method3: " + method3);
Method method4 = userServiceClass.getDeclaredMethod("test", null);
System.out.println("method4: " + method4);
Method method5 = userServiceClass.getDeclaredMethod("getLong", long[].class);
System.out.println("method5: " + method5);
Method method6 = userServiceClass.getDeclaredMethod("getInt", String.class, long[].class);
System.out.println("method6: " + method6);
}

最后还有一个getEnclosingMethod(),平时用的不多,可以参考博客了解一下:Java Class getEnclosingMethod实例讲解
如果习惯看文档,可以看Method类的说明文档:https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html
源代码附如下:
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*/
package java.lang.reflect;
import sun.reflect.CallerSensitive;
import sun.reflect.MethodAccessor;
import sun.reflect.Reflection;
import sun.reflect.generics.repository.MethodRepository;
import sun.reflect.generics.factory.CoreReflectionFactory;
import sun.reflect.generics.factory.GenericsFactory;
import sun.reflect.generics.scope.MethodScope;
import sun.reflect.annotation.AnnotationType;
import sun.reflect.annotation.AnnotationParser;
import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
import java.nio.ByteBuffer;
/**
* A {@code Method} provides information about, and access to, a single method
* on a class or interface. The reflected method may be a class method
* or an instance method (including an abstract method).
*
* <p>A {@code Method} permits widening conversions to occur when matching the
* actual parameters to invoke with the underlying method's formal
* parameters, but it throws an {@code IllegalArgumentException} if a
* narrowing conversion would occur.
*
* @see Member
* @see java.lang.Class
* @see java.lang.Class#getMethods()
* @see java.lang.Class#getMethod(String, Class[])
* @see java.lang.Class#getDeclaredMethods()
* @see java.lang.Class#getDeclaredMethod(String, Class[])
*
* @author Kenneth Russell
* @author Nakul Saraiya
*/
public final class Method extends Executable {
private Class<?> clazz;
private int slot;
// This is guaranteed to be interned by the VM in the 1.4
// reflection implementation
private String name; //方法名
private Class<?> returnType; //返回值类型
private Class<?>[] parameterTypes; //形参列表中参数类型
private Class<?>[] exceptionTypes; //异常类型
private int modifiers;
// Generics and annotations support
private transient String signature;
// generic info repository; lazily initialized
private transient MethodRepository genericInfo;
private byte[] annotations;
private byte[] parameterAnnotations;
private byte[] annotationDefault;
private volatile MethodAccessor methodAccessor;
// For sharing of MethodAccessors. This branching structure is
// currently only two levels deep (i.e., one root Method and
// potentially many Method objects pointing to it.)
//
// If this branching structure would ever contain cycles, deadlocks can
// occur in annotation code.
private Method root;
// Generics infrastructure
private String getGenericSignature() {return signature;}
// Accessor for factory
private GenericsFactory getFactory() {
// create scope and factory
return CoreReflectionFactory.make(this, MethodScope.make(this));
}
// Accessor for generic info repository
@Override
MethodRepository getGenericInfo() {
// lazily initialize repository if necessary
if (genericInfo == null) {
// create and cache generic info repository
genericInfo = MethodRepository.make(getGenericSignature(),
getFactory());
}
return genericInfo; //return cached repository
}
/**
* Package-private constructor used by ReflectAccess to enable
* instantiation of these objects in Java code from the java.lang
* package via sun.reflect.LangReflectAccess.
*/
Method(Class<?> declaringClass,
String name,
Class<?>[] parameterTypes,
Class<?> returnType,
Class<?>[] checkedExceptions,
int modifiers,
int slot,
String signature,
byte[] annotations,
byte[] parameterAnnotations,
byte[] annotationDefault) {
this.clazz = declaringClass;
this.name = name;
this.parameterTypes = parameterTypes;
this.returnType = returnType;
this.exceptionTypes = checkedExceptions;
this.modifiers = modifiers;
this.slot = slot;
this.signature = signature;
this.annotations = annotations;
this.parameterAnnotations = parameterAnnotations;
this.annotationDefault = annotationDefault;
}
/**
* Package-private routine (exposed to java.lang.Class via
* ReflectAccess) which returns a copy of this Method. The copy's
* "root" field points to this Method.
*/
Method copy() {
// This routine enables sharing of MethodAccessor objects
// among Method objects which refer to the same underlying
// method in the VM. (All of this contortion is only necessary
// because of the "accessibility" bit in AccessibleObject,
// which implicitly requires that new java.lang.reflect
// objects be fabricated for each reflective call on Class
// objects.)
if (this.root != null)
throw new IllegalArgumentException("Can not copy a non-root Method");
Method res = new Method(clazz, name, parameterTypes, returnType,
exceptionTypes, modifiers, slot, signature,
annotations, parameterAnnotations, annotationDefault);
res.root = this;
// Might as well eagerly propagate this if already present
res.methodAccessor = methodAccessor;
return res;
}
/**
* Used by Excecutable for annotation sharing.
*/
@Override
Executable getRoot() {
return root;
}
@Override
boolean hasGenericInformation() {
return (getGenericSignature() != null);
}
@Override
byte[] getAnnotationBytes() {
return annotations;
}
/**
* {@inheritDoc}
*/
@Override
public Class<?> getDeclaringClass() {
return clazz;
}
/**
* Returns the name of the method represented by this {@code Method}
* object, as a {@code String}.
*/
@Override
public String getName() {
return name;
}
/**
* {@inheritDoc}
*/
@Override
public int getModifiers() {
return modifiers;
}
/**
* {@inheritDoc}
* @throws GenericSignatureFormatError {@inheritDoc}
* @since 1.5
*/
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public TypeVariable<Method>[] getTypeParameters() {
if (getGenericSignature() != null)
return (TypeVariable<Method>[])getGenericInfo().getTypeParameters();
else
return (TypeVariable<Method>[])new TypeVariable[0];
}
/**
* Returns a {@code Class} object that represents the formal return type
* of the method represented by this {@code Method} object.
*
* @return the return type for the method this object represents
*/
public Class<?> getReturnType() {
return returnType;
}
/**
* Returns a {@code Type} object that represents the formal return
* type of the method represented by this {@code Method} object.
*
* <p>If the return type is a parameterized type,
* the {@code Type} object returned must accurately reflect
* the actual type parameters used in the source code.
*
* <p>If the return type is a type variable or a parameterized type, it
* is created. Otherwise, it is resolved.
*
* @return a {@code Type} object that represents the formal return
* type of the underlying method
* @throws GenericSignatureFormatError
* if the generic method signature does not conform to the format
* specified in
* <cite>The Java™ Virtual Machine Specification</cite>
* @throws TypeNotPresentException if the underlying method's
* return type refers to a non-existent type declaration
* @throws MalformedParameterizedTypeException if the
* underlying method's return typed refers to a parameterized
* type that cannot be instantiated for any reason
* @since 1.5
*/
public Type getGenericReturnType() {
if (getGenericSignature() != null) {
return getGenericInfo().getReturnType();
} else { return getReturnType();}
}
/**
* {@inheritDoc}
*/
@Override
public Class<?>[] getParameterTypes() {
return parameterTypes.clone();
}
/**
* {@inheritDoc}
* @since 1.8
*/
public int getParameterCount() { return parameterTypes.length; }
/**
* {@inheritDoc}
* @throws GenericSignatureFormatError {@inheritDoc}
* @throws TypeNotPresentException {@inheritDoc}
* @throws MalformedParameterizedTypeException {@inheritDoc}
* @since 1.5
*/
@Override
public Type[] getGenericParameterTypes() {
return super.getGenericParameterTypes();
}
/**
* {@inheritDoc}
*/
@Override
public Class<?>[] getExceptionTypes() {
return exceptionTypes.clone();
}
/**
* {@inheritDoc}
* @throws GenericSignatureFormatError {@inheritDoc}
* @throws TypeNotPresentException {@inheritDoc}
* @throws MalformedParameterizedTypeException {@inheritDoc}
* @since 1.5
*/
@Override
public Type[] getGenericExceptionTypes() {
return super.getGenericExceptionTypes();
}
/**
* Compares this {@code Method} against the specified object. Returns
* true if the objects are the same. Two {@code Methods} are the same if
* they were declared by the same class and have the same name
* and formal parameter types and return type.
*/
public boolean equals(Object obj) {
if (obj != null && obj instanceof Method) {
Method other = (Method)obj;
if ((getDeclaringClass() == other.getDeclaringClass())
&& (getName() == other.getName())) {
if (!returnType.equals(other.getReturnType()))
return false;
return equalParamTypes(parameterTypes, other.parameterTypes);
}
}
return false;
}
/**
* Returns a hashcode for this {@code Method}. The hashcode is computed
* as the exclusive-or of the hashcodes for the underlying
* method's declaring class name and the method's name.
*/
public int hashCode() {
return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
}
/**
* Returns a string describing this {@code Method}. The string is
* formatted as the method access modifiers, if any, followed by
* the method return type, followed by a space, followed by the
* class declaring the method, followed by a period, followed by
* the method name, followed by a parenthesized, comma-separated
* list of the method's formal parameter types. If the method
* throws checked exceptions, the parameter list is followed by a
* space, followed by the word throws followed by a
* comma-separated list of the thrown exception types.
* For example:
* <pre>
* public boolean java.lang.Object.equals(java.lang.Object)
* </pre>
*
* <p>The access modifiers are placed in canonical order as
* specified by "The Java Language Specification". This is
* {@code public}, {@code protected} or {@code private} first,
* and then other modifiers in the following order:
* {@code abstract}, {@code default}, {@code static}, {@code final},
* {@code synchronized}, {@code native}, {@code strictfp}.
*
* @return a string describing this {@code Method}
*
* @jls 8.4.3 Method Modifiers
*/
public String toString() {
return sharedToString(Modifier.methodModifiers(),
isDefault(),
parameterTypes,
exceptionTypes);
}
@Override
void specificToStringHeader(StringBuilder sb) {
sb.append(getReturnType().getTypeName()).append(' ');
sb.append(getDeclaringClass().getTypeName()).append('.');
sb.append(getName());
}
/**
* Returns a string describing this {@code Method}, including
* type parameters. The string is formatted as the method access
* modifiers, if any, followed by an angle-bracketed
* comma-separated list of the method's type parameters, if any,
* followed by the method's generic return type, followed by a
* space, followed by the class declaring the method, followed by
* a period, followed by the method name, followed by a
* parenthesized, comma-separated list of the method's generic
* formal parameter types.
*
* If this method was declared to take a variable number of
* arguments, instead of denoting the last parameter as
* "<tt><i>Type</i>[]</tt>", it is denoted as
* "<tt><i>Type</i>...</tt>".
*
* A space is used to separate access modifiers from one another
* and from the type parameters or return type. If there are no
* type parameters, the type parameter list is elided; if the type
* parameter list is present, a space separates the list from the
* class name. If the method is declared to throw exceptions, the
* parameter list is followed by a space, followed by the word
* throws followed by a comma-separated list of the generic thrown
* exception types.
*
* <p>The access modifiers are placed in canonical order as
* specified by "The Java Language Specification". This is
* {@code public}, {@code protected} or {@code private} first,
* and then other modifiers in the following order:
* {@code abstract}, {@code default}, {@code static}, {@code final},
* {@code synchronized}, {@code native}, {@code strictfp}.
*
* @return a string describing this {@code Method},
* include type parameters
*
* @since 1.5
*
* @jls 8.4.3 Method Modifiers
*/
@Override
public String toGenericString() {
return sharedToGenericString(Modifier.methodModifiers(), isDefault());
}
@Override
void specificToGenericStringHeader(StringBuilder sb) {
Type genRetType = getGenericReturnType();
sb.append(genRetType.getTypeName()).append(' ');
sb.append(getDeclaringClass().getTypeName()).append('.');
sb.append(getName());
}
/**
* Invokes the underlying method represented by this {@code Method}
* object, on the specified object with the specified parameters.
* Individual parameters are automatically unwrapped to match
* primitive formal parameters, and both primitive and reference
* parameters are subject to method invocation conversions as
* necessary.
*
* <p>If the underlying method is static, then the specified {@code obj}
* argument is ignored. It may be null.
*
* <p>If the number of formal parameters required by the underlying method is
* 0, the supplied {@code args} array may be of length 0 or null.
*
* <p>If the underlying method is an instance method, it is invoked
* using dynamic method lookup as documented in The Java Language
* Specification, Second Edition, section 15.12.4.4; in particular,
* overriding based on the runtime type of the target object will occur.
*
* <p>If the underlying method is static, the class that declared
* the method is initialized if it has not already been initialized.
*
* <p>If the method completes normally, the value it returns is
* returned to the caller of invoke; if the value has a primitive
* type, it is first appropriately wrapped in an object. However,
* if the value has the type of an array of a primitive type, the
* elements of the array are <i>not</i> wrapped in objects; in
* other words, an array of primitive type is returned. If the
* underlying method return type is void, the invocation returns
* null.
*
* @param obj the object the underlying method is invoked from
* @param args the arguments used for the method call
* @return the result of dispatching the method represented by
* this object on {@code obj} with parameters
* {@code args}
*
* @exception IllegalAccessException if this {@code Method} object
* is enforcing Java language access control and the underlying
* method is inaccessible.
* @exception IllegalArgumentException if the method is an
* instance method and the specified object argument
* is not an instance of the class or interface
* declaring the underlying method (or of a subclass
* or implementor thereof); if the number of actual
* and formal parameters differ; if an unwrapping
* conversion for primitive arguments fails; or if,
* after possible unwrapping, a parameter value
* cannot be converted to the corresponding formal
* parameter type by a method invocation conversion.
* @exception InvocationTargetException if the underlying method
* throws an exception.
* @exception NullPointerException if the specified object is null
* and the method is an instance method.
* @exception ExceptionInInitializerError if the initialization
* provoked by this method fails.
*/
@CallerSensitive
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
/**
* Returns {@code true} if this method is a bridge
* method; returns {@code false} otherwise.
*
* @return true if and only if this method is a bridge
* method as defined by the Java Language Specification.
* @since 1.5
*/
public boolean isBridge() {
return (getModifiers() & Modifier.BRIDGE) != 0;
}
/**
* {@inheritDoc}
* @since 1.5
*/
@Override
public boolean isVarArgs() {
return super.isVarArgs();
}
/**
* {@inheritDoc}
* @jls 13.1 The Form of a Binary
* @since 1.5
*/
@Override
public boolean isSynthetic() {
return super.isSynthetic();
}
/**
* Returns {@code true} if this method is a default
* method; returns {@code false} otherwise.
*
* A default method is a public non-abstract instance method, that
* is, a non-static method with a body, declared in an interface
* type.
*
* @return true if and only if this method is a default
* method as defined by the Java Language Specification.
* @since 1.8
*/
public boolean isDefault() {
// Default methods are public non-abstract instance methods
// declared in an interface.
return ((getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
Modifier.PUBLIC) && getDeclaringClass().isInterface();
}
// NOTE that there is no synchronization used here. It is correct
// (though not efficient) to generate more than one MethodAccessor
// for a given Method. However, avoiding synchronization will
// probably make the implementation more scalable.
private MethodAccessor acquireMethodAccessor() {
// First check to see if one has been created yet, and take it
// if so
MethodAccessor tmp = null;
if (root != null) tmp = root.getMethodAccessor();
if (tmp != null) {
methodAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newMethodAccessor(this);
setMethodAccessor(tmp);
}
return tmp;
}
// Returns MethodAccessor for this Method object, not looking up
// the chain to the root
MethodAccessor getMethodAccessor() {
return methodAccessor;
}
// Sets the MethodAccessor for this Method object and
// (recursively) its root
void setMethodAccessor(MethodAccessor accessor) {
methodAccessor = accessor;
// Propagate up
if (root != null) {
root.setMethodAccessor(accessor);
}
}
/**
* Returns the default value for the annotation member represented by
* this {@code Method} instance. If the member is of a primitive type,
* an instance of the corresponding wrapper type is returned. Returns
* null if no default is associated with the member, or if the method
* instance does not represent a declared member of an annotation type.
*
* @return the default value for the annotation member represented
* by this {@code Method} instance.
* @throws TypeNotPresentException if the annotation is of type
* {@link Class} and no definition can be found for the
* default class value.
* @since 1.5
*/
public Object getDefaultValue() {
if (annotationDefault == null)
return null;
Class<?> memberType = AnnotationType.invocationHandlerReturnType(
getReturnType());
Object result = AnnotationParser.parseMemberValue(
memberType, ByteBuffer.wrap(annotationDefault),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
getDeclaringClass());
if (result instanceof sun.reflect.annotation.ExceptionProxy)
throw new AnnotationFormatError("Invalid default: " + this);
return result;
}
/**
* {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @since 1.5
*/
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
return super.getAnnotation(annotationClass);
}
/**
* {@inheritDoc}
* @since 1.5
*/
public Annotation[] getDeclaredAnnotations() {
return super.getDeclaredAnnotations();
}
/**
* {@inheritDoc}
* @since 1.5
*/
@Override
public Annotation[][] getParameterAnnotations() {
return sharedGetParameterAnnotations(parameterTypes, parameterAnnotations);
}
/**
* {@inheritDoc}
* @since 1.8
*/
@Override
public AnnotatedType getAnnotatedReturnType() {
return getAnnotatedReturnType0(getGenericReturnType());
}
@Override
void handleParameterNumberMismatch(int resultLength, int numParameters) {
throw new AnnotationFormatError("Parameter annotations don't match number of parameters");
}
}