java反射(Reflection)

一,概述

反射机制允许程序在运行期间获得任何类的任何内部信息,并直接操作任意对象的内部属性和方法。

正是由于反射机制的存在,使java被视为准动态语言。

动态编程语言(Dynamic programming Language):
动态语言是指程序在运行时可以改变其结构。比如,新的函数可以被引进,已有的函数可以被删除等在结构上的变化。

静态类型语言(Statically Typed Language):
静态类型语言数据类型是在编译其间检查的。即是,在写程序时要声明所有变量的数据类型。

Class类:
反射与Class类是有密切关系的,学习反射前先搞清楚这个Class类。它就像平时常用的String类一样,是java的某个包中的一个类,只是String类更常用。

因为Class是一个类,所以当然可以定义创建一个Class的对象,比如Class c = ...;便定义了一个名为c的Class对象,又称类对象(只是把Class这个英文单词翻译成中文“类”)。

  • 类的对象
  • 任何的对象都叫类的对象;
  • String s = ...; Person p = ...; s和p都叫类的对象,上面的c也叫类的对象;
  • 只是,s是String类的对象,p是Person类的对象,c是Class类的对象;
  • 而c又称类对象,s又称字符串对象,p又称人类对象。

Class是java.lang包中的类,该类的实例可以帮助程序创建其他类的实例。

创建对象最常用的方法是使用new运算符和类的构造函数,但使用Class对象也可以获得某个类的实例。

Class对象(类对象)
是类加载的产物,封装了一类的所有信息(包括类名、父类、接口、属性、方法、构造函数);即,将类看作对象,在每个类的基础上在抽象一个类——Class类。

  • Class对象指向一个类,就如String对象指向一个字符串。

关于Class类和Class对象的更深层的内容,还需要对类的加载与ClassLoader学习之后研究。

二,获取类对象的三种方法

①通过类的对象获取类对象

Student stu = new Student();
Class<?> c = stu.getClass();

②通过类名获取类对象

Class c2 = Student.class;

③通过静态方法获取类对象

Class c3 = Class.forName("reflection.Student"); //"包名.类名"

