Java教程

JAVA反射学习

本文主要是介绍JAVA反射学习,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

反射

反射的定义

Reflection(反射)是JAVA被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API 取得任何类的内部信息,并直接能操作任意对象的内部属性及方法
加载完类之后,在堆的方法区中就产生了一个Class类型的对象(一个类只有一个Class 对象),这个对象就包含了完整的类的结构信息,我们可以通过这个对象看到类的结构,这个对象就像一面镜子,通过这个镜子看到类的结构,所以我们形象的称之为:反射
过程图解


反射的简单案例
    package com.njit.reflection;
    public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 通过反射获取类的Class对象
        Class c1 = Class.forName("com.njit.reflection.User");
        Class c2 = Class.forName("com.njit.reflection.User");
        Class c3 = Class.forName("com.njit.reflection.User");
        //一个类在内存中只有一个Class对象
        // 一个类被加载后,类的整体结构都会被封装在Class对象中
        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
    }
    }
/**
实体类
*/
class User {
   private String name;
   private int id;
   private int age;
   public User() {
   }
   public User(String name, int id, int age) {
       this.name = name;
       this.id = id;
       this.age = age;
   }
   public String getName() {
       return name;
   }
   public void setName(String name) {
       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;
   }
   @Override
   public String toString() {
       return "User{" +
               "name='" + name + '\'' +
               ", id=" + id +
               ", age=" + age +
               '}';
   }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

获取class类的代码演示
package reflection;

public class Test02 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        //方式1:通过对象获取
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());
        //方式2:通过forName获取
        Class c2 = Class.forName("reflection.Person");
        System.out.println(c2.hashCode());
        //方式3:通过类名
        Class c3 = Student.class;
        System.out.println(c3.hashCode());
//        方式4:基本内置类型的包装类都有一个TYPE类型
        Class c4 = Integer.TYPE;
        System.out.println(c4);
//        获取父类的Class
        Class c5 = c1.getSuperclass();
        System.out.println(c5.hashCode());
    }
}
//父类
class Person{
    private  String name;
    public Person() {
    }
    public Person(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student extends Person{
    public Student(){
        super("学生");
    }
}
class Teacher extends Person{
    public Teacher(){
        super("老师");
    }
}
哪些类可以有class对象
  • class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
  • interface:接口(Comparable.class)
  • []:数组(Sring[].class)
  • enum:枚举(ElementType.class)
  • annotation:注解@interface(Override.class)
  • primitive type:基本数据类型(Integer.class,int.class)
  • void(void.class)
类的加载

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package reflection;

public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException {
//        获取系统类的加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);   //返回jdk.internal.loader.ClassLoaders$AppClassLoader@77556fd
//        获取系统类加载器的父类加载器-->扩展加载器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);// 返回jdk.internal.loader.ClassLoaders$PlatformClassLoader@43a25848
//        获取扩展类加载器的父类加载器-->根加载器(c/c++)
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);  //返回null   根加载器是无法直接获取的
//        测试当前类是用哪个加载器加载的
        ClassLoader classLoader = Class.forName("reflection.Test03").getClassLoader();
        System.out.println(classLoader);  // 返回 jdk.internal.loader.ClassLoaders$AppClassLoader@77556fd
//        测试JDK内置的类是使用什么加载器加载的
        ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader1); //  返回 null
//         获取系统加载器可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
    }
}
双亲委派机制

双亲委派的意思是如果一个类加载器需要加载类,那么首先它会把这个类请求委派给父类加载器去完成,每一层都是如此。一直递归到顶层,当父加载器无法完成这个请求时,子类才会尝试去加载。
这个机制主要出去安全性方面的考虑,就是用户自定义一个类,和基础类有冲突,会优先执行基础类,不加载用户自定义的类

获得类的信息

总结:
方法是否加Declared这个单词的,表示是否获取所有方法,不加Declared这个的方法,只能获取public属性对应的东西,如果加了,则能获得包含私有属性的东西
如果是复数形式的方法,表示获得的是该类所有的属性
如果是单数形式的方法,则需要加上对应的name,参数,表示的是获得指定属性
示列代码如下:

package reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

//获得类的信息
public class Test04 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("reflection.User");
//        获得类的名字
        System.out.println(c1.getName());  //包名加类名   reflection.User
        System.out.println(c1.getSimpleName());  //类名  User
//        c1.getFields();   这个只能找到public属性
        Field[] fields = c1.getDeclaredFields();//可以找到所有的属性
        for (Field field : fields) {
            System.out.println(field);
        }
//        获得指定属性的值
//        Field name = c1.getField("name");
//        System.out.println(name);
        Field name1 = c1.getDeclaredField("name");
        System.out.println(name1);
