美文网首页
Java反射通俗易懂

Java反射通俗易懂

作者: info_gu | 来源:发表于2020-06-30 20:58 被阅读0次

反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁


1.获取Class对象

//        获取Class对象
//        1.Class.forName
        Class<?> aClass = Class.forName("bean.Student");
        System.out.println(aClass);
//         2.Student.class
        Class<Student> aClass1 = Student.class;
        System.out.println(aClass1);
//        3.lisi.getClass()
        Student lisi = new Student(18, "lisi");
        Class<? extends Student> aClass2 = lisi.getClass();
        System.out.println(aClass2);

2.判断是否为某个类的实例

public class Test_Gu {
    public static void main(String[] args)  {
        Class<Student> studentClass = Student.class;
        Student student = new Student();
        if (studentClass.isInstance(student)){
            System.out.printf("1");
        }
    }
}

运行结果如图:


image.png

3.通过反射来生成对象

1.使用Class对象的newInstance()方法来创建Class对象对应类的实例

public class Test_Gu {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
//        通过反射来生成对象
        Class<Student> studentClass = Student.class;
        Student student = studentClass.newInstance();
    }
}

2.使用Class对象的newInstance()方法来创建Class对象对应类的实例

public class Test_Gu {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//      先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例
        Class<Student> studentClass = Student.class;
        Constructor<Student> constructor = studentClass.getConstructor(int.class, String.class);
        Student student = constructor.newInstance(Student.class);
    }
}

4.获取某个Class对象的方法

getDeclaredMethods 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

public Method[] getDeclaredMethods() throws SecurityException
public class Test_Gu {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<Student> studentClass = Student.class;
        Method[] declaredMethods = studentClass.getDeclaredMethods();
        for (Method m :declaredMethods) {
            System.out.println(m);
        }
    }
}

控制台输出:

private int bean.Student.add(int,int)
public java.lang.String bean.Student.getName()
public void bean.Student.setName(java.lang.String)
public int bean.Student.getAge()
public void bean.Student.setAge(int)

Process finished with exit code 0

getMethods 方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。

public Method[] getMethods() throws SecurityException
public class Test_Gu {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<Student> studentClass = Student.class;
        Method[] methods = studentClass.getMethods();
        for (Method m :methods) {
            System.out.println(m);
        }
    }
}

控制台输出:

public java.lang.String bean.Student.getName()
public void bean.Student.setName(java.lang.String)
public int bean.Student.getAge()
public void bean.Student.setAge(int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

Process finished with exit code 0

getMethod 方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象

public Method getMethod(String name, Class<?>... parameterTypes)

注意:getMethod不能获取私有方法

举例说明中的Student类

package bean;

import java.util.stream.Stream;

/**
 * @PACKAGE_NAME: bean
 * @NAME: Student
 * @USER: "guzhenhua"
 * @PROJECT_NAME: JavaBase
 */
public class Student {
    int age;
    String name;
    public Student() {
    }

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

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

    private int add(int a,int b){
        return a+b;
    }
}

5.获取构造器信息(通过不同构造函数创建实例)

public class Test_Gu {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Student> studentClass = Student.class;
        Constructor<Student> constructor = studentClass.getConstructor(int.class,String.class);
        Student student = constructor.newInstance(18,"lisi");
        System.out.println(student.toString());
    }
}

6.获取类的成员变量(字段)信息

getFileds:访问公有的成员变量
getDeclaredField:所有已声明的成员变量,但不能得到其父类的成员变量.私有也可以获取

public class Test_Gu {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//  getFileds:访问公有的成员变量
        Student student = new Student(18,"lisi");
        Class<? extends Student> aClass = student.getClass();
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            Class<?> type = field.getType();
            String typeName = type.getTypeName();
            //获得成员变量的名称
            String fieldName = field.getName();
            System.out.println(typeName + " " + fieldName);
        }

        System.out.println("------------------");

//  getDeclaredField:所有已声明的成员变量,但不能得到其父类的成员变量
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field field : declaredFields) {
            Class<?> type = field.getType();
            String typeName = type.getTypeName();
            //获得成员变量的名称
            String fieldName = field.getName();
            System.out.println(typeName + " " + fieldName);
        }
    }
}

控制台输出:

int age
java.lang.String name
------------------
int age
java.lang.String name

7.调用方法

当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法

public Object invoke(Object obj, Object... args)
//bean-Student类中定义了
    public int add(int a,int b){
        return a+b;
    }

public class Test_Gu {
    public static void main(String[] args) throws, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Student> studentClass = Student.class;
        Student student = studentClass.newInstance();
        Method method = studentClass.getMethod("add", int.class, int.class);
        Object o = method.invoke(student, 18, 12);
        System.out.println(o);
    

控制台输出:

30

8.通过反射动态的创建对象

//动态的创建对象,通过反射
public class Test09 {

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获得Class对象
        Class c1 = Class.forName("com.lcy.reflection.User");

        //构造一个对象  此调用必须要有默认构造函数
        User user1 = (User) c1.newInstance();
        System.out.println(user1);  //调用默认构造方法

        //通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(int.class, String.class, String.class);
        User user2 = (User) constructor.newInstance(1, "陈平安", "剑气长城");
        System.out.println(user2);

