java中的反射机制

1.Java Reflection

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

2.Java反射机制提供的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的成员变量和方法
  • 生成动态代理

3.反射相关的主要API

  • java.lang.Class:代表一个类
  • java.lang.reflect.Method:代表类的方法
  • java.lang.reflect.Field:代表类的成员变量
  • java.lang.reflect.Constructor:代表类的构造方法

4.class类

在Object类中定义了以下的方法,此方法将被所有子类继承:● public final Class getClass()
以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称。
在这里插入图片描述

5.类的加载过程

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化。

在这里插入图片描述
在这里插入图片描述

6.获取Class类的实例的四种方式

  1. 调用运行时类本身的.class属性
	Class clazz1 = Person.class;
	System.out.println(clazz1.getName());
  1. 通过运行时类的对象获取
	Person p = new Person();
	Class clazz3 = p.getClass();
	System.out.println(clazz3.getName());
  1. 通过Class的静态方法获取
	String className = "com.atguigu.java.Person";
	Class clazz4 = Class.forName(className);
	System.out.println(clazz4.getName());
  1. (了解)通过类的加载器
	ClassLoader classLoader = this.getClass().getClassLoader();
	Class clazz5 = classLoader.loadClass(className);
	System.out.println(clazz5.getName());

7.反射机制的使用

通过反射机制,可以创建类对象并获取类的全部结构(属性、方法、构造器、父类、接口、注解等)
我们先定义一个测试类Person,这个类继承自Creature、实现了Comparable和MyInterface接口、有自定义注解MyAnnotation等以方便后面的测试。

  • Creature父类
public class Creature<T>{
	public double weight;
	
	public void breath(){
		System.out.println("呼吸!");
	}
}

  • MyInterface接口
import java.io.Serializable;

public interface MyInterface extends Serializable{

}
  • 自定义注解MyAnnotation
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
	String value();
}

  • Person测试类
@MyAnnotation(value = "atguigu")
public class Person extends Creature<String> implements Comparable,MyInterface{
	public String name;
	private int age;
	int id;
	//创建类时,尽量保留一个空参的构造器。
	public Person() {
		super();
	}
	public Person(String name) {
		super();
		this.name = name;
	}
	private Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	@MyAnnotation(value = "abc123")
	public void show(){
		System.out.println("我是一个人!");
	}
	
	private Integer display(String nation,Integer i) throws Exception{
		System.out.println("我的国籍是:" + nation);
		return i;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	@Override
	public int compareTo(Object o) {
		// TODO Auto-generated method stub
		return 0;
	}
	
	public static void info(){
		System.out.println("中国人!");
	}
	
	class Bird{
		
	}
	
}
7.1 获取并调用构造器

获取全部的构造器

  • public Constructor<T>[] getConstructors()
    返回此 Class 对象所表示的类的所有public构造方法。
  • public Constructor<T>[] getDeclaredConstructors()
    返回此 Class 对象表示的类声明的所有构造方法。

Constructor类中

  • 取得修饰符: public int getModifiers();
  • 取得方法名称: public String getName();
  • 取得参数的类型:public Class<?>[] getParameterTypes();
  • 创建对应的运行时类的对象。使用newInstance(),实际上就是调用了运行时类的空参的构造器.要想能够创建成功:①要求对应的运行时类要有空参的构造器。②构造器的权限修饰符的权限要足够。参见test1()
@Test
	public void test1() throws Exception{
		String className = "com.atguigu.java.Person";
		Class clazz = Class.forName(className);
		//创建对应的运行时类的对象。使用newInstance(),实际上就是调用了运行时类的空参的构造器。
		//要想能够创建成功:①要求对应的运行时类要有空参的构造器。②构造器的权限修饰符的权限要足够。
		Object obj = clazz.newInstance();
		Person p = (Person)obj;
		System.out.println(p);
	}

运行结果
在这里插入图片描述

  • 获取类中所有的构造器,共有三个构造器,其中含有两个参数的构造器的修饰符为private,参见test2()
	@Test
	public void test2() throws ClassNotFoundException{
		String className = "com.atguigu.java.Person";
		Class clazz = Class.forName(className);
		
		Constructor[] cons = clazz.getDeclaredConstructors();
		for(Constructor c : cons){
			System.out.println(c);
		}
	}

运行结果
在这里插入图片描述

