反射总结
1.Java的反射机制
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
2.对反射机制的理解
首先回顾一下类的概念:类是具有相同属性和行为的实体的集合。类比到反射机制中,不同的类都具有成员变量、方法、构造方法、包等信息,而这些信息相当于类的某种属性,所以具有相同属性的类的集合也是一个新的类,而成员变量、方法、构造方法、包等信息可以类比作类集合体的具体实现,即类的对象。
3.反射常用类
Class类——可以获取类和类的成员信息
Filed类——可以访问类的属性
Method类——可以调用类的方法
Constructor类——可以调用类的构造方法
4.使用反射的基本步骤:
<1>导入java.lang.reflect.*
<2>获得需要操作的类的Java.lang.Class对象
<3>调用Class的方法获取Field、Method等对象
<4>使用反射API进行操作(设置属性﹑调用方法
5.Class类的使用:
5.1 Class类是反射机制的起源和入口
- 每个类都有自己的Class对象
- 提供了获取类信息的相关方法
- Class类继承自Object类
5.2 Class类存放类的结构信息
- 类名
- 父类﹑接口
- 方法﹑构造方法﹑属性
- 注释
5.3 Class类的具体实现:
被测试类
public class Person extends AbstractPerson<String>{
private static int num = 1;
//成员变量
private String name;
private int age;
private String gender;
//构造方法
public Person() {
}
public Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
//方法
//无参无返回值
public void show(){
System.out.println("姓名:"+name+" 年龄:"+age+" 性别:"+gender);
}
//有参无返回值
public void show(String address){
System.out.println("姓名:"+name+" 年龄:"+age+" 性别:"+gender+" 地址:"+address);
}
//带返回值的方法
public String getInfo(){
return "信息:"+name+" "+age+" "+gender;
}
//静态方法
public static void print(){
System.out.println("这是一个静态方法");
}
//私有方法
private void show(String address,String email){
System.out.println("地址:"+address+" 邮箱:"+email);
}
}
<1>获取类的类对象
//获取类的类对象
public static void getClazz() throws Exception{
//获取Class对象的方法
//方式一:使用class属性获取
Class<?> clazz1 = Person.class;
System.out.println(clazz1.hashCode());
//方式二:通过getClass方法
Person person = new Person();
Class<?> clazz2 = person.getClass();
System.out.println(clazz2.hashCode());
//方式三:使用Class.forName方法:低耦合,不依赖具体的类,可以通过编译(推荐使用的方式)
Class<?> clazz3 = Class.forName("day.day19.Demo01.Person");
System.out.println(clazz2.hashCode());
//扩展:获取父类
Class<?> superclass = clazz3.getSuperclass();
System.out.println(superclass.getName());
Type genericSuperclass = clazz3.getGenericSuperclass();
System.out.println(genericSuperclass.getTypeName());
//获取接口
Class<?>[] interfaces = clazz3.getInterfaces();
System.out.println(interfaces.length);
for (Class<?> anInterface : interfaces) {
System.out.println(anInterface.toString());
}
//获取包名
Package aPackage = clazz3.getPackage();
System.out.println(aPackage.toString());
System.out.println(aPackage.getName());
}
<2>获取类中构造方法
//获取类中构造方法
public static void getConstructor() throws Exception {
Class<?> clazz = Class.forName("day.day19.Demo01.Person");
//获取构造方法
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
//获取单个构造方法
//获取无参构造方法
Constructor<?> constructor = clazz.getConstructor();
System.out.println(constructor);
System.out.println("---------------");
//获取带参构造方法
Constructor<?> constructor1 = clazz.getConstructor(String.class, int.class, String.class);
System.out.println(constructor1);
//利用构造方法创建对象
System.out.println("-----利用构造方法创建对象----");
Person zhangsan = new Person();
Object lisi = constructor.newInstance();
System.out.println(zhangsan);
System.out.println(lisi);
Object wangwu = constructor1.newInstance("王五", 20, "男");
System.out.println(wangwu);
//简单创建对象的方法
Object o = clazz.newInstance();
System.out.println(o.toString());
}
<3>获取类中方法
//获取类中方法
public static void getMethod() throws Exception{
Class<?> clazz = Class.forName("day.day19.Demo01.Person");
Method[] methods = clazz.getMethods();//只获取类自己公开的方法和继承的方法
for (Method method : methods) {
System.out.println(method);
}
Method[] declaredMethods = clazz.getDeclaredMethods();//获取本类的所有方法,包括私有的,但不包括继承自父类的方法
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
Method show = clazz.getMethod("show");
Object zhangsan = clazz.newInstance();
show.invoke(zhangsan);//zhangsan.show();
//获取有参构造方法
Method show2 = clazz.getMethod("show",String.class);
show2.invoke(zhangsan,"北京");
//获取带返回值的方法
Method getInfo = clazz.getMethod("getInfo");
Object value = getInfo.invoke(zhangsan);
System.out.println(value);
//获取静态方法
Method print = clazz.getMethod("print");
print.invoke(null);//Person.print();
//获取私有方法()
Method show3 = clazz.getDeclaredMethod("show", String.class, String.class);
//设置访问权限无效
show3.setAccessible(true);
show3.invoke(zhangsan,"上海","zhangsan@qq.com");
}
<4>获取类中成员变量
//获取类中成员变量
public static void getField() throws Exception {
Class<?> clazz = Class.forName("day.day19.Demo01.Person");
//获取
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
Object wangwu = clazz.newInstance();
//获取单个成员变量
System.out.println("---------");
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(wangwu, "王五");
//输出具体属性
Object o = name.get(wangwu);
System.out.println(o);
//获取静态变量
Field num = clazz.getDeclaredField("num");
num.setAccessible(true);
final Object o1 = num.get(wangwu);
System.out.println(o1);
}
5.4 动态创建对象
方法一:使用Class的newInstance()方法,仅适用于无参构造方法
Class clazz=Class.forName("com.qf.reflection.Student");
Object obj=clazz.newInstance();
方法二:调用Constructor的newInstance()方法,适用所有构造方法
Constructor cons = clazz.getConstructor(new Class[]{ String.class, int.class, float.class });
Object obj = cons.newInstance(new Object[ ] {"lkl", 32, 56.5f });
5.5 反射动态操作属性值
操作属性的基本步骤
1.通过Class对象获取Field 对象
2.调用Field 对象的方法进行取值或赋值操作
方法 | 说 明 |
---|---|
Xxx getXxx(Object obj) | 获取基本类型的属性值 |
Object get(Object obj) ) | 得到引用类型属性值 |
void setXxx(Object obj,Xxx val) | 将obj对象的该属性设置成val值 |
void set(Object obj,object val) | 将obj对象的该属性设置成val值 |
void setAccessible(boolean flag) | 对获取到的属性设置访问权限 |
6.反射技术的优点和缺点
优点:
<1>提高了Java程序的灵活性和扩展性,降低了耦合性,提高自适应能力
<2>允许程序创建和控制任何类的对象,无需提前硬编码目标类
缺点:
<1>性能问题
<2>代码维护问题