类加载机制与反射3——通过反射查看类信息

本文详细介绍了Java中的类加载机制,包括如何获得Class对象,以及从Class对象中获取类的详细信息。重点讲解了Java8的新特性,即方法参数反射,包括Executable抽象基类的使用,获取参数个数、形参名以及相关修饰符的方法。同时,讨论了如何在编译时保留方法形参名信息。
摘要由CSDN通过智能技术生成
Java程序中的许多对象在运行时都会出现两种类型:编译时类型和运行时类型,例如代码:Person p = new Student();这行代码将会生成一个p变量,该变量的编译时类型为Person,运行时类型为Student;除此之外,还有更极端的情形,程序在运行时接收到外部传入的一个对象,该对象的编译时类型是Object,但程序又需要调用该对象运行时类型的方法。
为了解决这些问题,程序需要在运行时发现对象和类的真实信息。解决该问题有以下两种做法。
①第一种做法是假设在编译时和运行时都完全知道类型的具体信息,在这种情况下,可以先使用instanceof运算符进行判断,再利用强制类型转换将其转换成其运行时类型的变量即可。
②第二种做法是编译时根本无法预知该对象和类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息,这就必须使用反射。
  • 获得Class对象
  • 从Class中获取信息
  • Java8新增的方法参数反射

1.获得Class对象

     每个类被加载之后,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类。
在Java程序中获得Class对象通常有如下三种方式。
①使用Class类的forName(String clazzName)静态方法。其中clazzName是某个类的全限定类名(必须添加完整包名);
②调用某个类的class属性来获取该类对应的Class对象。
③调用某个对象的getClass()方法。

一旦获得了某个类所对应的Class对象之后,程序就可以调用Class对象的方法来获得该对象和该类的真实信息了。

2.从Class中获取信息

        Class类提供了大量的实例方法来获取该Class对象所对应类的详细信息,用的时候查阅API即可。eg:可以获取Class对应类所包含的构造器、方法、成员变量、Annotation、内部类、外部类、实现的接口、继承的父类、修饰符、所在包、类名等基本信息、判断该类是否接口、枚举、注解类型等;

通过Class对象可以得到大量的Method、Constructor、Field等对象,这些对象分别代表该类所包括的方法、构造器和成员变量等信息,程序还可以通过这些对象来执行实际的功能,例如调用方法、创建实例。

3.Java8新增的方法参数反射

        Java8在java.lang.reflect包下新增了一个Executable抽象基类,该对象代表可执行的类成员,该类派生了Constructor、Method两个子类。Executable基类提供了大量方法来获取修饰该方法或构造器的注解信息;还提供了isVarArgs()方法用于判断该方法或构造器是否包含数量可变的形参,以及通过getModifiers()方法来获取该方法或构造器的修饰符。除此之外,Executable提供了如下两个方法来获取该方法或参数的参数个数及形参名。
int getParameterCount():获取该构造器或方法的所有形参;
Parameter[] getParameters():获取该构造器或方法的所有形参;
上面第二个方法返回了一个Parameter[]数组,Parameter也是Java8新增的API,每个Parameter对象代表方法或构造器的一个参数。
Parameter也提供了大量方法来获取声明该参数的泛型信息,还提供了如下常用方法来获取参数信息;
getModifiers():获取修饰该形参的修饰符。
String getName():获取形参名
Type getParameterizedType():获取带泛型的形参类型
Class<?> getType():获取形参类型
boolean isNamePresent():该方法返回该类的class文件中是否包含了方法的形参名信息
boolean isVarArgs():该方法用于判断该参数是否为个数可变的形参
需要指出的是,使用javac命令编译Java源文件时,默认生成的class文件并不包含方法的形参名信息,因此调用isNamePresent()方法将返回false,

调用getName()方法也不能得到该参数的形参名。如果希望javac命令编译java源文件是可以保留形参信息,则需要为该命令指定-parameters选项。

class Test
{
	public void replace(String str, List<String> list){}
}
public class MethodParameterTest
{
	public static void main(String[] args)throws Exception
	{
		// 获取String的类
		Class<Test> clazz = Test.class;
		// 获取String类的带两个参数的replace()方法
		Method replace = clazz.getMethod("replace"
			, String.class, List.class);
		// 获取指定方法的参数个数
		System.out.println("replace方法参数个数:" + replace.getParameterCount());
		// 获取replace的所有参数信息
		Parameter[] parameters = replace.getParameters();
		int index = 1;
		// 遍历所有参数
		for (Parameter p : parameters)
		{
			if (p.isNamePresent())
			{
				System.out.println("---第" + index++ + "个参数信息---");
				System.out.println("参数名:" + p.getName());
				System.out.println("形参类型:" + p.getType());
				System.out.println("泛型类型:" + p.getParameterizedType());
			}
		}
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值