  • 调用指定的构造器,参见test3()
	//调用指定的构造器,创建运行时类的对象
	@Test
	public void test3() throws Exception{
		String className = "com.atguigu.java.Person";
		Class clazz = Class.forName(className);
		
		Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
		cons.setAccessible(true);
		Person p = (Person)cons.newInstance("罗伟",20);
		System.out.println(p);
	}

运行结果
在这里插入图片描述

7.2 获取并调用方法

获取全部的方法

  • public Method[] getDeclaredMethods()
    返回此Class对象所表示的类或接口的全部方法
  • public Method[] getMethods()
    返回此Class对象所表示的类或接口的public的方法

Method类中

  • public Class<?> getReturnType()取得全部的返回值
  • public Class<?>[] getParameterTypes()取得全部的参数
  • public int getModifiers()取得修饰符
  • public Class<?>[] getExceptionTypes()取得异常信息
  • 获取类中的全部方法
	@Test
	public void test1(){
		Class clazz = Person.class;
		//1.getMethods():获取运行时类及其父类中所有的声明为public的方法
		Method[] m1 = clazz.getMethods();
		for(Method m : m1){
			System.out.println(m);
		}
		System.out.println();
		//2.getDeclaredMethods():获取运行时类本身声明的所有的方法(包括私有方法)
		Method[] m2 = clazz.getDeclaredMethods();
		for(Method m : m2){
			System.out.println(m);
		}
	}

运行结果
在这里插入图片描述

  • 获取方法中的注解 权限修饰符 返回值类型 方法名 形参列表 异常
	@Test
	public void test2(){
		Class clazz = Person.class;
		
		Method[] m2 = clazz.getDeclaredMethods();
		for(Method m : m2){
			//1.注解
			Annotation[] ann = m.getAnnotations();
			for(Annotation a : ann){
				System.out.println(a);
			}
			
			//2.权限修饰符
			String str = Modifier.toString(m.getModifiers());
			System.out.print(str + " ");
			//3.返回值类型
			Class returnType = m.getReturnType();
			System.out.print(returnType.getName() + " ");
			//4.方法名
			System.out.print(m.getName() + " ");
			
			//5.形参列表
			System.out.print("(");
			Class[] params = m.getParameterTypes();
			for(int i = 0;i < params.length;i++){
				System.out.print(params[i].getName() + " args-" + i + " ");
			}
			System.out.print(")");
			
			//6.异常类型
			Class[] exps = m.getExceptionTypes();
			if(exps.length != 0){
				System.out.print("throws ");
			}
			for(int i = 0;i < exps.length;i++){
				System.out.print(exps[i].getName() + " ");
			}
			System.out.println();
		}
	}

运行结果
在这里插入图片描述

  • 调用运行时类中指定的方法
	@Test
	public void test3() throws Exception{
		Class clazz = Person.class;
		//getMethod(String methodName,Class ... params):获取运行时类中声明为public的指定的方法
		Method m1 = clazz.getMethod("show");
		Person p = (Person)clazz.newInstance();
		//调用指定的方法:Object invoke(Object obj,Object ... obj)
		Object returnVal = m1.invoke(p);//我是一个人
		System.out.println(returnVal);//null
		
		Method m2 = clazz.getMethod("toString");
		Object returnVal1 = m2.invoke(p);
		System.out.println(returnVal1);//Person [name=null, age=0]
		//对于运行时类中静态方法的调用
		Method m3 = clazz.getMethod("info");
		m3.invoke(Person.class);
		
		//getDeclaredMethod(String methodName,Class ... params):获取运行时类中声明了的指定的方法
		Method m4 = clazz.getDeclaredMethod("display",String.class,Integer.class);
		m4.setAccessible(true);
		Object value = m4.invoke(p,"CHN",10);//我的国籍是:CHN
		System.out.println(value);//10
	}

运行结果
在这里插入图片描述

7.3 获取并调用属性

获取全部属性

  • public Field[] getFields()
    返回此Class对象所表示的类或接口的public的Field,只能获取到运行时类中及其父类中声明为public的属性
  • public Field[] getDeclaredFields()
    返回此Class对象所表示的类或接口的全部Field,获取运行时类本身声明的所有的属性

Field方法中