        //通过反射调用普通方法
        User user3 = (User) c1.newInstance();
        //通过反射获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //invoke :激活的意思   (对象,"方法的值")
        setName.invoke(user3,"陆沉");
        System.out.println(user3.getName());

        //通过反射操作属性
        User user4 = (User) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        //不能直接操作私有属性,关闭安全检测,暴力反射可以提高效率
        name.setAccessible(true);
        name.set(user4,"宁姚");
        System.out.println(user4.getName());

    }

}

9.反射操作泛型

泛型是确保数据的安全性和免去强制类型转换问题

/通过反射获取泛型
public class Test11 {

    public void test01(Map<String,User> map, List<User> list) {
        System.out.println("test01");
    }

    public Map<String,User> test02() {
        System.out.println("test02");
        return null;
    }


    public static void main(String[] args) throws NoSuchMethodException {
        /*
        #java.util.Map<java.lang.String, com.lcy.reflection.User>
        class java.lang.String
        class com.lcy.reflection.User
        #java.util.List<com.lcy.reflection.User>
        class com.lcy.reflection.User
        */
        //加载的方法和参数
        Method method = Test11.class.getMethod("test01", Map.class, List.class);
        //获得泛型的参数类型
        Type[] genericParameterTypes = method.getGenericParameterTypes();

        for (Type type :genericParameterTypes) {  //打印泛型
            System.out.println("#"+type);
            if (type instanceof ParameterizedType) {  //想知道里面的参数类型
                //强转获得真实的泛型参数信息
                Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
                for (Type temp :typeArguments) {
                    System.out.println(temp);
                }
            }
        }

        /*
        class java.lang.String
        class com.lcy.reflection.User
         */
        method = Test11.class.getMethod("test02",null);
        //获得返回值类型
        Type genericReturnType = method.getGenericReturnType();
        if (genericReturnType instanceof  ParameterizedType) {
            Type[] types = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type temp :types) {
                System.out.println(temp);
            }
        }
    }
}

10.反射操作注解


//反射操作注解
public class Test12 {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.lcy.reflection.Student");

        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation :annotations) {
            //找到了外面的注解@com.lcy.reflection.TableTemp(value=db_stu)
            System.out.println(annotation);
        }

        //获得注解value的值  db_stu
        TableTemp tableTemp = (TableTemp) c1.getAnnotation(TableTemp.class);
        String value = tableTemp.value();
        System.out.println(value);

        /**
         * 获得类指定的注解
         * db_stu
         * db_name
         * String
         * 10
         */
        Field f = c1.getDeclaredField("name");  //name对应表中的字段
        FieldTemp annotation = f.getAnnotation(FieldTemp.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());

    }

}

@TableTemp("db_stu")
class Student{
    @FieldTemp(columnName = "db_id",type = "int",length = 10)
    private int id;
    @FieldTemp(columnName = "db_name",type = "String",length = 10)
    private String name;
    @FieldTemp(columnName = "db_age",type = "varchar",length = 5)
    private int age;

    public Student() {
    }

    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

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

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

//类名的注解
@Target(ElementType.TYPE)   //设置作用域
@Retention(RetentionPolicy.RUNTIME)  //设置什么级别可以获取
@interface TableTemp{
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldTemp{
    String columnName();  //列名的注解
    String type();      //类型
    int length();       //长度
}
 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;
    }
}

//类名的注解
@Target(ElementType.TYPE)   //设置作用域
@Retention(RetentionPolicy.RUNTIME)  //设置什么级别可以获取
@interface TableTemp{
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldTemp{
    String columnName();  //列名的注解
    String type();      //类型
    int length();       //长度
}

相关文章

  • Java反射通俗易懂

    反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是...

  • Java 反射机制

    Java 反射机制 概述 通俗易懂的来说,反射是可以理解为 Java 运行时的一本说明书。这本说明书里面,记录着被...

  • 博客地址

    java注解-01、java注解-02、Git面试资源java反射-01、java反射-02、java反射-03为...

  • Java反射机制入门

    Java反射机制入门 一、什么是反射 JAVA反射机制(The JAVA reflection mechanism...

  • Java基础之反射

    Java基础之—反射(非常重要)Java中反射机制详解Java进阶之reflection(反射机制)——反射概念与...

  • 反射之一

    总结内容源自一下文章粗浅看java反射机制反射机制应用实践谈谈java反射机制Java Reflection(反射...

  • 反射之二

    总结内容源自一下文章粗浅看java反射机制反射机制应用实践谈谈java反射机制Java Reflection(反射...

  • Java基础之反射

    Java基础之反射 反射基本介绍 反射的使用通过反射调用属性和方法通过反射获取配置文件 反射基本介绍 Java反射...

  • Java 反射机制

    Java 反射机制 什么是反射 Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”。 ...

  • 一探究竟:Java反射效率低的原因到底在哪?

    预备知识 了解 Java 反射基本用法 看完本文可以达到什么程度 了解 Java 反射原理及 Java 反射效率低...

网友评论

      本文标题:Java反射通俗易懂

      本文链接:https://www.haomeiwen.com/subject/gldxqktx.html