反射
反射机制概述:
JAVA反射机制是在运行转态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息
以及动态调用对象的方法的功能称为java语言的反射机制。简单一句话:反射技术可以对一个类进行解剖。要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。
Class类——反射的基石:
java中所有的类文件都有共性的内容,可以进行向上抽取,把这些共性内容用类进行封装,这个类就是Class。Class类封装了java类中定义的成员变量,成员方法,构造函数等。
获取Class对象的三种方式:
1:通过对象的getClass()方法获取(每个class都有此方法)
示例:
String str = "abc";
Class c = str.getClass();
2:任何数据类型都有一个静态的属性class,这个属性可以直接获取到该类的Class对象。
示例:
Class c = String.class;
3:使用Class类中的静态方法forName();
示例:
Class c = Class.froName("java.lang.String");
这种方法这样知道类名称就可以获取字节码文件,不需要使用该类,也不需要去调用该类具体的方法和属性,所以更有利于程序的扩展。
九个预定义Calss的示例对象:
1:八种基本数据类型(byte,short,int,long,float,double,char,boolean)字节码对象和一种返回值为空void类型的void.class。
2:Integer.TYPE是Integer类的一个常量,它代表此包装类型包装的基本类型的字节码,所以和ing.class是相等的。基本数据类型的字节码都可以用与之对应的包装类中
的TYPE常量表示。
isPrimitive()方法可以判断是否是基本数据类型的字节码。
Class类中的方法:
static Class forName(String className)
返回与给定字符串名的类或接口的相关联的Class对象。
Class getClass()
返回的是Object运行时的类,即返回Class对象即字节码对象
Constructor getConstructor()
返回Constructor对象,它反映此Class对象所表示的类的指定公共构造方法。
Field getField(String name)
返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段。
Field[] getFields()
返回包含某些Field对象的数组,表示所代表类中的成员字段。
Method getMethod(String name,Class… parameterTypes)
返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法。
Method[] getMehtods()
返回一个包含某些Method对象的数组,是所代表的的类中的公共成员方法。
String getName()
以String形式返回此Class对象所表示的实体名称。
String getSuperclass()
返回此Class所表示的类的超类的名称
boolean isArray()
判定此Class对象是否表示一个数组
boolean isPrimitive()
判断指定的Class对象是否是一个基本类型。
T newInstance()
创建此Class对象所表示的类的一个新实例。
Constructor:
如果指定的类中没有空参数的构造函数,或者要创建的类对象需要通过指定的构造函数进行初始化。这时怎么办呢?这时就不能使用Class类中的
newInstance方法了。既然要通过指定的构造函数进行对象的初始化。就必须先获取这个构造函数——Constructor。Constructor代表某个类的构造方法。
获取构造方法:
得到这个类的所有构造方法:以Student类为例
Constructor[] cons = Class.forName(“cn.itheima.Person”).getConstructors();
获取某一个构造方法:
Constructor con=Person.class.getConstructor(String.class,int.class);
创建实例对象:
通常方式:Person p = new Person(“lisi”,30);
反射方式:Person p= (Person)con.newInstance(“lisi”,30);
Filed类:
Filed类代表某个类中的一个成员变量。
常用方法:
Field getField(String s);
只能获取公有和父类中公有变量
Field getDeclaredField(String s);
获取该类中任意成员变量,包括私有
setAccessible(ture);
如果是私有字段,要先将该私有字段进行取消权限检查的能力。也称暴力访问。
set(Object obj, Object value);
将指定对象变量上此Field对象表示的字段设置为指定的新值。
Object get(Object obj);
返回指定对象上Field表示的字段的值。
下面通过一段代码演示一下Filed的常用方法:
<span style="font-size:12px;">package com.heima.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import com.heima.bean.Person; public class Demo4_Field { public static void main(String[] args) throws Exception { Class clazz = Class.forName("com.heima.bean.Person"); Constructor c = clazz.getConstructor(String.class,int.class); //获取有参构造 Person p = (Person) c.newInstance("张三",23); //通过有参构造创建对象 //Field f = clazz.getField("name"); //获取姓名字段 //f.set(p, "李四"); //修改姓名的值 Field f = clazz.getDeclaredField("name"); //暴力反射获取字段 f.setAccessible(true); //去除私有权限 f.set(p, "李四"); System.out.println(p); } } </span>
Method类:
Method类代表某个类中的一个成员方法。调用某个对象身上的方法,要先得到方法,再针对某个对象调用。
常用方法:
Method[] getMethods();
只获取公共和父类中的方法。
Method[] getDeclaredMethods();
获取本类中包含私有。
Method getMethod("方法名",参数.class(如果是空参可以写null));
Object invoke(Object obj ,参数);调用方法
如果方法是静态,invoke方法中的对象参数可以为null。
下面通过一段代码演示Method类的常用方法
<span style="font-size:12px;">package com.heima.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import com.heima.bean.Person; public class Demo5_Method { public static void main(String[] args) throws Exception { Class clazz = Class.forName("com.heima.bean.Person"); Constructor c = clazz.getConstructor(String.class,int.class); //获取有参构造 Person p = (Person) c.newInstance("张三",23); //通过有参构造创建对象 Method m = clazz.getMethod("eat"); //获取eat方法 m.invoke(p); Method m2 = clazz.getMethod("eat", int.class); //获取有参的eat方法 m2.invoke(p, 10); } } </span>
数组的反射:
1;具有相同类型和相同维数的数组共享同一份字节码,即同一个Class类。
2;代表数组的Class实例对象的getSupperClass()方法返回的父类为Object类对应的Class。
3;基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,即可以做Object类型使用,又可以当作Object[]类型使用。
4;Array.asList()方法处理int[]和String[]的时候是有差异的;
例如:
用Array中的asList()方法处理String[]:
Arrays.asList(new String[] {"aa", "bb", "cc"});转换后的List集合里面有3个元素,分别是"aa", "bb", "cc";
用Array中的asList()方法处理int[]:
Arrays.asList(new int[] {1, 2, 3});转换后的List集合里面就只有一个元素,这个元素就是new int[] {1, 5, 9}这个数组本身。
5;Array工具类用于完成数组的反射操作,类里面的方法都是静态的;
如以下代码:
<span style="font-size:12px;">public void printObject(Object obj) { if(obj.getClass().isArray()) { for(int i = 0; i < Array.getLength(obj); i++) { System.out.println(Array.get(obj, i)); } } else { System.out.println(obj); } } </span>