  • public int getModifiers() 以整数形式返回此Field的修饰符
  • public Class<?> getType() 得到Field的属性类型
  • public String getName() 返回Field的名称。
  • 获取对应的运行时类的属性
	@Test
	public void test1(){
		Class clazz = Person.class;
		//1.getFields():只能获取到运行时类中及其父类中声明为public的属性
		Field[] fields = clazz.getFields();
		for(int i = 0;i < fields.length;i++){
			System.out.println(fields[i]);
		}
		System.out.println();
		//2.getDeclaredFields():获取运行时类本身声明的所有的属性
		Field[] fields1 = clazz.getDeclaredFields();
		for(Field f : fields1){
			System.out.println(f.getName());
		}
	}

运行结果
在这里插入图片描述

  • 获取属性的各个部分的内容
	@Test
	public void test2(){
		Class clazz = Person.class;
		Field[] fields1 = clazz.getDeclaredFields();
		for(Field f : fields1){
			//1.获取每个属性的权限修饰符
			int i = f.getModifiers();
			String str1 = Modifier.toString(i);
			System.out.print(str1 + " ");
			//2.获取属性的类型
			Class type = f.getType();
			System.out.print(type.getName() + " ");
			//3.获取属性名
			System.out.print(f.getName());
			
			System.out.println();
		}
	}

运行结果
在这里插入图片描述

  • 调用运行时类中指定的属性
	@Test
	public void test3() throws Exception{
		Class clazz = Person.class;
		//1.获取指定的属性
		//getField(String fieldName):获取运行时类中声明为public的指定属性名为fieldName的属性
		Field name = clazz.getField("name");
		//2.创建运行时类的对象 
		Person p = (Person)clazz.newInstance();
		System.out.println(p);
		//3.将运行时类的指定的属性赋值
		name.set(p,"Jerry");
		System.out.println(p);
		System.out.println("%"+name.get(p));
		
		System.out.println();
		//getDeclaredField(String fieldName):获取运行时类中指定的名为fieldName的属性
		Field age = clazz.getDeclaredField("age");
		//由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作。
		age.setAccessible(true);
		age.set(p,10);
		System.out.println(p);		
	}

运行结果
在这里插入图片描述

7.4 获取类中的其他结构
  • 获取运行时类的父类

public Class<? Super T> getSuperclass()返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。

	@Test
	public void test1(){
		Class clazz = Person.class;
		Class superClass = clazz.getSuperclass();
		System.out.println(superClass);
	}

运行结果
在这里插入图片描述

  • 泛型相关

获取父类泛型类型:Type getGenericSuperclass()
泛型类型:ParameterizedType
获取实际的泛型类型参数数组:getActualTypeArguments()

	//2.获取带泛型的父类
	@Test
	public void test2(){
		Class clazz = Person.class;
		Type type1 = clazz.getGenericSuperclass();
		System.out.println(type1);
	}

运行结果
在这里插入图片描述

	//3*.获取父类的泛型
	@Test
	public void test3(){
		Class clazz = Person.class;
		Type type1 = clazz.getGenericSuperclass();
		
		ParameterizedType param = (ParameterizedType)type1;
		Type[] ars = param.getActualTypeArguments();
		
		System.out.println(((Class)ars[0]).getName());
	}

运行结果
在这里插入图片描述

  • 获取实现的接口:public Class<?>[] getInterfaces()
	@Test
	public void test4(){
		Class clazz = Person.class;
		Class[] interfaces = clazz.getInterfaces();
		for(Class i : interfaces){
			System.out.println(i);
		}
	}

运行结果
在这里插入图片描述

  • 获取所在的包:Package getPackage()
	@Test
	public void test5(){
		Class clazz = Person.class;
		Package pack = clazz.getPackage();
		System.out.println(pack);
	}

运行结果
在这里插入图片描述

  • 获取注释
  • get Annotation(Class<T> annotationClass)
  • getDeclaredAnnotations()
	@Test
	public void test6(){
		Class clazz = Person.class;
		Annotation[] anns = clazz.getAnnotations();
		for(Annotation a : anns){
			System.out.println(a);
		}
	}

运行结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值