大纲:
一:反射
1,定义:反射是JAVA语言中一种机制,通过该机制可以动态的实例化对象,读取属性,以及调用方法。
2.作用/为什么要学反射
java的反射机制就是增加程序的灵活性,避免将代码写的太死,使其更灵活。
二:类类
1.什么是类类?
举个通俗易懂的例子:比如旺财是狗类的实例,张三是学生类的实例,而狗类和学生类以及其他所有的类又是类类的实例 所以说类类就是其他类的上一级,其他类就是类类的实例
2.类类的三种获取方式:例:学生类
package com.ljj.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());
}
}
其中包括:三个属性,无参的构造方法,带一个参的公有的构造方法,带两个参的公有的构造方法
无参的公有方法:hello() 带一个参的公有方法 hello(String name) 带两个参的私有方法(integer a,interger b)
1.如何获取类类
用 类.class
Class clz1=Student.class;
2.类实例
//2、类实例.getClass()
// 确定本工程有这个类,才可以实例化
Student stu=new Student();
// 本工程没有这个类,也可以编译通过,但是会在运行期报错
// Object newInstance = Class.forName("com.ycx.reflect.Student").newInstance();
Class clz2 = stu.getClass();
3.Class.forName("类的全路径名")
//3、Class.forName("类的全路径名");
Class clz3 = Class.forName("com.ycx.reflect.Student");
三.反射实例化
什么时候用到?
我们可以通过直接实例来拿到一个类的公开的方法,但是拿不到私有的,此时就需要反射实例化
例:上文中的学生类
* 反射实例化
1、无参数 共有的构造方法
2、有参数 共有的构造方法
3、有多个参数 共有的构造方法
4、私有的构造方法
注意:所有的反射皆从获取类类开始!!!
反射中的方法:
1.调用无参的共有的构造方法 同时也是默认的
类类..newInstance();
2.有参数 共有的构造方法
拿到构造器对象 三个.代表可以传1个或n个参数 拿到一个参数为String的构造器对象,调用类中的方法,括号中填方法参数的类型.class
类类.getConstructor(String.class);
3、.getDeclaredConstructor(); 调用类中的方法, 其中括号里面是填的类型
类类.getDeclaredConstructor(Integer.class);
4.getConstructor与getDeclaredConstructor的区别:
getConstructor只能够获取共有的构造方法,要获取私有的构造器getDeclaredConstructor
但是 很多小伙办在调用了getDeclaredConstructor之后却报错
解决方法:getDeclaredConstructor 需要设置访问权限
.setAccessible(true);
完整案例:
package com.ljj.reflect;
import java.lang.reflect.Constructor;
/**
* 反射实例化
* 1.无参数 共有的构造方法
* 2.有参数 共有的构造方法
* 3.有多个参数 共有的构造方法
* 4.私有的构造方法
* @author Administrator 刘俊杰
*下午7:12:41
*/
public class Demo2 {
public static void main(String[] args) throws Exception, Exception {
Student stu1 = new Student();
Student stu2 = new Student("s001");
Student stu3 = new Student("s001", "fjsdk");
System.out.println("***************以下均为反射方式实例化对象");
//获取类类
Class<? extends Student> clz1 = stu1.getClass();
// 默认就是调用无参的 共有的 构造函数
// 1.无参数 共有的构造方法
Student stu4 = clz1.newInstance();
// 2.有参数 共有的构造方法
// 拿到构造器对象 三个.代表可以传1个或n个参数 拿到一个参数为String的构造器对象
Constructor<? extends Student> c1 = clz1.getConstructor(String.class);
Student stu5 = c1.newInstance("s001");
// 3.有多个参数 共有的构造方法 拿到有两个参数的构造器对象
Constructor<? extends Student> c2 = clz1.getConstructor(String.class,String.class);
Student stu6 = c2.newInstance("s001","李四");
// 4.私有的构造方法
// getConstructor只能够获取共有的构造方法,要获取私有的构造器getDeclaredConstructor
Constructor<? extends Student> c3 = clz1.getDeclaredConstructor(Integer.class);
//打开访问权限
c3.setAccessible(true);
Student stu7 = c3.newInstance(18);
}
}
运行结果:参照Student类中的打印结果
四.反射动态方法调用
1.调用无参的共有方法
调用步骤:
1.先拿到类类
2.拿到方法对象
3.调用对应的方法
1.调用无参的共有方法
//拿到类类
Class<Student> clz=Student.class;
//name:方法名 parameterTypes:方法对应的参数
// 拿到方法对象
Method m1 = clz.getMethod("hello");
// 1.调用对应的方法
// 第一个参数:那个类实例 第二个参数:方法调用时的实参
// m1.invoke方法调用的返回值 就是 方法对象本身的返回值 hello方法的返回值
Object invoke = m1.invoke(clz.newInstance());
System.out.println(invoke);
结果:
2.调用一个有参数的共有方法
// 2.调用一个参数的构造方法
Method m2 = clz.getMethod("hello", String.class);
Object invoke2 = m2.invoke(clz.newInstance(), "张三");
System.out.println(invoke2);
//
结果:
3.调用两个个有参的 私有方法
3调用两个个有参的 私有方法
Method m3 = clz.getDeclaredMethod("add", Integer.class,Integer.class);
m3.setAccessible(true);
Object invoke3 = m3.invoke(clz.newInstance(), 5,5);
System.out.println(invoke3);
结果:
五: 反射读取属性
需求:读取对象的每一个属性
如果换做我们没有学反射之前来完成这个需求的话,我们可能会这样操作
package com.ljj.reflect;
import java.lang.reflect.Field;
/**
* @author Administrator 刘俊杰
*下午5:38:18
*/
public class Demo4 {
public static void main(String[] args) throws Exception {
Student stu = new Student("s003", "张三");
stu.age=20;
// 拿到这个学生所有的属性以及属性值
System.out.println("age:"+stu.age);
System.out.println("sname"+stu.getSname());
System.out.println("sid:"+stu.getSid());
}
}
读取结果:
但是现在我们要思考更多的问题:
1.如果我们事先不知道这个类有几个属性呢?
2.假设这个类有几十个属性呢?
所以我们需要使用反射来实现该需求:
代码展示:
package com.ljj.reflect;
import java.lang.reflect.Field;
/**
* @author Administrator 刘俊杰
*下午5:38:18
*/
public class Demo4 {
public static void main(String[] args) throws Exception {
Student stu = new Student("s003", "张三");
stu.age=20;
// 一切反射从类类开始
Class<? extends Student> clz = stu.getClass();
// 当前类的所有属性对象
Field[] fields = clz.getDeclaredFields();
System.out.println(fields.length);
// for循环中的f代表每一个属性对象
for (Field f : fields) {
// 打开访问权限
f.setAccessible(true);
// 通过属性对象拿到属性名称
System.out.println(f.getName());
// 拿到当前的属性对象的属性值
System.out.println(f.get(stu));
}
}
}
读取结果:
这样以来我们只需要一个for循环就可以得到所有的属性,无论有多少个属性都可以拿到,代码始终不变