前言
上篇(http://t.csdn.cn/vUffo)中我们已经认识了XML的建模,这篇我们将学习反射
目录
反射
A、什么是反射?
概念:反射是Java的一种机制,让我们可以在运行时获取类的信息
作用:通过反射,我们可以在程序运行时动态创建对象,还能获取到类的所有信息,比如它的属性、构造器、方法、注解等;
Java反射机制主要提供了以下功能:
- 1.在运行时判断任意一个对象所属的类。
- 2.在运行时构造任意一个类的对象。
- 3.在运行时判断任意一个类所具有的成员变量和方法。
- 4.在运行时调用任意一个对象的方法。
Java中反射的用法非常多,常见的有以下几种
一、在运行时获取一个类的 Class 对象
二、在运行时构造一个类的实例化对象
三、在运行时获取一个类的所有信息:变量、方法、构造器、注解
B、类类
一切反射从类类开始
Student 类:
package com.oyang.reflect;
/**
* 学生实体类
* @author yang
*
* @date 2022年6月16日上午11:51:28
*/
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());
}
}
类类的获取方式
- 类.Class
- 类实例.getClass
- Class.forName("类的全路径名");
package com.oyang.reflect;
/**
* 类类的获取方式
* @author yang
*
* @date 2022年6月16日上午8:51:43
*/
public class Demo1 {
public static void main(String[] args) throws Exception {
//1.类.Class
Class clz1= Student.class;
//确定本工程有这个类,你才可以实例化
// Student stu = new Student();
//本工程没有这个类,也可以编译通过
//Object newInstance = Class.forName("com.oyang.reflect.Student").newInstance();
//2.类实例.getClass
Student stu = new Student();
Class clz2 = stu.getClass();
//3.Class.forName("类的全路径名");
Class clz3 = Class.forName("com.oyang.reflect.Student");
}
}
运行结果:
反射实例化
不用反射实例化:
package com.oyang.reflect;
import java.lang.reflect.Constructor;
/**
* 反射实例化
* @author yang
*
* @date 2022年6月16日上午10:04:16
*/
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", "oyang");
}
}
new 不到私有的构造方法
使用反射实例化
无参数,公有的构造方法:
package com.oyang.reflect;
import java.lang.reflect.Constructor;
/**
* 反射实例化
* 1.无参数,公有的构造方法
* @author yang
*
* @date 2022年6月16日上午10:04:16
*/
public class Demo2 {
public static void main(String[] args) throws Exception {
//获取类类
Class<? extends Student> clz1 = stu1.getClass();
//默认就是调用无参 公有的构造函数
//1.无参数,公有的构造方法
Student stu4 = clz1.newInstance();
}
}
有参数 公有的构造方法
package com.oyang.reflect;
import java.lang.reflect.Constructor;
/**
* 反射实例化
* 有参的,公有的构造方法
* @author yang
*
* @date 2022年6月16日上午10:04:16
*/
public class Demo2 {
public static void main(String[] args) throws Exception {
Student stu1 = new Student();
//获取类类
Class<? extends Student> clz1 = stu1.getClass();
//2.有参数 公有的构造方法
// 拿到构造器对象 三个.代表可以传1个2个..n个参数 -->拿到一个参数为String的构造对象
Constructor<? extends Student> c1 = clz1.getConstructor(String.class);
Student sru5 = c1.newInstance("s001");
}
}
有多个参数 公有的构造方法:
package com.oyang.reflect;
import java.lang.reflect.Constructor;
/**
* 反射实例化
* 有多个参数 公有的构造方法
* @author yang
*
* @date 2022年6月16日上午10:04:16
*/
public class Demo2 {
public static void main(String[] args) throws Exception {
Student stu1 = new Student();
//new 不到私有的构造方法
/**
* 一下均为反射的方式实例化对象
*/
//获取类类
Class<? extends Student> clz1 = stu1.getClass();
// 有多个参数 公有的构造方法
Constructor<? extends Student> c2 = clz1.getConstructor(String.class,String.class);
Student stu6 = c2.newInstance("s001","陽");
}
}
私有构造方法:
package com.oyang.reflect;
import java.lang.reflect.Constructor;
/**
* 反射实例化
* 私有的构造方法
* @author yang
*
* @date 2022年6月16日上午10:04:16
*/
public class Demo2 {
public static void main(String[] args) throws Exception {
Student stu1 = new Student();
//new 不到私有的构造方法
/**
* 一下均为反射的方式实例化对象
*/
//获取类类
Class<? extends Student> clz1 = stu1.getClass();
// 私有构造方法
//getConstructor只能获取公有的构造方法,要获取私有的构造器getDeclaredConstructor
Constructor<? extends Student> c3 = clz1.getDeclaredConstructor(Integer.class);
//打开访问权限
c3.setAccessible(true);
Student wtu7 = c3.newInstance(3);
}
}
getConstructor只能获取公有的构造方法,要获取私有的构造器getDeclaredConstructor
反射动态调用方法
思路:
- 拿到类类
- 拿到方法对象
- 调用对应的方法
package com.oyang.reflect;
import java.lang.reflect.Method;
/**
* 反射动态调用方法
* 1.调用无参数,公有的方法
* 2.调用有1个参数的,公有的方法
* 3.调用2个有参数的 私有方法
* @author yang
*
* @date 2022年6月16日上午10:25:34
*/
public class Demo3 {
public static void main(String[] args) throws Exception {
/**
* 1.拿到类类
* 2.拿到方法对象
* 3.调用对应的方法
*/
// 调用无参数,公有的方法
// 1.先拿到类类
Class<Student> clz= Student.class;
//name:方法名 parameterTypes:方法对应的参数
Method m1 = clz.getMethod("hello");
//3.调用对应的方法
//第一个参数:那个类实例 第二个参数:方法调用时的实参
//m1.invoke方法调用的返回值 就是方法对象本身的返回值hello方法的反回值
Object invoke = m1.invoke(clz.newInstance());
System.out.println(invoke);
//调用有1个参数的,公有的方法
Method m2 = clz.getMethod("hello", String.class);
Object invoke2 = m2.invoke(clz.newInstance(), "陽");
System.out.println(invoke2);
//调用2个有参数的 私有方法
Method m3 = clz.getDeclaredMethod("add",Integer.class,Integer.class);
m3.setAccessible(true);
Object invoke3 = m3.invoke(clz.newInstance(), 13,32);
System.out.println(invoke3);
}
}
结果:
反射读写属性
package com.oyang.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* 反射读写属性
* @author yang
*
* @date 2022年6月16日上午10:45:01
*/
public class Demo4 {
public static void main(String[] args) throws Exception {
Student stu = new Student("s003","张三");
stu.age=20;
//需求:要拿到这个学生所有的属性值
System.out.println("sid:"+stu.getSid());
System.out.println("sname:"+stu.getSname());
System.out.println("sage:"+stu.age);
/**
* 上述代码存在的问题
* 1.事先得知道这个类有哪些属性
* 2.假设Student有30个属性呢?
*/
//一切反射从类类开始
Class<? extends Student> clz = stu.getClass();
//当前类的所有属性对象
Field[] f = clz.getDeclaredFields();
System.out.println(f.length);
//for循环中的fi代表每一个属性对象
for (Field fi : f) {
//打开访问权限
fi.setAccessible(true);
//通过属性对象拿到属性名
System.out.println(fi.getName());
//拿到当前的属性对象的 属性值
System.out.println(fi.get(stu));
}
}
}
通过反射拿到属性对应的修饰符
package com.oyang.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* 反射拿到对应的修饰符
* @author yang
*
* @date 2022年6月16日上午10:45:01
*/
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[] f = clz.getDeclaredFields();
System.out.println(f.length);
//for循环中的fi代表每一个属性对象
for (Field fi : f) {
//打开访问权限
fi.setAccessible(true);
//通过属性对象拿到属性名
System.out.println(fi.getName());
//拿到当前的属性对象的 属性值
System.out.println(fi.get(stu));
//返回一个用数字表示的java修饰符
System.out.println(fi.getModifiers());
//通过数字拿到对应的修饰符
System.out.println(Modifier.toString(fi.getModifiers()));
}
}
}
运行结果:
反射的常用场景
1、Spring 实例化对象:当程序启动时,Spring 会读取配置文件applicationContext.xml并解析出里面所有的标签实例化到IOC容器中。
2、反射 + 工厂模式:通过反射消除工厂中的多个分支,如果需要生产新的类,无需关注工厂类,工厂类可以应对各种新增的类,反射可以使得程序更加健壮。
3、JDBC连接数据库:使用JDBC连接数据库时,指定连接数据库的驱动类时用到反射加载驱动类
OK,今日的学习就到此结束啦,如果对个位看官有帮助的话可以留下免费的赞哦(收藏或关注也行),如果文章中有什么问题或不足以及需要改正的地方可以私信博主,博主会做出改正的。个位看官,小陽在此跟大家说拜拜啦!