2. 正文--反射
1. 什么是反射?
2. 获取反射类Class?
3. 通过反射类获取Field对象
4. 通过反射类获取Method类
5. 通过反射类获取Annotation类
6. 通过反射类获取Contstructor类
7. 综合练习
8. 通过反射+注解+泛型手写一个ORM框架。
3. 什么是反射---是框架设计的灵魂。
框架: 是一个半成品软件。好处: 可以快速开发程序,使开发变的更加简洁。
反射: 把类中的成员封装成其他的类的过程。这就是反射。
4. 如何获取Class反射类
(1)通过全类名字符串来获取。
比如框架. spring框架 <bean id="student" class="com.ykq.entity.Student"> ----得到该类的对象
(2)通过类名来获取。
比如:mybatis-----> session.getMapper(StudentDao.class);----StudentDao对象
(3)通过对象来获取。
如果知道了类对象,则可以通过该对象获取Class
**/
public class Test01 {
public static void main(String[] args) throws Exception{
//如何获取Class类
//(1)通过全类名来获取.
Class<?> aClass = Class.forName("com.ykq.demo01.Student");
//(2)通过类名获取.
Class<?> bClass = Student.class;
//(3)通过对象来获取Class类
Student s=new Student();
Class<?> cClass = s.getClass();
//思考 aClass,bClass,cClass这三个对象的引用地址是否相同?
System.out.println(aClass==bClass);
System.out.println(aClass==cClass);
System.out.println(bClass==cClass);//任意一个类,经过加载到JVM中只会产生一个Class类对象。
}
}
5. 通过反射类得到相应的类对象。
Class<?> aclass=Class.forName("com.ykq.demo01.Student");
//得到对应的类对象
Object o = aclass.newInstance(); //可以通过反射类得到相应的类对象 原理就是调用的无参构造函数。
System.out.println(o);
6. 得到Field类对象。
getField(String name) : 获取指定属性名的public属性对象。
getFields() : 获取所有的public属性对象 包含父类中的属性。
getDeclaredField(String name) :获取指定的属性类对象。不能获取父类的属性。
getDeclaredFields() : 获取所有的属性类对象。不包含父类的属性。
//通过反射类获取Field类对象。
package com.ykq.demo02;
import java.lang.reflect.Field;
/**
* @program: java高级特点-反射
* @description:
* @author: 闫克起
* @create: 2021-08-09 15:20
**/
public class Test02 {
public static void main(String[] args)throws Exception {
Class clazz=Student.class;
Field ageField= clazz.getField("address");//获取Student类中的public修饰age属性类对象。以及父类中的属性。
//System.out.println(ageField);
Field[] fields = clazz.getFields();//获取类中所有public修饰的属性类对象 以及父类中的类对象.
// for (Field field:fields){
// System.out.println(field);
// }
Field age = clazz.getDeclaredField("name");//获取指定属性名的属性对象。不包含父类中的属性
// System.out.println(age);
Field[] declaredFields = clazz.getDeclaredFields(); //获取所有的奔雷中定义的属性对象
for(Field field:declaredFields){
System.out.println(field);
}
}
}
class Father{
public String address;
}
class Student extends Father{//----编译后产生几个字节码 1个----->classLoader加载到JVM中
private String name;
public Integer age;
String school;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void show(){
System.out.println("show方法的name==="+name+";age==="+age);
}
public Student(){
System.out.println("这是无参构造函数");
}
}
6.2 Field相应操作
get(Object obj) : 获取该属性的值。
set(Object obj, Object value) : 为该属性设置值。
setAccessible(true):表示允许访问私有属性。
public static void main(String[] args) throws Exception {
Class clazz=Student.class;
Object o = clazz.newInstance();//通过反射类得到相应的类对象
Field ageField = clazz.getField("age");//通过反射类得到相应的public修饰的属性对象
Object ageValue = ageField.get(o);//得到对象o中age属性的值
System.out.println(ageValue);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
ageField.set(o,25);//为age属性赋值
ageValue= ageField.get(o);
System.out.println(ageValue);
System.out.println("===============================================");
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);//设置该属性可以被访问
nameField.set(o,"范银成"); //为私有属性赋值。
Object nameValue = nameField.get(o);
System.out.println(nameValue);
}
7. Class得到Method的操作
getMethod(String name, 类<?>... parameterTypes) :得到指定名称和形参类型的方法。
getMethods() :得到所有的public修饰方法。
public static void main(String[] args) throws Exception {
Class clazz=Class.forName("com.ykq.demo03.Student");
Object o = clazz.newInstance();
Method show = clazz.getMethod("show");//获取无参的show方法对象
show.invoke(o);//回调 Method类中的方法
Method setName=clazz.getMethod("setName",String.class);//获取有参的setName, 参数的数据类型
setName.invoke(o,"海涛");//执行该方法
Method[] methods = clazz.getMethods();//得到所有的public修饰的方法 包含父类中的
for (Method m:methods){
System.out.println(m);
}
}
8. 获取Annotation注解。--【Class,Field ,Method】
getAnnotation():获取指定的注解
getAnnotations():获取所有的类注解
package com.ykq.demo04;
import java.lang.annotation.*;
import java.lang.reflect.Field;
/**
* @program: java高级特点-反射
* @description:
* @author: 闫克起
* @create: 2021-08-09 16:47
**/
public class Test04 {
public static void main(String[] args) throws Exception{
Class clazz=Student.class;
MyAnnotation annotation = (MyAnnotation) clazz.getAnnotation(MyAnnotation.class);//获取Student类上的MyAnnotation注解
System.out.println(annotation.value());//得到注解相应的属性值。
//1.得到Field对象
Field stuId = clazz.getDeclaredField("stuId");
TableId annotation1 = stuId.getAnnotation(TableId.class);
System.out.println(annotation1.value());
//2.得到Method上的注解 省略
}
}
@MyAnnotation(value = "tb_student")
class Student{
@TableId(value = "stu_id")
private Integer stuId;
/*
* 回顾:
* @Controller
* class StudentController{
* @Autowire
* private StudentService studentService;
* @RequestMapping(value="list")
* public String list(){
*
* }
* }
* */
}
@Target(value = ElementType.TYPE)
@Retention(value= RetentionPolicy.RUNTIME) //指定注解的有效期 默认源码有效
@interface MyAnnotation{ //自定义注解
String value();
}
@Target(value = ElementType.FIELD)
@Retention(value= RetentionPolicy.RUNTIME) //指定注解的有效期 默认源码有效
@interface TableId{
String value();
}
9. 案例 --- spring bean
1.写一个框架,不改变任何类的前提下,可以帮我们创建任意类的对象,执行该类下面的方法;
条件: 反射+属性配置文件。
步骤:
-
读取配置文件中的全类名。
//1.读取配置文件
InputStream resourceAsStream = Test.class.getClassLoader().getResourceAsStream("config.properties");//读取配置文件
//2.读取配置文件的内容 =====把属性文件中的内容封装到Properties类中
Properties properties=new Properties();
properties.load(resourceAsStream); -
根据该名创建反射类
-
根据反射类创建该类的对象。
-
读取配置文件中的方法名
-
根据反射类得到方法对象
-
执行该方法。
总结:
1. 反射:======>Class
反射属性=====>Field:
反射方法=====>Method:
反射注解=====>Annotation:
(1)作业:
(1)把上课讲的例子 全部写一遍。【2遍】
(2) 熟悉手写的ORM框架