目录
反射java语言中的一种机制,通过这种机制可以动态的实例化对象,读写属性,调用方法
一.反射
反射java语言中的一种机制,通过这种机制可以动态的实例化对象,读写属性,调用方法
1.实例化对象:new
2.读写属性:.get .set 这就是读写
3.调用方法:那么就是点调用方法就可以了
y1主要是框架,快速去提高我们的开发效率
框架:反射+设计模式 组合而成的一个半成品。
半成品指的是什么呢?指的就是在S阶段去做项目的时候就是从复都有,要有jsp,servlet,完了之后然后一大堆增删改查,那就是多处地方去开发。
在Y阶段的框架,就是基于这个半成品去开发,就会发现一个新增,一个查询就是一行代码就可以完成了,那么为什么人家可以一行代码帮你把这个新增功能给完成,为什么人家可以把这个修改给完成,原因是因为这个半成品,那么这个半成品是怎么的来的,就是反射+设计模式
比如:鞭炮:这个东西你要加任何的混合物,最后把它混合出来,混合出来之后,爆炸的原理是因为在一瞬间产生了大量的一个气体,然后在一个密封的空气里面或者说在容器里面,然后最后把这个容器给炸开,这就是爆炸的原理。
那么鞭炮里面的销要研究出来的话,首先需要准备各种的原材料,按照比例把它们混合在一起,那么这里就有两种方式,第一方式:假如哪个销要用10种原材料按照一定的比例去配,第一种方式就是一个一个的去找,这10种原材料,在由一个专业人士将哪个销混合在一起,然后在把它塞进去,塞到一个密闭的容器里面去,这是一种方式,还要一种方式是直接就去采购,已经配好的销,然后在进行组装就可以了
半成品就是 合成后的火药
反射+设计模式:合成火药的过程
从这里我们就可以看出来反射重不重要,肯定重要,一个反射+设计模式
二.类类
比如: 狗类 旺财 小黄
猫类 肥波 加菲
类类 狗类 猫类 人类 各种类
旺财是狗类的实例
肥波是猫类的实例
狗类是谁的实例? 类类
有一个资料:学生类 都是类类的一个实例
注意这个表包含的东西比较多:这里面有属性,然后属性有私有属性也有公开属性,方法有公有方法,无参方法,有参的方法,然后有一个参数的,两个参数的,还要私有的方法,下面就它的一些内容。 这是一个及各种情况于一生的实体类,这就是我们要用的到的一个表.
package com.jiangwenjuan.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());
}
}
下面这张图就是类类的获取方式:三种方式,获取类类的目的就是为了下面这三个 ,就前面的实例化对象,读写属性,调用方法,我们要用这些功能前提是要先拿到这些类类,拿到类类就可以进行下面的这三个。
Ctrl+T,可以查看父子关键及其他关系。
在jdbc连接的时候,它不属于mysql也不属于其他的,它一定存在类,我能不能实例化,可以,先不管它是接口,但是接口的引用此项一个类的实现这肯定能实现的了,那子类到底是谁,在你写下面这个代码的时候,
// Driver driver = new com.mysql.jdbc.Driver();
// Driver driver = new com.oracle.jdbc.Driver();
你不知道,但是能我的这个代码是不是可以这样写,
Driver driver = Class.forName(java.sql.Driver);
//如果在我们这个工程里面你放了一个包是mysql包,你把这个写好的包放到这个下面来
这个程序是不是依然成立
Driver driver = Class.forName(com.mysql.jdbc.Driver);
实例化前提你还是要先拿带那个类类
// 第一种方式:类.class
Class clz = Student.class;
// 上面这种写法,就是在我们学反射之前,先确定本工程有这个类,你才可以实例化
// Student stu = new Student();
// 下面这种就是本工程没有这个类,也可以编译通过
// 只不过你真的没有的话就会报错
// Object newInstance = Class.forName("com.jiangwenjuan.reflect.Student").newInstance();
如果真的没有这个类的话就会在运行的时候报错:
创建一个然后最终运行出来就是这样的:
只要你写一个父类,以后你要用那个东西你只要去继承这个父类,然后就不会报错,这个反射的作用就是将未知这个实例化,未知的东西就存在一切的可能,它就能够去拥抱变化,为什么后面我们就会去写通用的增删改查,就是因为它底层用了反射,能够将未知的东西实例化出来,我都不知道以后是去做书籍表增删改查,还是订单的增删改查,但是我的程序就有包容性,我能够让我的程序及能够运用书籍也能够运用订单这个增删改查,就是这个原因。
三.反射实例化
构造函数
声明的构造函数
新实例
在很多时候为什么在你写一个有参构造的同时一定要提供一个无参的构造方法,原因很简单,往后写框架的时候,如果框架里面没有无参的构造方法,很多代码都会报错,在运行的时候会报错,写的时候不会出错。
package com.jiangwenjuan.reflect;
import java.lang.reflect.Constructor;
/**
* 反射实例化
* 1.无参数 公有的构造方法
* 2.有参数 公有的构造方法
* 3.有多个参数 公有的构造方法
* 4.私有的构造方法
* @author 蒋文娟
*
* @date 2022年6月16日 下午4:48:31
*/
public class Demo2 {
public static void main(String[] args) throws Exception {
// 无参的构造方法
Student stu1 = new Student();
// 带一个参数的构造方法
Student stu2 = new Student("s001");
// 带有两个参数的构造方法 公有的
Student stu3 = new Student("s001", "张三");
/*------------以下均为反射的方式实例化对象----------*/
// 获取类类
Class<? extends Student> clz1 = stu1.getClass();
// 默认就是调用无参的公有的构造函数
Student stu4 = clz1.newInstance();
// 2.有参数 公有的构造方法
// 拿到构造器对象 三个 . 代表可以传1个2个.. 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","李四");
}
}
new的方式不能对私有的进行调用,但反射能做到。
怎么解决这个问题:要获取私有的构造器getDeclaredConstructor
// 4.私有的构造方法
// getConstructor只能够获取公有的构造方法,要获取私有的构造器getDeclaredConstructor
Constructor<? extends Student> c3 = clz1.getDeclaredConstructor(Integer.class);
Student stu7 = c3.newInstance(18);
这样就会报出另外一个错误,这个错误根刚刚那个错误不一样:
如果想要打开访问怎么打开访问:
// 打开访问权限 c3.setAccessible(true);
所以代码块:
package com.jiangwenjuan.reflect;
import java.lang.reflect.Constructor;
/**
* 反射实例化
* 1.无参数 公有的构造方法
* 2.有参数 公有的构造方法
* 3.有多个参数 公有的构造方法
* 4.私有的构造方法
* @author 蒋文娟
*
* @date 2022年6月16日 下午4:48:31
*/
public class Demo2 {
public static void main(String[] args) throws Exception {
// 无参的构造方法
Student stu1 = new Student();
// 带一个参数的构造方法
Student stu2 = new Student("s001");
// 带有两个参数的构造方法 公有的
Student stu3 = new Student("s001", "张三");
/*------------以下均为反射的方式实例化对象----------*/
// 获取类类
Class<? extends Student> clz1 = stu1.getClass();
// 默认就是调用无参的公有的构造函数
Student stu4 = clz1.newInstance();
// 2.有参数 公有的构造方法
// 拿到构造器对象 三个 . 代表可以传1个2个.. 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);
}
}
四.反射动态方法调用
方法
声明的方法
1.调用无参的 公有方法
package com.jiangwenjuan.reflect;
import java.lang.reflect.Method;
/**
* 反射动态调用方法
* 1.调用无参的 公有方法
* 2.调用1个有参 公有方法
* 3.调用私有的方法
* @author 蒋文娟
*
* @date 2022年6月16日 下午5:43:33
*/
public class Demo3 {
public static void main(String[] args) throws Exception {
/*
* 1.先拿到类类
* 2.拿到方法对象
* 3.调用对应方法
*/
// 1.先拿到类类
Class<Student> clz = Student.class;
// 2.拿到方法对象
// name:指的是方法名 parameterTypes:方法对应的参数
Method m1 = clz.getMethod("hello");
// 3.调用对应方法
// 第一个参数:指的是那个类实例 第二参数:指的是方法调用时的实参
// m1.invoke方法调用的返回值就是 方法对象本身的返回值hello方法的返回值
Object invoke = m1.invoke(clz.newInstance());
System.out.println(invoke);
}
}
2.调用1个有参 公有方法或者调用2个的有参 公有方法,跟这个一样的。
// 调用1个有参的 公有方法
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.jiangwenjuan.reflect;
import java.lang.reflect.Field;
/**
* 反射读写属性
* @author 蒋文娟
*
* @date 2022年6月16日 下午6:08:10
*/
public class Demo4 {
public static void main(String[] args) {
Student stu = new Student("s003", "张三");
stu.age = 20;
// 需求 要拿到这个学生所以的属性及属性值
// 在还不知道反射的时候,之前就是这样拿到
System.out.println("age:"+stu.age);
System.out.println("name:"+stu.getSname());
System.out.println("sid:"+stu.getSid());
/*
* 上述代码存在的问题:
* 1.你事先得知道这个类有哪些属性
* 2.假设studnet有30个属性呢?
*/
// 一切反射从类类开始
Class<? extends Student> clz = stu.getClass();
// 当前类的所以属性对象
Field[] fields = clz.getDeclaredFields();
System.out.println(fields.length);
}
}
运行结果为:
如果在去加一个属性对象结果就会为4:
拿到属性名及属性值:
// for循环中的f代表每一个属性对象
for (Field f : fields) {
// 打开访问权限
f.setAccessible(true);
// 通过属性对象拿到属性名称
System.out.println(f.getName());
// 拿到当前的属性对象的 属性值
System.out.println(f.get(stu));
}
运行结果为:
访问修饰符:
最后的自己理解的思维导图: