重要前言:Java的重要思想就是万物皆对象。
关于反射学习篇一
目录
反射理解
注:反射(Reflection)
反射就是:加载类,并允许以编程的方式 解剖类中的各种成分(成员变量、成员方法、构造器等);反射可以用来做框架的。
学习要点
学习如何获取类的信息,并对它们进行操作。
三种获取Class对象方式
注:作用是:获取类;
也是实现反射的第一步,获取Class类就是获取对应的字节码文件,就是获取到对应的类,然后继续通过此类获取到 对应的 构造器,成员变量,成员方法;然后进行一定操作;Class类对象代表了类。
案例
导入依赖
注:简化代码
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
创建对象模板类
Student类
package com.xie.reflect02.test.obj;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private String name;
private int age;
private char sex;
private double height;
private String hobby;
public Student(String name) {
this.name = name;
}
}
测试
测试类(Test1Class)
package com.xie.reflect02.test;
import com.xie.reflect02.test.obj.Student;
import org.junit.Test;
/**
* 目标:获取Class对象
* */
public class Test1Class {
/**
* 通过第一种方式
* */
@Test
public void testGetClass1() {
Class c = Student.class;
// 获取类的全类名
System.out.println(c.getName());
// 获取类的简名
System.out.println(c.getSimpleName());
}
/**
* 通过第二种方式 调用Class对象提供的forName()方法,方法内部需要传参,传一个全类名
* */
@Test
public void testGetClass2() throws ClassNotFoundException {
Class c = Class.forName("com.xie.reflect02.test.obj.Student");
// 获取类的全类名
System.out.println(c.getName());
// 获取类的简名
System.out.println(c.getSimpleName());
}
/**
* 不用单元测试,直接用main方法进行,判断通过三种方式获取到的是否是同一个对象
* */
public static void main(String[] args) throws Exception {
// 根据模板类,创建对应对象,并初始化对象中的其中一个字段name
Student s = new Student("小明");
// 获取Class对象
Class c1 = Student.class;
Class c2 = Class.forName("com.xie.reflect02.test.obj.Student");
Class c3 = s.getClass();
// 打印判断,观察
System.out.println(c1 == c2);
System.out.println(c2 == c3);
}
}
总的认识
反射作用
基本作用:可以得到一个类的全部成分然后操作。
可以破坏封装性。
最重要的用途是:适合做]ava的框架,基本上,主流的框架都会基于反射设计出一些通用的功能。
一,获取构造器
构造器应用案例
导入依赖
作用:maven项目—>简化代码
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
创建对象模板类
Cat类
package com.xie.reflect02.test.obj;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
private String name;
private int age;
private Cat(String name) {
this.name = name;
System.out.println("私有有参构造器name参数的执行了!!!");
}
public Cat(int age) {
this.age = age;
System.out.println("有参构造器int参数的执行了!!!");
}
}
测试
测试类(Test2Contructor)
package com.xie.reflect02.test;
import com.xie.reflect02.test.obj.Cat;
import org.junit.Test;
import java.lang.reflect.Constructor;
/**
* 目标:掌握获取类的构造器,并对其进行操作。
* */
public class Test2Contructor {
/**
* 获取public修饰的构造方法(构造器),获取全部构造器
* */
@Test
public void testGetContructors() {
// 1,反射第一步:必须先得到这个类的Class对象
Class c = Cat.class;
// 2,获取类的全部构造器
Constructor[] constructors = c.getConstructors();
// 3,遍历该数组,得到每一个构造器
for (Constructor constructor : constructors) {
// 打印构造器的名字(全类名)及构造参数的数量
System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
}
}
/**
* 同时获取private修饰的构造方法(构造器),获取全部构造器
*
* 开发中常用此种方式获取构造器
* */
@Test
public void testGetContructors2() {
// 1,反射第一步:必须先得到这个类的Class对象
Class c = Cat.class;
// 2,获取类的全部构造器
Constructor[] constructors = c.getDeclaredConstructors();
// 3,遍历该数组,得到每一个构造器
for (Constructor constructor : constructors) {
// 打印构造器的名字(全类名)及构造参数的数量
System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
}
}
/**
* 获取public修饰的构造方法(构造器)
*
* 获取指定参数的构造器,即获取某个构造器
* */
@Test
public void testGetContructor() throws Exception {
// 1,反射第一步:必须先得到这个类的Class对象
Class c = Cat.class;
// 2,获取某个构造器:无参构造器
Constructor constructor = c.getConstructor();
// 3,// 打印构造器的名字(全类名)及构造参数的数量
System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());
}
/**
* 获取指定参数的构造器,即获取某个构造器
*
* 同时获取private修饰的构造方法(构造器),开发中常用此种方式获取
* */
@Test
public void testGetContructor2() throws Exception {
// 1,反射第一步:必须先得到这个类的Class对象
Class c = Cat.class;
// 2,获取某个构造器:单参构造器(这里指的是Cat类中的name参数 与 int参数)
Constructor constructor = c.getDeclaredConstructor(String.class);
Constructor constructor2 = c.getDeclaredConstructor(int.class);
// 3,// 打印构造器的名字(全类名)及构造参数的数量
System.out.println(constructor.getName()+"--->"+constructor.getParameterCount());
System.out.println(constructor2.getName()+"--->"+constructor2.getParameterCount());
// 禁止检查--->访问权限
constructor.setAccessible(true);
// 初始化对象,然后进行返回
Cat cat1 = (Cat) constructor.newInstance("叮当猫");
Cat cat2 = (Cat) constructor2.newInstance(3);
System.out.println(cat1);
System.out.println("--------------------------------");
System.out.println(cat2);
}
}
获取的类构造器的作用
获取类构造器的作用:依然是初始化一个对象返回。
二,获取成员变量
成员变量应用案例
导入依赖
注:简化代码
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
创建对象模板类
Cat类
package com.xie.reflect02.test.obj;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
public static int a;
public static final String country = "中国";
private String name;
private int age;
public Cat(String name) {
this.name = name;
System.out.println("有参构造器name参数的执行了!!!");
}
public Cat(int age) {
this.age = age;
System.out.println("有参构造器int参数的执行了!!!");
}
}
测试
测试类(Test3Field)
package com.xie.reflect02.test;
import com.xie.reflect02.test.obj.Cat;
import org.junit.Test;
import java.lang.reflect.Field;
/**
* 目标:掌握获取类的成员变量,并对其进行操作。
* */
public class Test3Field {
/**
* 获取全部成员变量
* */
@Test
public void testGetFields() {
// 1,反射第一步:必须先得到类的Class对象
Class c = Cat.class;
// 2,获取类的全部成员变量。
Field[] fields = c.getDeclaredFields();
// 3,遍历这个成员的变量数组
for (Field field : fields) {
System.out.println(field.getName() + "--->" + field.getType());
}
}
/**
* 获取指定成员变量,即单个成员变量
* */
@Test
public void testGetField() throws Exception {
// 1,反射第一步:必须先得到类的Class对象
Class c = Cat.class;
Field name = c.getDeclaredField("name");
System.out.println(name.getName() + "--->" + name.getType());
Field age = c.getDeclaredField("age");
System.out.println(age.getName() + "--->" + age.getType());
System.out.println("---------------分隔符-----------------");
Field a = c.getDeclaredField("a");
System.out.println(a.getName() + "--->" + a.getType());
Field country = c.getDeclaredField("country");
System.out.println(country.getName() + "--->" + country.getType());
// 赋值,赋值前提需要一个对象来接收,所以先创建一个Cat对象
Cat cat = new Cat();
// 在设值之前,执行暴力反射,禁止检查访问权限,使其通过检查的拦截
name.setAccessible(true);
name.set(cat, "咖啡猫");
System.out.println("设值--->" + cat);
// 取值
String s = (String) name.get(cat);
System.out.println("取值--->" + s);
}
}
获取的成员变量的作用
获取类成员变量的作用:依然是赋值、取值。
三,获取成员方法
获取的成员方法的作用
获取类成员方法的作用:依然是执行此方法。
成员方法应用案例
导入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
创建模板类对象
Cat类
package com.xie.reflect02.test.obj;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
public static int a;
public static final String country = "中国";
private String name;
private int age;
public Cat(String name) {
this.name = name;
System.out.println("有参构造器name参数的执行了!!!");
}
public Cat(int age) {
this.age = age;
System.out.println("有参构造器int参数的执行了!!!");
}
/**
* 成员方法
* */
private void run() {
System.out.println("跑的贼快哈!!!");
}
public void eat() {
System.out.println("非常爱吃鱼!!!");
}
private String eat(String name) {
return "也爱吃猫粮!!!" + name;
}
}
测试
测试类(Test4Method)
package com.xie.reflect02.test;
import com.xie.reflect02.test.obj.Cat;
import org.junit.Test;
import java.lang.reflect.Method;
/**
* 目标: 掌握获取类的成员方法,并对其进行操作。
* */
public class Test4Method {
@Test
public void testGetMethods() throws Exception {
// 1,反射第一步:必须先得到类的Class对象
Class c = Cat.class;
// 2,获取类中的全部成员方法
Method[] methods = c.getDeclaredMethods();
// 3,遍历这个数组中的每个方法对象
for (Method method : methods) {
System.out.println(method.getName() + "--->" + method.getParameterCount() + "--->" + method.getReturnType());
}
System.out.println("----------------分隔符----------------");
// 4,获取某个成员方法
Method run = c.getDeclaredMethod("run");
System.out.println(run.getName() + "--->" + run.getParameterCount() + "--->" + run.getReturnType());
Method eat = c.getDeclaredMethod("eat", String.class);
System.out.println(eat.getName() + "--->" + eat.getParameterCount() + "--->" + eat.getReturnType());
System.out.println("----------------分隔符----------------");
// 5,invoke()为触发方法,触发执行某个对象的该方法,执行方法的前提是要有该对象,然后再有该对象的方法,所以先创建一个Cat对象
Cat cat = new Cat();
//
//调用无参数的run方法,用cat对象触发调用的
run.setAccessible(true);
eat.setAccessible(true);
Object invoke1 = run.invoke(cat);
String invoke2 = (String)eat.invoke(cat, " + 中国猫");
System.out.println(invoke1+ "--->" + invoke2);
}
}
简易框架制作案例
Maven依赖
注:简写代码之用
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
创建对象模板类
Student类
package com.xie.reflect02.test;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private String name;
private int age;
private char sex;
private double height;
private String hobby;
}
Teacher类
package com.xie.reflect02.test;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Teacher {
private String name;
private double salary;
}
制作框架
框架类(ObjectFrame)
package com.xie.reflect02;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
/**
* 简易框架,一个简单案例
* */
public class ObjectFrame {
/**
目标:保存任意对象的字段和其数据到指定文件中去
* */
public static void saveObject(Object obj) throws Exception {
// 创建打印流,把需要保存内容打印到指定文件中去
PrintStream ps = new PrintStream(new FileOutputStream("E:\\WorkStations\\JavaStation\\分点重点学习\\反射\\fanshe01\\data.txt", true));
// obj是可以接收任意对象的
Class c = obj.getClass();
String simpleName = c.getSimpleName();
ps.println("-------------------" + simpleName + "----------------------");
// 从类中取出它的全部成员变量
Field[] fields = c.getDeclaredFields();
// 遍历每个成员变量
for (Field field : fields) {
// 禁止检查访问控制
field.setAccessible(true);
// 拿到成员变量的名字
String name = field.getName();
// 拿到该成员变量在对象中的数据
//String value = (String) field.get(obj);
String value = field.get(obj) + "";
ps.println(name + "=" + value);
}
// 关闭流
ps.close();
}
}
测试
测试类(Test5Frame)
package com.xie.reflect02.test;
import com.xie.reflect02.ObjectFrame;
import org.junit.Test;
/**
* 目标:利用反射技术,设计一个保存任意对象字段信息的简易版框架
* */
public class Test5Frame {
@Test
public void save() throws Exception {
// 测试方法可用性
System.out.println("--666--");
// 创建对象
Student s1 = new Student("柳岩", 18 , '女',60, "唱歌");
Teacher t1 = new Teacher("谢老师",12000);
// 调用框架,进行保存对象信息操作
ObjectFrame.saveObject(s1);
ObjectFrame.saveObject(t1);
}
}
备注
注:应用的时候记得多多注意各类的包的正确性。此类包括第三方包的类及本类。