方法①②在使用时需要类存在,依赖性较强,而方法③允许在编译时类可不存在,更方便使用。

		Student stu = new Student();
		Class<?> c1 = stu.getClass();		
		System.out.println(c1);
		
		Class c2 = Student.class;
		System.out.println(c2);
		
		try {
			Class c3 = Class.forName("reflection.Student");
			System.out.println(c3);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

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

从运行结果可以看出,三中方法产生的Class对象相同。

一个类只有一个Class对象。(深层内容要研究类的加载)

三,与反射相关的方法

①使用Class的方法,获取包名、包、父类和实现的接口。

String cname = c.getName();//返回由类对象表示的实体的名称,作为 String
		Package pack = c.getPackage(); //获得此类的包
		Class<?> parent = c.getSuperclass(); //返回该类的父类
		Class<?>[] interfaces = c.getInterfaces(); //返回由类对象表示的类实现的接口
		
		System.out.println(cname);
		System.out.println(pack);
		System.out.println(parent);
		for(Class<?> in : interfaces)
		{
			System.out.println(in);
		}

在这里插入图片描述

②使用构造函数创建类的对象:

		Class<?> c = null;
		//1,获取类的类对象
		try {
			c = Class.forName("reflection.Student");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//2,获取类的所有构造方法
		Constructor<?>[] cons = c.getConstructors();
		//3,获取类的无参构造函数
		Constructor<?> con = null;
		Student s = null;
		try {
			con = c.getConstructor();
		//4,使用构造函数构建类的对象
			s = (Student)con.newInstance();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(s.toString());
		
		//5,获取类的有参构造函数
		Constructor<?> con2 = null;
		Student s2 = null;
		try {
			con2 = c.getConstructor(String.class,int.class,boolean.class);
		//6,使用类的有参构造函数创建类的对象
			s2 = (Student)con2.newInstance("小明",12,true);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		System.out.println(s2.toString());

在这里插入图片描述
③使用Class对象调用newInstance()实例化类的对象

	    Class<?> c = null;
		Student s = null;
		try {
			//1,获取类的类对象
			c = Class.forName("reflection.Student");
			//2,创建无参对象
			s = (Student) c.newInstance();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(s.toString());

在这里插入图片描述
此时,Student类必须有无参构造方法。通过此方法好像不能创建有参的对象。

④ Method相关方法
1)获得类中的包括继承的在内的public方法

		//2,获得Student类的public方法,(包括继承的)
		Method[] mets = c.getMethods();
		for(Method m : mets)
		{
			System.out.println(m);
		}

在这里插入图片描述
2)获取类的所有的(private、default、protect、public)的方法,不包含继承的

		//3,获得类Student的所有方法,不包括继承的
		Method[] mets = c.getDeclaredMethods();
		for(Method m:mets)
		{
			System.out.println(m);
		}

在这里插入图片描述
3)获取指定的方法

Class<?> c = null;
		Student s = null;
		try {
			//1,获取类的类对象
			c = Class.forName("reflection.Student"); //现在c是指向类Student的类对象		
			s = (Student)c.newInstance();
			
			//3,获得类Student的指定的方法,无参无返回值
			Method studyMet = c.getMethod("study");
			//3,调用对象s的study方法
			studyMet.invoke(s);
			
			//4,获得带返回值的方法
			Method playMet1 = c.getMethod("play");
			//4,调用对象s的play方法,有返回值
			String res = (String)playMet1.invoke(s);
			System.out.println(res);
			
			//5,获得带参带返回值的方法
			Method playMet2 = c.getMethod("play",String.class);
			//5,调用对象s的play方法,有参有返回值
			String res2 = (String)playMet2.invoke(s, "乒乓球");
			System.out.println(res2);
 			 
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		

在这里插入图片描述
4)获取类的私有方法

	//6,获取类的私有方法
	Method privateMet = c.getDeclaredMethod("fangfa");
	privateMet.setAccessible(true); //设置访问权限无效
	privateMet.invoke(s);	

其中,私有方法在获取之后不能调用执行的,可通过setAccessible(true)方法,设置该方法的访问权限无效,后方可调用私有方法。

5)类的静态方法

			//1,获取类的类对象
			c = Class.forName("reflection.Student"); //现在c是指向类Student的类对象		
			s = (Student)c.newInstance();
			
			//7,获取类的静态方法	
			Method staticMet = c.getMethod("fun",String.class);
			//7,调用静态方法
			staticMet.invoke(null, "123");
			staticMet.invoke(s, "234");
 			 

在这里插入图片描述
其中需要注意的是,调用静态方法时,可不传对象。

⑤获取属性相关方法
1)获取类中的所有public的属性,包括继承的

			//获得类中的所有public属性,包括继承
			Field[] fields = c.getFields();
			for(Field f:fields)
			{
				System.out.println(f);
			}

在这里插入图片描述
2)获取属性的所有方法,不包括继承

			//获得类中的所属性,不包括继承
			Field[] fields = c.getDeclaredFields();
			for(Field f:fields)
			{
				System.out.println(f);
			}

在这里插入图片描述
3)获取指定的属性并操作

			//2,获取指定的属性
			Field name = c.getDeclaredField("name");
			
			//设置访问权限无效
			name.setAccessible(true);
			
			//3,给指定的对象的name赋值
			name.set(s, "小明");
			//4,读取指定对象的name的值
			System.out.println(name.get(s));

四,实践——使用反射实现一个可以调用任何对象方法的通用方法

static Object invokeAny(Object obj,String methodName,Class<?>[] types,Object ...args)throws Exception
	{
		//1,获取类对象
		Class<?> cs = obj.getClass();
		//2,获取方法
		Method method = cs.getMethod(methodName, types);
		//调用
		return method.invoke(obj, args);
	}

调用:

Test.invokeAny(s,"play",new Class[]{String.class},"篮球");

以上内容是我个人在学习之后的梳理和总结,旨在使所学的内容更加清晰和方面后续复习,故请不勿喷语言表达不清和逻辑结构不清的地方,但虚心接受大家的交流和指导,如果本文能对大家的学习起到帮助,我深感荣幸!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值