java的反射机制及使用

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();
}

执行结果:
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值