WHAT:
是java语言的一种机制,通过这种机制,可以动态的实例化对象,读写属性,调用方法。
WHY:
为什么会有反射
因为在java程序运行时,有一些类是不需要从头用到尾的,而反射机制可以在需要的时候在加载类,就比如数据库配置时使用的相关类
HOW:
反射怎么用,用反射能干什么
提高代码健壮性,灵活性
-
怎么用:
使用反射机制,首先我们引入一个叫做’类类’的东西,也就是Class类,类类有三种获取方式
这里借助一个学生类Student.java
package com.csf.reflect;
public class Student {
private String sid;
private String sname;
public Integer age;
static{
System.out.println("加载进jvm中!");
}
public Student() {
super();
System.out.println("调用无参构造方法创建了一个学生对象");
}
public Student(String sid) {
super();
this.sid = sid;
System.out.println("调用带一个参数的构造方法创建了一个学生对象");
}
public Student(String sid, String sname) {
super();
this.sid = sid;
this.sname = sname;
System.out.println("调用带二个参数的构造方法创建了一个学生对象");
}
@SuppressWarnings("unused")
private Student(Integer age) {
System.out.println("调用Student类私有的构造方法创建一个学生对象");
this.age = age;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public void hello() {
System.out.println("你好!我是" + this.sname);
}
public void hello(String name) {
System.out.println(name + "你好!我是" + this.sname);
}
@SuppressWarnings("unused")
private Integer add(Integer a, Integer b) {
return new Integer(a.intValue() + b.intValue());
}
}
1.通过类得到
Class stuClz=Student.class;
2.通过对象得到
Student s=new Student();
Class<Student> stuClz = (Class<Student>) s.getClass();
3.通过完整类名得到
Class<Student> stuClz = Class.forName("com.csf.reflect.Student");
所以,反射的第一步,得到类类
得到类类之后,可通过反射实例化得到对象,得对象,便可用这个对象的属性,方法。
以下都借助Student类进行,都用stuClz作为类类名称
1.反射实例化:
1.stuClz.newInstance() 无参构造
Student stu = (Student) stuClz.newInstance();
stu.hello();
stu.hello("张三");
可以看到,这个方法调用了Student的无参构造,并且对应方法的调用都没问题。
注:所以,如果要使用这种方法进行反射实例化,则在给类写有参构造是,须保留无参构造。
2.stuClz.getConstrutor(参数) 有参构造,这里的参数填实体类中构造函数的数据类型。
这里调用的是反射的有参构造器,还需要一步才能得到对象
Constructor<Student> c = stuClz.getConstructor(String.class);
Student stu = c.newInstance("s001");
stu.hello();
3.stuClz.getDeclaredConstructor() 和上面这个方法差不多,不过利用这个方法有调用私有方法的权限。
先用上面的方法去调用Student的私有方法
Constructor<Student> c = stuClz.getConstructor(String.class);
c.newInstance(18);
这里报了方法未找到的错,所以,这种方法是无法获取私有方法的
所以,用.getDeclaredConstructor()再试一下,
Constructor c = stuClz.getDeclaredConstructor(Integer.class);
c.newInstance(133);
可以看到,还是报错,不过这一次的错已经不一样了。这里是因为检测到了这个私有的构造,不过没有权限,所以需要打开权限。
Constructor c = stuClz.getDeclaredConstructor(Integer.class);
c.setAccessible(true);
c.newInstance(133);
OK了。上面的.getConstrutor(参数) 方法是用不了。setAccessible()方法的。
反射动态方法
反射调用方法有两种方式,
1..getMethod("方法名","参数");//不可调用私有的
2..getDeclaredMethod("方法名","参数");//可以调用私有的
所以就只演示第二种了
- 首先得到类对象
- 创建一个类实例(后面会用到)
- 再调用.getDeclareMethod()
- 再用方法对象调用执行方法,就可运行也就是.idnvoke(参数)。参数放该方法的对象
Class stuClz=Class.forName("com.csf.reflect.Student");
Student stu = (Student) stuClz.newInstance();
//invoke:
//参数一:类实例,在这里就是Student的类实例
//参数二:调用的方法传递的参数,这里是Student中,hello方法的参数
//返回值,就是被反射调用的方法的返回值
//stuClz.getDeclaredMethod(name, parameterTypes) name是方法名 parameterTypes参数类型,因为这里调用的方法没有参数,所以不写
Method m1 = stuClz.getDeclaredMethod("hello");
m1.invoke(stu);//因为没有返回值,所以不用接收
Method m1 = stuClz.getDeclaredMethod("hello");
m1.invoke(stu);
Method m2 = stuClz.getDeclaredMethod("hello", String.class);
m2.invoke(stu, "张三");
Method m3 = stuClz.getDeclaredMethod("add", Integer.class,Integer.class);
m3.setAccessible(true);
System.out.println(m3.invoke(stu, 123,456));
注:在调用私有方法是,同样要打开权限
反射读写属性
读写属性的思维和上面差不多
就不详细讲解
Class stuClz=Class.forName("com.csf.reflect.Student");
Student s= (Student) stuClz.newInstance();
Field f = stuClz.getDeclaredField("sname");
f.setAccessible(true);
f.set(s, "张三");
System.out.println(s.getSname());
System.out.println(f.get(s));
输出效果是
不过,用反射可以将对象属性,一把提出来
方法是
Field[] f=stuClz.getDeclaredFields();
for (Field ff : f) {
ff.setAccessible(true);
System.out.println(ff.getName()+":1"+ff.get(s));
}
over.