Java反射最全面总结(附代码)

Java反射最全面总结

Java中的编译类型

①.静态编译:在编译时确定类型,绑定对象即通过
②.动态编译:在运行时确定对象类型,绑定对象体现了Java的灵活性和多态性,降低类之间的耦合度。
反射的原理

反射是什么?

Java在运行时,对于任何一个类都能获得这个类的信息(属性、方法、修饰符等等),还可以在运行时实例化对象,实现动态创建对象

反射的执行流程

Java程序通过javac产生.class文件,通过JVM的类加载器加载class文件,并生成Class对象(注意Class对象只创建一次)Class对象是反射的源头。反射的本质是获取Class对象之后反向获取被反射类的各种信息。请看下图:
在这里插入图片描述

为什么用反射

  • 使用反射可以赋予JVM动态编译的能力,否则类的元数据信息只能使用静态编译的实现,当我们写的程序运行时,需要动态的加载,提升服务器的性能。
  • 使用Java的方式机制可以增加程序的灵活性,避免程序写死

反射的实现类

Class类:反射的源头
主要描述: 当创建一个类的时候首先通过编译生成相应的class文件,之后通过JVM的类的加载器,将class文件加载到内存中,创建一个Class对象Class对象只会加载一次
获取class对象的四种方法:

        // 方式1.调用运行时类本身的class属性
    	Class<Person> clazz1 = Person.class;
    	// getName获取完整路径(全限定名或者完全限定名)
    	System.out.println(clazz1.getName());
    	// 方式2.通过运行时类getClass方法
    	Person person = new Person();
    	Class<Person> clazz2 = (Class<Person>) person.getClass();
    	System.out.println(clazz2.getName());
    	//3.通过Class。forName(“全路径”)静态方法
    	Class clazz3 = Class.forName("com.hpe.reflect.Person");
    	System.out.println(clazz3.getName());
    	// 4.通过类加载器ClassLoader
    	ClassLoader classLoader = this.getClass().getClassLoader();
    	Class class4 = classLoader.loadClass("com.hpe.reflect.Person");
    	System.out.println(class4.getName());

常见的方法:

      getDeclaredFields():获取类所有属性
       getField(String name):获取类的指定属性
       getMothods():获取类的public类型方法
       getMethod (String name,Class [] args)获得类的指定方法
       getConstrutors()获得类的public类型的构造方法
       getConstrutor(Class[] args)获得类的特定构造方法
        newInstance()通过类的无参构造方法创建一个对象
       getName()获得类的完整名字
       getPackage()获取此类所属的包
   getSuperclass()获得此类的父类对应的Class对象

使用反射反射创建对象,访问类的结构

  // 获取Person类的Class类对象
    	Class<Person> clazz = Person.class;
    	// 常见clazz对应的运行时类的Person对象
    	Person person = (Person) clazz.newInstance();
    	System.out.println(person);
    	// 通过反射获取运行时类的指定属性
    	Field f1 = clazz.getField("name");
    	// 设置属性
    	f1.set(person, "jack");
    	System.out.println(person);
    	Field f2 = clazz.getDeclaredField("age");
    	f2.setAccessible(true);
    	// 设置属性
    	f2.set(person, 20);
    	System.out.println(person);
    	// 通过反射获取运行时指定的方法
    	Method method = clazz.getMethod("show");
    	// 调用方法(指明实例对象和参数值)
    	method.invoke(person);
    	Method m2 = clazz.getMethod("display", String.class);
    	m2.invoke(person, "China");

获取Class对象的方式:

// 方式1.调用运行时类本身的class属性
    	Class<Person> clazz1 = Person.class;
    	// getName获取完整路径(全限定名或者完全限定名)
    	System.out.println(clazz1.getName());
    	// 方式2.通过运行时类getClass方法
    	Person person = new Person();
    	Class<Person> clazz2 = (Class<Person>) person.getClass();
    	System.out.println(clazz2.getName());
    	//3.通过Class。forName(“全路径”)静态方法
    	Class clazz3 = Class.forName("com.hpe.reflect.Person");
    	System.out.println(clazz3.getName());
    	// 4.通过类加载器ClassLoader
    	ClassLoader classLoader = this.getClass().getClassLoader();
    	Class class4 = classLoader.loadClass("com.hpe.reflect.Person");
    	System.out.println(class4.getName());

Field:

获取对应运行时类的属性

  // 1.getFields():获取运行时类及其父类声明的public的属性
    	Field[] fields = clazz.getFields();
    	for (int i = 0; i < fields.length; i++) {
			System.out.println(fields[i])}
    	// 2.getDeclareFields():获取运行时类的本身声明的所有属性
    	Field[] fields2 = clazz.getDeclaredFields();
    	for (Field field : fields2) {
			System.out.println(field.getName());
	}

获取属性的各个部分的内容(权限修饰符、类型、名称)

 Class clazz = Person.class;
	Field[] fields = clazz.getDeclaredFields();
	for (Field f : fields) {
		// 1.获取每个属性的权限修饰符
	System.out.println(Modifier.toString(f.getModifiers()));
	// 2.获得属性的类型
	Class type = f.getType();
	String typeName = type.getName();
	System.out.println(typeName);
	// 3.获取属性名称
	System.out.println(f.getName());
}

