Java 编程问题:七、Java 反射类、接口、构造器、方法和字段3

简介: Java 编程问题:七、Java 反射类、接口、构造器、方法和字段

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())和正确类型的参数(StringSeedint传递给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>中获取这两种方法。

这个问题的解决方案有两个主要步骤:

  1. 获取给定类的所有可用方法
  2. 通过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
相关文章
|
4天前
|
Java Apache Maven
Java将word文档转换成pdf文件的方法?
【10月更文挑战第13天】Java将word文档转换成pdf文件的方法?
14 1
|
8天前
|
Java 编译器
Java“返回类型为 void 的方法不能返回一个值”解决
在 Java 中,如果一个方法的返回类型被声明为 void,那么该方法不应该包含返回值的语句。如果尝试从这样的方法中返回一个值,编译器将报错。解决办法是移除返回值语句或更改方法的返回类型。
|
8天前
|
Java
让星星⭐月亮告诉你,Java NIO之Buffer详解 属性capacity/position/limit/mark 方法put(X)/get()/flip()/compact()/clear()
这段代码演示了Java NIO中`ByteBuffer`的基本操作,包括分配、写入、翻转、读取、压缩和清空缓冲区。通过示例展示了`position`、`limit`和`mark`属性的变化过程,帮助理解缓冲区的工作原理。
17 2
|
8天前
|
Java
让星星⭐月亮告诉你,jdk1.8 Java函数式编程示例:Lambda函数/方法引用/4种内建函数式接口(功能性-/消费型/供给型/断言型)
本示例展示了Java中函数式接口的使用,包括自定义和内置的函数式接口。通过方法引用,实现对字符串操作如转换大写、数值转换等,并演示了Function、Consumer、Supplier及Predicate四种主要内置函数式接口的应用。
14 1
|
8天前
|
Java
让星星⭐月亮告诉你,Java synchronized(*.class) synchronized 方法 synchronized(this)分析
本文通过Java代码示例,介绍了`synchronized`关键字在类和实例方法上的使用。总结了三种情况:1) 类级别的锁,多个实例对象在同一时刻只能有一个获取锁;2) 实例方法级别的锁,多个实例对象可以同时执行;3) 同一实例对象的多个线程,同一时刻只能有一个线程执行同步方法。
9 1
|
6天前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
7 0
|
SQL Java 关系型数据库
java8 多字段分组+count
java8 多字段分组+count
java8 多字段分组+count
|
4天前
|
安全 Java UED
Java中的多线程编程:从基础到实践
本文深入探讨了Java中的多线程编程,包括线程的创建、生命周期管理以及同步机制。通过实例展示了如何使用Thread类和Runnable接口来创建线程,讨论了线程安全问题及解决策略,如使用synchronized关键字和ReentrantLock类。文章还涵盖了线程间通信的方式,包括wait()、notify()和notifyAll()方法,以及如何避免死锁。此外,还介绍了高级并发工具如CountDownLatch和CyclicBarrier的使用方法。通过综合运用这些技术,可以有效提高多线程程序的性能和可靠性。
|
4天前
|
缓存 Java UED
Java中的多线程编程:从基础到实践
【10月更文挑战第13天】 Java作为一门跨平台的编程语言,其强大的多线程能力一直是其核心优势之一。本文将从最基础的概念讲起,逐步深入探讨Java多线程的实现方式及其应用场景,通过实例讲解帮助读者更好地理解和应用这一技术。
22 3
|
8天前
|
Java 调度 UED
深入理解Java中的多线程与并发机制
本文将详细探讨Java中多线程的概念、实现方式及并发机制,包括线程的生命周期、同步与锁机制以及高级并发工具。通过实例代码演示,帮助读者理解如何在Java中有效地处理多线程和并发问题,提高程序的性能和响应能力。