159 调用实例方法
假设我们有以下Melon
类:
public class Melon { ... public Melon() {} public List<Melon> cultivate( String type, Seed seed, int noOfSeeds) { System.out.println("The cultivate() method was invoked ..."); return Collections.nCopies(noOfSeeds, new Melon("Gac", 5)); } ... }
我们的目标是调用cultivate()
方法并通过 Java 反射 API 获得返回。
首先,让我们通过Method.getDeclaredMethod()
获取cultivate()
方法作为Method
。我们所要做的就是将方法的名称(在本例中为cultivate()
)和正确类型的参数(String
、Seed
和int
传递给getDeclaredMethod()
。getDeclaredMethod()
的第二个参数是Class<?>
类型的varargs
,因此对于没有参数的方法可以为空,也可以包含参数类型列表,如下例所示:
Method cultivateMethod = Melon.class.getDeclaredMethod( "cultivate", String.class, Seed.class, int.class);
然后,获取一个Melon
类的实例。我们想要调用一个实例方法;因此,我们需要一个实例。依靠Melon
的空构造器和 Java 反射 API,我们可以做到:
Melon instanceMelon = Melon.class .getDeclaredConstructor().newInstance();
最后,我们重点讨论了Method.invoke()
方法。主要是给这个方法传递调用cultivate()
方法的实例和一些参数值:
List<Melon> cultivatedMelons = (List<Melon>) cultivateMethod.invoke( instanceMelon, "Gac", new Seed(), 10);
以下消息显示调用成功:
The cultivate() method was invoked ...
另外,如果我们通过System.out.println()
打印调用返回,则得到如下结果:
[Gac(5g), Gac(5g), Gac(5g), ...]
我们刚刚通过反射培养了 10 个Gac
。
160 获取静态方法
假设我们有以下Melon
类:
public class Melon { ... public void eat() {} public void weighsIn() {} public static void cultivate(Seed seeds) { System.out.println("The cultivate() method was invoked ..."); } public static void peel(Slice slice) { System.out.println("The peel() method was invoked ..."); } // getters, setters, toString() omitted for brevity }
这个类有两个static
方法-cultivate()
和peel()
。让我们在List<Method>
中获取这两种方法。
这个问题的解决方案有两个主要步骤:
- 获取给定类的所有可用方法
- 通过
Modifier.isStatic()
方法过滤包含static
修饰符的
在代码中,如下所示:
List<Method> staticMethods = new ArrayList<>(); Class<Melon> clazz = Melon.class; Method[] methods = clazz.getDeclaredMethods(); for (Method method: methods) { if (Modifier.isStatic(method.getModifiers())) { staticMethods.add(method); } }
通过System.out.println()
打印列表的结果如下:
[public static void modern.challenge.Melon.peel(modern.challenge.Slice), public static void modern.challenge.Melon.cultivate(modern.challenge.Seed)]
再往前一步,我们可能想调用这两个方法中的一个。
例如,我们调用peel()
方法(注意我们传递的是null
而不是Melon
的实例,因为static
方法不需要实例):
Method method = clazz.getMethod("peel", Slice.class); method.invoke(null, new Slice());
成功调用peel()
方法的输出信号:
The peel() method was invoked ...
161 获取方法、字段和异常的泛型
假设我们有以下Melon
类(列出的只是与这个问题相关的部分):
public class Melon<E extends Exception> extends Fruit<String, Seed> implements Comparable<Integer> { ... private List<Slice> slices; ... public List<Slice> slice() throws E { ... } public Map<String, Integer> asMap(List<Melon> melons) { ... } ... }
Melon
类包含几个与不同工件相关联的泛型类型。超类、接口、类、方法和字段的泛型类型主要是ParameterizedType
实例。对于每个ParameterizedType
,我们需要通过ParameterizedType.getActualTypeArguments()
获取参数的实际类型。此方法返回的Type[]
可以迭代提取每个参数的信息,如下所示:
public static void printGenerics(Type genericType) { if (genericType instanceof ParameterizedType) { ParameterizedType type = (ParameterizedType) genericType; Type[] typeOfArguments = type.getActualTypeArguments(); for (Type typeOfArgument: typeOfArguments) { Class classTypeOfArgument = (Class) typeOfArgument; System.out.println("Class of type argument: " + classTypeOfArgument); System.out.println("Simple name of type argument: " + classTypeOfArgument.getSimpleName()); } } }
现在,让我们看看如何处理方法的泛型。
方法的泛型
例如,让我们获取slice()
和asMap()
方法的通用返回类型。这可以通过Method.getGenericReturnType()
方法实现,如下所示:
Class<Melon> clazz = Melon.class; Method sliceMethod = clazz.getDeclaredMethod("slice"); Method asMapMethod = clazz.getDeclaredMethod("asMap", List.class); Type sliceReturnType = sliceMethod.getGenericReturnType(); Type asMapReturnType = asMapMethod.getGenericReturnType();
现在,调用printGenerics(sliceReturnType)
将输出以下内容:
Class of type argument: class modern.challenge.Slice Simple name of type argument: Slice
并且,调用printGenerics(asMapReturnType)
将输出以下内容:
Class of type argument: class java.lang.String Simple name of type argument: String Class of type argument: class java.lang.Integer Simple name of type argument: Integer
方法的通用参数可通过Method.getGenericParameterTypes()
获得,如下所示:
Type[] asMapParamTypes = asMapMethod.getGenericParameterTypes();
此外,我们为每个Type
(每个泛型参数)调用printGenerics()
:
for (Type paramType: asMapParamTypes) { printGenerics(paramType); }
以下是输出(只有一个通用参数,List<Melon>
):
Class of type argument: class modern.challenge.Melon Simple name of type argument: Melon
字段的泛型
对于字段(例如,slices
),可以通过Field.getGenericType()
获取泛型,如下所示:
Field slicesField = clazz.getDeclaredField("slices"); Type slicesType = slicesField.getGenericType();
调用printGenerics(slicesType)
将输出以下内容:
Class of type argument: class modern.challenge.Slice Simple name of type argument: Slice
超类的泛型
获取超类的泛型可以通过调用当前类的getGenericSuperclass()
方法来完成:
Type superclassType = clazz.getGenericSuperclass();
调用printGenerics(superclassType)
将输出以下内容:
Class of type argument: class java.lang.String Simple name of type argument: String Class of type argument: class modern.challenge.Seed Simple name of type argument: Seed
接口泛型
通过调用当前类的getGenericInterfaces()
方法,可以得到实现接口的泛型:
Type[] interfacesTypes = clazz.getGenericInterfaces();
此外,我们为每个Type
调用printGenerics()
。输出如下(有单一接口,Comparable<Integer>
Class of type argument: class java.lang.Integer Simple name of type argument: Integer