获取运行时类的指定属性

  Class clazz = Class.forName("com.hpe.reflect.Person");
    	// 1.获取指定的属性
    	// getFields(String name):获取运行时类中声明问public的类型名的属性
    	Field name = clazz.getDeclaredField("name");
    	name.setAccessible(true);
    	// 2.创建运行时的随想
    	Person p = (Person)clazz.newInstance();
    	System.out.println(p);
    	// 3.设置属性值
    	name.set(p, "eric");
    	System.out.println(p);
    	// 4.getDeclareField(String filedName):获取运行时指定的属性值
    	Field age = clazz.getDeclaredField("age");
    	// 由于属性权限修饰符的问题,为了给属性赋值时,需要在操作前使得该属性可被操作
    	age.setAccessible(true);
    	age.set(p, 25);
    	System.out.println(p);

Constructor类:

 	// 创建对应的运行时的对象使用newInstance 实际上调用了运行时类的空参构造器
// 创建运行类的对象条件①。空参构造器,访问权限要足够
Object newInstance = clazz.newInstance();
Person p = (Person) newInstance;
11.获取构造器:
         Class clazz = Person.class;
		 Constructor[] cons = clazz.getDeclaredConstructors();
		 for (Constructor c : cons) {
			System.out.println(c);
		}

.调用指定的构造器,创建运行时对象

  Class clazz = Person.class;
// 调用空参构造器
Constructor c = clazz.getDeclaredConstructor();
    Person p1 = (Person) c.newInstance();
System.out.println(p1);
// 通过getDeclaredConstructor方法传入指定的参数可以获取所有参数的构造器
Constructor cons = clazz.getDeclaredConstructor(String.class, int.class);
// 通过构造器newInstance方法传入参数值创建对象
Person person = (Person) cons.newInstance("jack",20);
System.out.println(person);

不能注释掉原类的无参构造器
Method类:表示类的方法:

获取运行类中的方法:

// 1.getMethods():获取运行时类及其父类声明问public的方法
	Method[] methods = clazz.getMethods();
	for (Method method : methods) {
		System.out.println(method);
}
	System.out.println("---------------------------");
	// 2.getDeclaredMothods():获取运行类声明的所有方法
	Method[] m = clazz.getDeclaredMethods();
	for (Method method : m) {
		System.out.println(method);
	}

调用运行时类的指定的方法:

 Class<Person> clazz = Person.class;
	// 创建运行类的对象
	Person p = (Person) clazz.newInstance();
	// 获取属性
	Field f_name = clazz.getDeclaredField("name");
	Field f_age = clazz.getDeclaredField("age");
	// 设置允许访问属性
	f_age.setAccessible(true);
	f_name.setAccessible(true);
	// 设置属性值
	f_name.set(p, "tina");
	f_age.set(p, 30);
	// 1. 获取运行时类中声明为public的方法
	Method m1 = clazz.getMethod("show");
	// 2.调用方法 invoke(指定对象,方法的参数)
	m1.invoke(p);
	// 调用有返回值的参数
	Method m2 = clazz.getMethod("sayHello");
	Object returnVall = m2.invoke(p);
	System.out.println(returnVall);
	// 3.调用静态方法
	Method m3 = clazz.getMethod("info");
	// 相当于类名。方法名
	m3.invoke(Person.class);
	// 4.调用带参数的方法
	// 获取所有运行时类中所有的方法getDeclareMethod()
	Method m4 = clazz.getDeclaredMethod("display", String.class);
	// 调用方法的同时传入参数值
	m4.invoke(p, "China");

调用有参数的构造器创建运行类对象,调用相关方法:

 Class<Person> clazz = Person.class;
	Constructor<Person> cons = clazz.getConstructor(String.class, int.class);
	// 通过有残构造器近视运行类的赋值(初始化成员属性)
	Person p = cons.newInstance("tom,25");
	// 获取方法
	Method m1 = clazz.getMethod("display", String.class);
	// 调用方法
	m1.invoke(m1, "CHN");

文件的操作:

   // 读取配置文件(
	FileReader in = new FileReader(new File("propertices"));
	// 将流加载到配置文件
	properties.load(in);
	in.close();
	
	// 获取用户名和密码
	String username = properties.getProperty("user");
	String password = properties.getProperty("password");
	System.out.println("用户名:"+ username + " 密码:"+password);
	
	//通过反射获取Class对象
	Class<?> clazz = Class.forName(properties.getProperty("className"));
	Method m1 = clazz.getMethod(properties.getProperty("methodName"));
	// 创建student的运行时对象
	//Student student = (Student) clazz.newInstance();
	// 调用show方法
	m1.invoke(clazz.getConstructor().newInstance());
	//m1.invoke(student);

泛型擦除 程序编译后产生的。Class文件没有泛型约束的,这种现象就做泛型的擦除:

ArrayList<Integer> arr = new ArrayList<>();
	arr.add(123);
	//获取ArrayLiist的字节码对象
	Class<? extends ArrayList> c = arr.getClass();
	// 通过反射的方式获得add方法
	Method m = c.getMethod("add", Object.class);
	// 调用方法
	m.invoke(arr, "abc");
	System.out.println(arr);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值