//        获取类的方法
        Method[] methods = c1.getMethods(); //获取本类的public方法
        for (Method method : methods) {
            System.out.println(method);
        }
        Method[] declaredMethods = c1.getDeclaredMethods(); //获得本类的所有的方法
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
//        获取指定的方法
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);
//        获取构造器
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        Constructor[] declaredConstructors = c1.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
//        获得指定的构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        System.out.println(declaredConstructor);
    }
}
动态创建对象执行方法

创建一个class对象

        //获得class对象
        Class c1 = Class.forName("reflection.User");
        //构建一个对象
//        User user =(User)c1.newInstance();
//        System.out.println(user);
//        通过构造器创建对象
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User user2 = (User) declaredConstructor.newInstance("gek", 001, 19);
        System.out.println(user2);

通过反射去创建一个方法

//        通过反射去获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
//        invoke :激活
//        (对象,"方法的值")
        setName.invoke(user2,"gek2");
        System.out.println(user2.getName());

通过反射操作属性

//        通过反射获取属性
        Field name = c1.getDeclaredField("name");
//       不能直接操作私有属性,关闭权限检测
        name.setAccessible(true);
        name.set(user2,"gek3");
        System.out.println(user2.getName());

总结:
操作方法步骤:
1、通过反射去获得方法
2、通过invoke方法激活使用:方法.invoke(对象,方法的值)
操作属性步骤:
1、通过反射获取属性
2、必须关闭权限检测 通过属性.setAccessible(true)
3、操作属性

性能检测

性能总结:普通方式性能>关闭检测反射方法>直接用反射方法
代码示例

package reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test06 {
    /**
     * 普通方式
     */
    public static void test01(){
        User user = new User();
        long starttime = System.currentTimeMillis();
        for (int i = 0; i <100000000 ; i++) {
            user.getName();
        }
        long endtime = System.currentTimeMillis();
        System.out.println("普通方法执行了:"+(endtime-starttime));
    }
    /**
     * 反射方法
     */
    public static void  test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getMethod("getName", null);
        long starttime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            getName.invoke(user,null);
        }
        long endtime = System.currentTimeMillis();
        System.out.println("反射执行的时间为:"+(endtime-starttime));
    }
    /**
     * 反射关闭检测
     */
    public static void  test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getMethod("getName", null);
        getName.setAccessible(true);
        long starttime = System.currentTimeMillis();
        for (int i = 0; i <100000000 ; i++) {
            getName.invoke(user,null);
        }
        long endtime = System.currentTimeMillis();
        System.out.println("反射关闭检测时间:"+(endtime-starttime));
    }


    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        test01();
        test02();
        test03();
    }
    /**
     * 普通方法执行了:3ms
     * 反射执行的时间为:248ms
     * 反射关闭检测时间:145ms
     */
}

反射操作泛型

package reflection;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class Test07 {
    public  static  void  test01(Map<String,User> map, List<Integer> list){
        System.out.println("test01");
    }
    public  static  Map<String,User> test02(){
        System.out.println("test02");
        return  null;
    }

    public static void main(String[] args) throws NoSuchMethodException {
        Method method = Test07.class.getMethod("test01", Map.class, List.class);
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("####"+genericParameterType);
            if(genericParameterType instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
        Method method2 = Test07.class.getMethod("test02");
        Type  returnType = method2.getReturnType();
        if(returnType instanceof  ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }
}
/**
 * ####java.util.Map<java.lang.String, reflection.User>
 * class java.lang.String
 * class reflection.User
 * ####java.util.List<java.lang.Integer>
 * class java.lang.Integer
 */
通过反射获取注解信息
package reflection;

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class Test08 {
    public static void main(String[] args) throws NoSuchFieldException {
        Class c1 = Test08.class.getClass();
//        通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        System.out.println(annotations);
//        获取注解的value值
        MyAnnotation annotation = (MyAnnotation) c1.getAnnotation(MyAnnotation.class);
        System.out.println(annotation.value());
//        获取类的字段的指定注解
        Field name = c1.getDeclaredField("name");
        MyAnnotation2 annotation1 = name.getAnnotation(MyAnnotation2.class);
        System.out.println(annotation1.columnName());
        System.out.println(annotation1.Type());
        System.out.println(annotation1.Length());
    }
}
@MyAnnotation("test1")
class User2{
    @MyAnnotation2(columnName = "name",Type = "String",Length = 10)
    private String name;
    @MyAnnotation2(columnName = "age",Type = "Integer",Length = 8)
    private int age;
    @MyAnnotation2(columnName = "id",Type = "Integer",Length = 10)
    private int id;
    public User2(){

    }
    public  User2(String name,int age,int id){
        this.name=name;
        this.age=age;
        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;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "User2{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }
}

@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    String value();
}
@Target(value = {ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface  MyAnnotation2{
    String columnName();
    String Type();
    int Length();
}
这篇关于JAVA反射学习的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!