1. 反射概述
1.1 什么是反射?
反射是框架设计的灵魂。
反射就是类在运行期间,把类中成员抽取为其他类的过程就是反射。
1.2 为什么使用反射?
反射是为了解决在运行期,对某个实例一无所知的情况下,如何调用其方法或属性。
例子: spring框架中只需要传入类的路径,spring框架就会帮你创建类的对象。
阿里巴巴 腾讯 国企写项目—使用第三方的框架 。
2. Class
2.1 获取Class反射类的方式
提供了三种模式:
通过类名.class获取、通过对象.getClass()获取、通过Class.forName(“全类名”)获取
Student实体类
public class Student extends People {
private String name;
private int age;
public void show() {
}
public void show(String name) {
System.out.println("我的名字是:"+name);
}
private void fun(String name,int age) {
System.out.println("我的名字是:"+name+"今年"+age+"岁了");
}
}
测试类
aClass1、aClass2、aClass3三者只是通过不同方式来获取到的反射类对象,指向的都是同一个引用地址。
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException{
//第一种:通过类名.class获取
Class aClass1 = Student.class;
//第二种:通过对象.getClass()获取
Student student = new Student();
Class aClass2 = student.getClass();
//第三种:通过Class.forName("全类名")获取
Class aClass3 = Class.forName("com.ykx.entity.Student");
System.out.println(aClass3);
}
}
2.2. Class类中常用的方法
aClass.newInstance(); // 通过反射类创建实例对象
aClass.getAnnotation(Myannotation.class); // 获取注解
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE) //作用范围为类
@Retention(RetentionPolicy.RUNTIME) //运行期可见
public @interface Myannotation {
String value();
}
测试类
public static void main(String[] args) throws Exception{
//通过类名获取反射类
Class<Student> aClass = Student.class;
//1. 通过反射类创建实例对象
Student student = aClass.newInstance();
System.out.println(student);
//2. 获取反射类上的注解
Myannotation annotation = aClass.getAnnotation(Myannotation.class);
System.out.println(annotation.value());
}
3. Method
3.1 获取Method方法类的方式
getDeclaredMethods();//得到本类中所有的方法。
getDeclaredMethod("方法名",参数类型);//获取本类中指定的方法对象
getMethods();//获取本类以及父辈类中public修饰的方法。
getMethod("方法名",参数类型);//获取本类以及父辈类中指定public修饰的方法。
public static void main(String[] args) throws Exception{
//通过类名获取反射类
Class<Student> studentClass = Student.class;
//1. 获取本类中所有方法--getDeclaredMethods();
Method[] declaredMethods = studentClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("declaredMethod:"+declaredMethod);
}
//2. 获取本类中指定的方法对象--getDeclaredMethod("方法名",参数类型);
Method show = studentClass.getDeclaredMethod("show", String.class);
System.out.println("show:"+show);
//3. 获取本类以及父类中public修饰的方法--getMethods();
Method[] methods = studentClass.getMethods();
for (Method method : methods) {
System.out.println("method:"+method);
}
//4. 获取本类以及父类中public修饰的指定方法--getMethod("方法名",参数类型);
Method show1 = studentClass.getMethod("show", String.class);
}
3.2 Method类对象中常用的方法
invoke()方法
反射类获取的方法.invoke—表示方法执行。
invoke(调用对象)–参数列表中的参数表示是谁调用。
setAccessible()方法
当试图访问并获取实体类中的私有属性或者方法时,是不被允许的。
通过设置该方法,参数有两个值
--true表示可访问,打破不可访问私有规则
--默认为false,表示不可访问私有属性
public static void main(String[] args) throws Exception{
//通过类名获取反射类
Class<Student> studentClass = Student.class;
//创建实例对象
Student student = studentClass.newInstance();
//获取学生类的不带参数的show方法
Method methodShow = studentClass.getMethod("show");
//invoke()---调用学生对象,执行该方法
Object result = methodShow.invoke(student);
System.out.println("invoke 不带参的show:"+result);
Method methodShowName = studentClass.getMethod("show",String.class);
Object result1 = methodShowName.invoke(student,"陆可");
System.out.println("invoke 带参的show:"+result1);
//setAccessible()---访问私有方法并执行
Method methodShowPeople = studentClass.getDeclaredMethod("fun", String.class, int.class);
methodShowPeople.setAccessible(true);
Object result2 = methodShowPeople.invoke(student,"陆可",18);
System.out.println("invoke 带参的fun:"+result2);
}
4. Field
4.1获取Field属性的方式
getDeclaredFields();//得到本类中所有的属性
getDeclaredField("方法名",参数类型);//获取本类中指定的属性
getFields();//获取本类以及父辈类中public修饰的属性
getMethodFields("方法名",参数类型);//获取本类以及父辈类中指定public修饰的属性
4.2 Field类中常用的方法
- set(Object对象,值)-----为属性赋值
- getName()-----获取属性名
- getAnnotation()-----获取属性上的注解对象
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE,ElementType.FIELD}) //作用范围为类
@Retention(RetentionPolicy.RUNTIME) //运行期可见
public @interface Myannotation {
String value();
}
实体类
import com.ykx.annotation.Myannotation;
@Myannotation(value = "学生类")
public class Student extends People {
@Myannotation(value = "name--名字")
private String name;
@Myannotation(value = "age--年龄")
private int age;
public void show() {
}
public String show(String name) {
System.out.println("我的名字是:"+name);
return "我的名字是:"+name;
}
private void fun(String name,int age) {
System.out.println("我的名字是:"+name+"今年"+age+"岁了");
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
public static void main(String[] args) throws Exception{
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
//获取学生类的name属性
Field name = studentClass.getDeclaredField("name");
//name是私有属性,若要赋值需要设置
name.setAccessible(true);
//为其属性值赋值
name.set(student,"陆可");
System.out.println("student中name属性:"+name);
System.out.println(student);
//获取本类中所有属
Field[] declaredFields = studentClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
//getName-->获取属性名
System.out.println(declaredField.getName());
//getAnnotation-->获取每个属性对象上的注解对象
Myannotation annotation = declaredField.getAnnotation(Myannotation.class);
String value = annotation.value();
System.out.println(value);
}
}
5. 案例练习
在properties属性文件中指定类的路径,通过反射完成类对象的创建以及类中属性的赋值
properties属性文件
className=com.ykx.entity.Demo01
# 通过反射类创建实例对象
测试类
public static void main(String[] args) {
//加载属性文件步骤
//1. 获取路径
String path = "";
//2. 获取流
InputStream resourceAsStream = demo01.class.getClassLoader().getResourceAsStream("db.properties");
//3. 创建属性类
Properties properties = new Properties();
try {
//4. 加载属性文件
properties.load(resourceAsStream);
//5. 获取属性文件中ClassName的value值
String name = properties.getProperty("className");
//通过类路径的方式获取反射类
Class aClass = Class.forName(name);
//创建反射类实例对象
Object o = aClass.newInstance();
//获取反射类的所有属性
Field[] declaredFields = aClass.getDeclaredFields();
//为每个属性赋值
for (Field declaredField : declaredFields) {
//赋值
declaredField.setAccessible(true);
//随机生成一个数为其属性赋值,实体类中的属性值都设置为String数据类型
declaredField.set(o,new Random().nextInt(100)+"");
}
System.out.println(o);
}catch (Exception e){
e.printStackTrace();
}
}