文章目录
1.反射的简介(Reflection)
(1)反射的理解
- 反射机制允许程序在执行期借助Reflection API取得类内部的任何信息,并且能直接操作任意对象的内部属性及方法
Class c = Class.forName("java.lang.String");
- 加载完类之后,在jvm的方法区中就生成了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息,我们通过这个对象看到类的结构。这个Class对象就像一面镜子,通过这个镜子可以看到类的结构,所以,我们称其为:反射
来自狂神的视频
(2)反射的优点
优点:可以实现动态创建对象和编译,体现出极大的灵活性
缺点:对性能有影响。使用反射基本上是一种解释型的操作,我们告诉JVM我们希望做什么,并且它满足我们的要求。这类操作总是慢于直接执行相同的操作
反射的性能很低,一般情况下不建议使用。
(3)Class类
对象照镜子后可以得到的信息:包括某个类的属性、方法和构造器以及某个类到底实现了哪些接口等等。对于每个类而言,JRE都为其保留了一个不变的Class对象。一个Class对象包含了特定某个结构(class,interface,enum,annotation,primitive type,void,[])的有关信息
- Class本身也是一个类
- Class对象只能有系统建立对象
- 一个加载的类在jvm中只会有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个.class文件
- 每个类的实例都会记得自己是由哪个Class实例所生成
- 每个Class可以完整地得到一个类中的所有被加载的结构
- Class类是Reflection的根源,针对任何你想动态加载、运行的类,都必须先获得相应的Class对象
2.反射的获取
(1)Class类的一些常用方法
方法名 | 功能说明 |
---|---|
static ClassforName(String name) | 返回指定类名的Class对象 |
Object newInstance() | 调用缺省构造函数,返回Class对象的一个实例 |
getName() | 返回此Class对象所表示的实体(包含类,接口,数组类或void)的名称 |
Class getSuperClass() | 返回当前对象的父类的Class对象 |
Class[] getInterfaces() | 返回当前Class对象的接口 |
ClassLoader getClassLoader() | 返回该类的类加载器 |
Constructor[] getContructors() | 返回该类的构造器 |
Method getMethod(String name,Class… T) | 返回该类的方法 |
Field[] getDeclaredFields() | 返回该类的Field |
(2)获取Class类的实例的方法
1、若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class clazz = Person.class;
2、已知某个类的实例对象,通过该实例的getClass() 方法获取Class对象
Class clazz = person.getClass();
3、已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法**forName()**获取,可能抛出ClassNotFundException异常
Class clazz = Class.forName("wu.reflection.Student");
4、如果是内置基本数据类型的包装类的话可以直接用 .Type
Class<Integer> type = Integer.TYPE;
创建方法测试:
//测试Class类的创建方式有哪些
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println(person.getName());
//方式一:通过对象获得
Class c1 = person.getClass();
System.out.println(c1.hashCode());
//方式二:通过类名.class获得
Class<Student> c3 = Student.class;
System.out.println(c3.hashCode());
//方式三:通过Class类的静态方法forName()获取
Class c2 = Class.forName("wu.reflection.Student");
System.out.println(c2.hashCode());
//方式四:基本内置类型的包装类都有一个Type属性
Class<Integer> type = Integer.TYPE;
System.out.println(type);
//获得父类类型
Class c4 = c1.getSuperclass();
System.out.println(c4.hashCode());
}
}
class Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 学生类
class Student extends Person{
public Student(){
this.setName("学生");
}
}
// 老师类
class Teacher extends Person{
public Teacher(){
this.setName("老师");
}
}
增加:哪些类可以有Class对象
- class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
- interface:接口
- []:数组
- enum:枚举
- annotation:注解@interface
- primitive type:基本数据类型
- void
//所有类型的class
public class Test04 {
public static void main(String[] args) {
Class c1 = Object.class; // 类
Class c2 = Comparable.class; // 接口
Class c3 = String[].class; // 一维数组
Class c4 = int[][].class; // 二维数组
Class c5 = Override.class; // 注解
Class c6 = ElementType.class; // 枚举
Class c7 = Integer.class; // 基本数据类型
Class c8 = void.class; // void
Class c9 = Class.class; // Class
System.out.println("类:" + c1);
System.out.println("接口:" + c2);
System.out.println("一维数组:" + c3);
System.out.println("二维数组:" + c4);
System.out.println("注解:" + c5);
System.out.println("枚举:" + c6);
System.out.println("基本数据类型:" + c7);
System.out.println("void:" + c8);
System.out.println("Class:" + c9);
}
}
执行结果:
(3)获取运行时类的完整结构
通过反射获取类的运行时结构:
Field,Method,Constructor,Superclass,Interface,Annotation
- 实现的全部接口
- 所继承的父类
- 全部的构造器
- 全部的方法
- 全部的Field
- 注解
- …
1、获取类的名字
Class c1 = Class.forName("wu.reflection.User");
// 获得类的名字
System.out.println(c1.getName()); // 获得包名 + 类名
System.out.println(c1.getSimpleName()); // 获得类名
2、获取类的属性
1、获取public属性
Class c1 = Class.forName("wu.reflection.User");
// 获得类的属性
Field[] fields = c1.getFields(); // 只能找到public属性
for (Field field : fields) {
System.out.println(field);
}
2、获取全部属性(包括private修饰的)
Class c1 = Class.forName("wu.reflection.User");
Field[] declaredFields = c1.getDeclaredFields(); // 可以找到全部属性
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
3、获取指定的属性
Class c1 = Class.forName("wu.reflection.User");
Field name = c1.getDeclaredField("name"); // 这里由于name是private,所以要用getDeclaredField()
System.out.println(name);
3、获取类的方法
1、获取public方法
Class c1 = Class.forName("wu.reflection.User");
// 获得类的方法
Method[] methods = c1.getMethods();// 获得public方法
for (Method method : methods) {
System.out.println(method);
}
2、获取所有方法(包括private)
Class c1 = Class.forName("wu.reflection.User");
Method[] declaredMethods = c1.getDeclaredMethods();// 获得所有方法
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
3、获取指定的方法
Class c1 = Class.forName("wu.reflection.User");
//获得指定方法
Method getName = c1.getMethod("getName", null); // 只能获得public方法
Method getAge = c1.getDeclaredMethod("getAge", null); // 可以获得所有方法
Method getAll = c1.getDeclaredMethod("getAll",int.class,String.class,int.class);
System.out.println(getName);
System.out.println(getAge);
System.out.println(getAll);
需要注意的是:
当我们需要获取指定的方法时,后面要指定传入的参数类型的class对象,没有则为null,例如
// 原方法有三个参数
// public String getAll(int id,String name,int age) { return "";}
c1.getDeclaredMethod("getAll",int.class,String.class,int.class);
4、获取类的构造器
1、获取所有public的构造器)
Class c1 = Class.forName("wu.reflection.User");
//获得所有的构造器
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println("getConstructors(public)--->"+constructor);
}
2、获取所有的构造器(包括private)
Class c1 = Class.forName("wu.reflection.User");
Constructor[] declaredConstructors = c1.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println("getDeclaredConstructors(所有)--->"+declaredConstructor);
}
3、获取指定的构造器
Class c1 = Class.forName("wu.reflection.User");
//获得指定的构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(int.class, String.class, int.class);
System.out.println(declaredConstructor);
需要注意的是,这里只需要传入该构造器所含参数的类型
4、测试
// 获得类的信息
public class Test08 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("wu.reflection.User");
System.out.println("============================获得类的名字==================================");
//获得类的名字
System.out.println(c1.getName());//获得包名 + 类名
System.out.println(c1.getSimpleName());//获得类名
System.out.println("=============================获得类的属性(public)=================================");
//获得类的属性
Field[] fields = c1.getFields();//只能找到public属性
for (Field field : fields) {
System.out.println(field);
}
System.out.println("==========================找到全部属性====================================");
Field[] declaredFields = c1.getDeclaredFields();//可以找到全部属性
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("=============================获得指定属性的值=================================");
//获得指定属性的值
Field name = c1.getDeclaredField("name"); // 这里由于name是private,所以要用getDeclaredField()
System.out.println(name);
System.out.println("============================获得类的方法(public)==================================");
//获得类的方法
Method[] methods = c1.getMethods();//获得public方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("=========================获得所有方法=====================================");
Method[] declaredMethods = c1.getDeclaredMethods();//获得所有方法
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
//获得指定方法
Method getName = c1.getMethod("getName", null);// 只能获得public方法
Method getAge = c1.getDeclaredMethod("getAge", null);// 可以获得所有方法
Method getAll = c1.getDeclaredMethod("getAll",int.class,String.class,int.class);
System.out.println(getName);
System.out.println(getAge);
System.out.println(getAll);
System.out.println("==============================获得所有的构造器================================");
//获得所有的构造器
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println("getConstructors(public)--->"+constructor);
}
Constructor[] declaredConstructors = c1.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println("getDeclaredConstructors(所有)--->"+declaredConstructor);
}
System.out.println("===========================获得指定的构造器===================================");
//获得指定的构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(int.class, String.class, int.class);
System.out.println(declaredConstructor);
}
}
//实体类:pojo , entity
class User{
private int id;
private String name;
private int age;
public User() {
}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
// 有三个参数
public String getAll(int id,String name,int age) {
return "";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
执行结果:
3.反射的使用
(1)创建对象
1、使用newInstance()方法
// 获得Class对象
Class c1 = Class.forName("wu.reflection.User");
// 构造一个对象
User user = (User) c1.newInstance(); // 本质上是调用无参构造器构造的
当类中没有无参构造时,会报错,还需要有相应的权限
2、获取构造器
Class c1 = Class.forName("wu.reflection.User");
//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(int.class, String.class, int.class);
Object user2 = constructor.newInstance(001, "好好玩", 20);
获取指定的构造器创建对象,创建时根据构造器函数传入参数
(2)调用对象的方法
要使用对象里的方法,要先获取到这个方法(上面讲过),然后调用该方法的
invoke() 方法
1、调用public方法
Class c1 = Class.forName("wu.reflection.User");
//通过反射调用普通方法
User user3 = (User) c1.newInstance();
//通过反射获取一个方法
user3.setAge(30); // 普通方法设置属性
//invoke : 激活的意思
//( 对象 , "方法的值" )
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(user3,"还好玩");
2、调用没有权限的方法(private)
当这个类里的方法是private修饰的时候,一般我们是无法使用的,而如果用反射的话,只需要调用该方法的setAccessible(true),将true传入,表示不开启安全检测,直接放行
Class c1 = Class.forName("wu.reflection.User");
User user3 = (User) c1.newInstance();
Method getAll = c1.getDeclaredMethod("getAll", int.class, String.class, int.class);
// 设置setAccessible为true
getAll.setAccessible(true);
// 调用invoke()方法
System.out.println(getAll.invoke(user3,1, "wu", 20));
(3)操作对象的属性
public的属性不反射也能操作就不演示了。
当属性是由private修饰的时候,操作属性的方法和调用方法的方法差不多,也是先获取到相应的属性名,再调用该属性的setAccessible(true),将true传入,表示不开启安全检测,直接放行,之后直接调用该属性的set() 方法进行赋值操作
Class c1 = Class.forName("wu.reflection.User");
//通过反射操作属性
User user4 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,我们需要关闭程序的安全检测,即把属性或者方法的setAccessible()设置为true.
name.setAccessible(true);
name.set(user4,"还好玩"); // 调用set()方法
(4)测试
// 动态的创建对象,通过反射
public class Test09 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
// 获得Class对象
Class c1 = Class.forName("wu.reflection.User");
// 构造一个对象
// User user = (User) c1.newInstance();
// System.out.println(user);
//通过构造器创建对象
// Constructor constructor = c1.getDeclaredConstructor(int.class, String.class, int.class);
// Object user2 = constructor.newInstance(001, "好好玩", 20);
// System.out.println(user2);
//通过反射调用普通方法
User user3 = (User) c1.newInstance();
//通过反射获取一个方法
user3.setAge(30); // 普通方法设置属性
//invoke : 激活的意思
//( 对象 , "方法的值" )
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(user3,"还好玩");
System.out.println(user3);
Method getAll = c1.getDeclaredMethod("getAll", int.class, String.class, int.class);
// 设置setAccessible为true
getAll.setAccessible(true);
// 调用invoke()方法
System.out.println(getAll.invoke(user3,1, "wu", 20));
System.out.println("=============操作类的属性=================");
//通过反射操作属性
User user4 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,我们需要关闭程序的安全检测,即把属性或者方法的setAccessible()设置为true.
name.setAccessible(true);
name.set(user4,"还好玩");
System.out.println(user4);
}
}
//实体类:pojo , entity
class User{
private int id;
private String name;
private int age;
public User() {
}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
// 有三个参数
private String getAll(int id,String name,int age) {
return "执行了getAll()方法";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
执行结果:
4.反射操作注解
1、获取注解
Class c1 = Class.forName("wu.reflection.Student2");
// 通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
2、获取注解的value值
Class c1 = Class.forName("wu.reflection.Student2")
// 获得注解的value的值
TableWu tableWu = (TableWu) c1.getAnnotation(TableWu.class);
String value = tableWu.value();
System.out.println(value);
3、获取指定的注解
// 获得类指定的注解
Field name = c1.getDeclaredField("name"); // 获取方法名
FieldWu annotation = name.getAnnotation(FieldWu.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length());
4、测试
//练习反射操作注解
public class Test12 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("wu.reflection.Student2");
// 通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
// 获得注解的value的值
TableWu tableWu = (TableWu) c1.getAnnotation(TableWu.class);
String value = tableWu.value();
System.out.println(value);
// 获得类指定的注解
Field name = c1.getDeclaredField("name"); // 获取方法名
FieldWu annotation = name.getAnnotation(FieldWu.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length());
}
}
@TableWu("db_student")
class Student2{
@FieldWu(columnName = "db_id",type = "int",length = 10)
private int id;
@FieldWu(columnName = "db_age",type = "int",length = 10)
private int age;
@FieldWu(columnName = "db_name",type = "varchar",length = 5)
private String name;
public Student2() {
}
public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//类名的注解
@Target(ElementType.TYPE) // 表示是类的注解
@Retention(RetentionPolicy.RUNTIME)
@interface TableWu{
String value();
}
//属性的注解
@Target(ElementType.FIELD) // 表示是属性的注解
@Retention(RetentionPolicy.RUNTIME)
@interface FieldWu{
String columnName();
String type();
int length();
}
执行结果: