1.反射
概述:
- 通过一个Class文件对象去使用或者修改文件对象中的成员变量,构造方法,成员方法(无论是否私有,都能获取并使用)
之前学习:
- 我们在使用成员之前,得先有一个java文件,然后在实例化的时候,new一下就完事了。
Person p = new Person();
p.eat(“汉堡”);
现在的船新概念:
- 总归来说,无论是调用什么成员,都是有个对象,归根结底,对象是根据类来的,实际上底层是依赖一个class文件
对于java程序来说,依赖的是这个class文件对应的Class文件对象。
class类:
- 成员变量:Field
- 构造方法:Constructor
- 成员方法:Method
如何获取一个类的对应的Class文件对象呢?
- 方式1:通过Object类中的getClass()方法,返回此Object类的运行时的类
- 方式2:在不new的前提下,获取该类的class文件对象,java中每一个类都有一个静态的属性class
- 方式3:Class类中有一个静态的方法,获取该类的class文件对象 (最常用的)
获取对象对应的class文件对象代码
public class ReflexDemo1 {
public static void main(String[] args) {
//方式一:通过Object类中的getClass()方法,返回此Object类运行时的类
Person person1 = new Person();
Class<? extends Person> c1 = person1.getClass();
Person person2 = new Person();
Class<? extends Person> c2 = person2.getClass();
System.out.println(c1 == c2); //true
//方式二:在不 new 的情况下,获取该类的class文件对象,java中的每一个类都有一个静态的属性class
Class<Person> c3 = Person.class;
System.out.println(c1 == c3); //true
System.out.println(c2 == c3); //true
//方式三:Class类中有一个静态方法,获取该类的class文件对象(最常用的)
//static Class<?> forName(String className)
//返回与给定字符串名称的类或接口相关联的 类对象。
try {
Class<?> c4 = Class.forName("com.bigdat.java.day29.Person");
System.out.println(c4);
System.out.println(c1 == c4); //true
System.out.println(c1 == c4); //true
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
如何通过反射获取Class文件对象并使用其中的构造方法创建对象呢?
- getConstructors() 返回一个包含Constructor对象的数组,反映由此Constructor对象表示的类的所有公共类函数
- getDeclaredConstructors() 获取的是该类中的所有构造方法,包括私有,被保护的,默认的,公共的
- getConstructor() 返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。
- getDeclaredConstructor() 获取单个私有的带参数的构造方法
注意点:
- newInstance(Object… initargs)
使用此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。如果使用带参数的构造方法用newInstance创建对象,参数必须一样。形如:Object o = con1.newInstance(“张三”);- 如果获取带参数的构造方法,里面填的参数是:**类型.class** 。
如:Constructor<?> con2 = c1.getDeclaredConstructor(String.class, int.class);
public class ReflexDemo2 {
public static void main(String[] args) {
//获取person类的Class文件对象
Class<?> c1 = null;
try {
c1 = Class.forName("com.bigdatjava.day29.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取Class文件对象的构造方法
//public Constructor<?>[] getConstructors() throws SecurityException
//返回一个包含Constructor对象的数组,反应由此Constructor对象表示的类的所有的公共类函数
Constructor<?>[] cons1 = c1.getConstructors();
for (Constructor<?> c : cons1) {
System.out.println(c);
}
System.out.println("===========================================================");
//public Constructor<?>[] getDeclaredConstructors() throws SecurityException
//返回Constructor 对象表名的类声明的所有Constructor对象的数组类
//获取的是该类中的所有构造方法,包括私有,被保护,默认和公共的
Constructor<?>[] cons2 = c1.getDeclaredConstructors();
for (Constructor<?> c : cons2) {
System.out.println(c);
}
System.out.println("=================================================================");
//获取单个的构造方法
//Constructor<T> getConstructor(类<?>... parameterTypes)
//返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。
Constructor<?> con1 = null;
try {
con1 = c1.getConstructor(String.class);
System.out.println(con1);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//获取单个私有的带参数的构造方法
// Constructor<?> con2 = c1.getConstructor(String.class, int.class);
// System.out.println(con2);
Constructor<?> con2 = null;
try {
con2 = c1.getDeclaredConstructor(String.class, int.class);
System.out.println(con2);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
System.out.println("======================================================================");
//使用公共的构造方法创建对象
//使用公共的构造方法创建对象
//T newInstance(Object... initargs)
//使用此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
try {
Object o = con1.newInstance("我真蠢!");
Person p = (Person)o; // 向下转型
System.out.println(p);
} catch (Exception e) {
e.printStackTrace();
}
try {
con2.setAccessible(true);
Object two = con2.newInstance("我是小垃圾", 19);
// 向下转型
Person o1 = (Person) two;
System.out.println(o1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
通过反射获取Class文件对象中私有的构造方法并创建对象
重点
- 当还是象访问公共对象去访问私有变量时会报 IllegalAccessException 非法的访问异常
解决办法:暴力访问
- 通过setAccessible(true)方法暴力访问。值是true的化,表示反射对象在使用的时候,取消Java语言的访问检查
public class ReflexDemo3 {
public static void main(String[] args) {
Class<?> a = null;
try {
a = Class.forName("com.bigdat.java.day29.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取私有的构造方法
Constructor<?> dec1 = null;
try {
dec1 = a.getDeclaredConstructor(String.class, int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
// .IllegalAccessException 非法的访问异常
//构造方法是私有的,可以获取的到,但是不能这么使用
//通过构造方法创建对象
//暴力访问
dec1.setAccessible(true); // 如果这里是 true 的话,表示反射对象在这里用的话,取消Java语言的访问检查
Object xh = dec1.newInstance("小花", 100);
//向下转型
Person p = (Person) xh;
System.out.println(p);
p.eat("红烧肉");
} catch (Exception e) {
e.printStackTrace();
}
}
}
反射获取类Class文件对象中的成员变量并使用
- getFields() 返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 类对象。获取当前类所有被public修饰的成员变量
- getDeclaredFields() 返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。获取当前类中所有的成员变量,包括私有的,公共的,被保护的,默认的字段,不包括继承的字段。
- getField() 获取单个的成员变量
- getDeclaredField() 获取私有的成员变量并赋值
- 暴力访问: name.setAccessible(true);
public class ReflexDemo4 {
public static void main(String[] args)throws Exception {
Class<?> c1 = null;
//获取Class的文件对象
try {
c1 = forName("com.bigdat.java.day29.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//Field[] getFields()
//返回一个包含一个数组的 Filed 对象反射由此表示的类或接口的所有可访问的公共字段 类对象。
//获取当前类所有被public修饰的成员变量
Field[] fields = c1.getFields();
for (Field field : fields) {
System.out.println(field); //public java.lang.String com.bigdat.java.day29.Person.id
}
System.out.println("==============================================================");
//Field[] getDeclaredFields()
//返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。
//获取当前类中所有的成员变量,包括私有的,公共的,被保护的,默认的字段,不包括继承的字段。
Field[] dec = c1.getDeclaredFields();
for (Field field : dec) {
System.out.println(field);
}
System.out.println("-----------------------------------------------------------------");
//此方法并不能获得该类继承的其父类的任何属性
Class<?> c2 = null;
try {
c2 = forName("com.bigdat.java.day29.B");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Field[] declaredFields = c2.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("========================================================");
//获取Class文件的对象
Class<?> c = forName("com.bigdat.java.day29.Person");
//通过 getConstructor 方法来创建一个构造器
Constructor<?> ctr = c.getConstructor();
//通过构造方法来创建一个对象
Object o = ctr.newInstance();
//获取单个的成员变量
Field id = c1.getField("id");
//void set(Object obj, Object value)
//将指定对象参数上的此 Field对象表示的字段设置为指定的新值。
//id.set(o,"1001");//给对象o中的成员变量id赋值为"1001"
id.set(o, "1001");
System.out.println(o);
//获取私有的成员变量并赋值
Field name = c1.getDeclaredField("name");
name.setAccessible(true); // 在使用私有的成员变量时需要进行暴力访问
name.set(o, "名字");
System.out.println(o); // IllegalAccessException 不暴力访问的话会报异常
System.out.println("================================================================");
Field age = c1.getDeclaredField("age");
age.set(o, 101);
System.out.println(o);
Field address = c1.getDeclaredField("address");
address.set(o,"中国-云南-保山");
System.out.println(o);
}
}
class A{
private String aaa;
public int bbb;
}
class B extends A{
}
通过反射获取Class文件对象中的成员方法并使用
-== Method[] getMethods()== 返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。
- getDeclaredMethods() 获取本类中的所有方法,包括私有的,被保护的,默认的,公共的。不获取继承关系父类中的方法
public class ReflexDemo5 {
public static void main(String[] args) throws Exception{
//获取person类的class文件对象
Class<?> c = Class.forName("com.bigdat.java.day29.Person");
//获取方法
//Method[] getMethods()
//返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。
//获取本类以及父类中所有的公共方法(被public所修饰的方法)
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("===========================================================");
//获取本类中的所有方法,包括私有,被保护,默认,公共的方法,但是不获取继承关系的父类方法
Method[] declaredMethods = c.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("======================================================================");
//创建对象的构造器
Constructor<?> con = c.getConstructor();
Object o = con.newInstance();
//获取单个的方法并使用
//Object invoke(Object obj, Object... args)
//在具有指定参数的 方法对象上调用此 方法对象表示的底层方法。
Method fun1 = c.getMethod("fun1" );
fun1.invoke( o );
System.out.println("================================================================================");
//获取私有的成员方法使用
Method fun2 = c.getDeclaredMethod("fun2",String.class);
`fun2.setAccessible(true);`
fun2.invoke( o ,"你好!");
System.out.println("==================================================================================");
Method fun3 = c.getDeclaredMethod("fun3");
fun3.invoke( o );
Method fun4 = c.getDeclaredMethod("fun4" );
fun4.invoke( o );
}
}
原创文章,作者:6024010,如若转载,请注明出处:https://blog.ytso.com/244396.html