JavaSE基础——反射

1、反射概述
  Java反射机制是在 运行状态下,对于任意一个类,都能够知道这个类所有的属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及 动态调用对象的方法的功能 称为Java的反射机制。

  加载完类之后,在堆内存中的方法区就会产生了一个 Class 类型的对象 (一个类只有一个Class对象) ,这个对象就包含了完整的类的信息结构。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,通过镜子可以看到类的结构,所以我们称之为反射。

2、反射的优缺点

   优点: 可以实现动态的创建对象和编译,体现出很大的灵活性。
   缺点: 对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。

3、获取一个类的Class对象的三种方式:

/**
 * 获取一个类的Class对象的三种方式
 */
public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException {
        //方式1:通过类的实例对象和Object类的getClass()方法获取
        String s = new String("hello");
        Class class1 = s.getClass();
        System.out.println(class1);
        //方式2:通过类名.class获取到Class文件对象
        Class<String> class2 = String.class;
        System.out.println(class2);
        //方式3:通过Class类的静态方法forName()获取
        Class class3 = Class.forName("java.lang.String");
        System.out.println(class3);
        //获取到的都是一个对象,一个类只有一个Class类对象
        System.out.println(class1 == class2);
        System.out.println(class2 == class3);
    }
}

执行结果:
在这里插入图片描述
  4、通过反射获取类的构造方法并使用

   在反射机制中,把类中的成员(构造方法、成员方法、成员变量)都封装成了对应的类进行表示。构造方法类使用类 Constructor 表示。通过Class 类提供的方法获取构造方法:

  1、 返回一个构造方法:
      public Constructor<T> getConstructor(Class<?> ... parameterTypes) : 获取public修饰,指定参数类型所对应的构造方法。
      public Constructor<T> getDeclaredConstructor(Class<?> ... parameterTypes) : 获取指定参数类型所对应的构造方法(包含私有的)2、 返回多个构造方法:
       public Constructor<T> [] getConstructors() : 获取所有的public修饰的构造方法。
       public Constructor<T> [] getDeclaredConstructors() : 获取所有的构造方法(包含私有的)

代码演示:

//自定义Person类
public class Person {
    int id;
    String name;
    int age;

    public Person(){

    }
    private Person(int id) {
        this.id = id;
    }
    public Person(String name) {
        this.name = name;
    }
    public Person(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.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;
    }
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

//测试类
import java.lang.reflect.Constructor;
public class ReflectionDemo1 {
    public static void main(String[] args) throws Exception {
        //获取Person类的Class文件对象
        Class c = Class.forName("com.hang.reflection.Person");

        //获取Person类的构造方法,指定参数都是Class类型
        Constructor constructor = c.getConstructor(int.class,String.class,int.class);
        //获取所有的构造方法(含私有)
        Constructor[] declaredConstructors = c.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }

        //也可以通过获取到的字节码文件对象调用Class类的newInstance()创建反射类的对象
        //前提是反射类提供了非私有的空参构造器
        Person person = (Person) c.newInstance();
        System.out.println(person);
        //获取到的构造方法通过newInstance()方法创建Person实例
        Person person1 = (Person) constructor.newInstance(001, "司马恂", 36);
        System.out.println(person1);
    }
}

执行结果:
在这里插入图片描述
关闭反射类对象的权限检查的方法:

      public void setAccessible(boolean flag) throws SecurityException
      将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
      值为 false 则指示反射的对象应该实施 Java 语言访问检查。 

代码演示:

import java.lang.reflect.Constructor;

public class ReflectionDemo3 {
    public static void main(String[] args) throws Exception{
        //获取Person类的class文件对象
        Class c = Class.forName("com.hang.reflection.Person");
        //获取私有的构造方法
        Constructor constructor = c.getDeclaredConstructor(int.class);
        constructor.setAccessible(true);
        Person person = (Person) constructor.newInstance(001);
        System.out.println(person);

    }
}

默认开启访问权限检查的运行结果:出现异常
在这里插入图片描述
执行结果:
在这里插入图片描述

  5、通过反射获取类的成员变量并使用

   返回一个成员变量:
     public Field getFiled(String name) : 获取指定的 public 修饰的变量。
     public Field getDeclaredField(String name) : 获取指定的任意变量(含私有)。
   返回多个成员变量:
     public Field[] getFields() : 获取所有的 public 修饰的变量。
     public Field[] getDeclaredFields() : 获取所有的变量(含私有)

/**
 * 获取反射类的成员变量
 */

import java.lang.reflect.Field;

public class ReflectionDemo4 {
    public static void main(String[] args) throws Exception {
        Class c = Class.forName("com.hang.reflection.Person");
        Person person = (Person) c.newInstance();
        //获取所有的成员变量
        Field[] declaredFields = c.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        //获取成员变量
        Field name = c.getDeclaredField("name");
        name.setAccessible(true);
        name.set(person,"zhangsan");
        System.out.println(person);
    }
}

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

  6、通过反射获取类的成员方法并使用

    返回获取一个方法:
       public Method getMethod(String name,Class<?> parameterTypes): 获取 public 修饰的方法。
       public Method getDeclearedMethod(String name,Class<?> parameterTypes) : 获取任意的方法。
    返回获取所有的方法:
       public Method[] getMethods(): 获取本类中和父类中所有的 public 方法。
       public Method[] getDeclaredMethods(): 获取本类中的所有方法(含私有的)。 
    Method类中的方法invoke():
       public Object invoke(Object obj, Object... args) :
          对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。 

代码演示:

//动物类
public class Animal {
    private int id;
    private String name;
    private int age;

    public Animal() {
    }

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

    private void run(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
        System.out.println(name + " " + "Running");
    }

    private void show() {
        System.out.println("{" + this.id + "," + this.name + "," + +this.age + "}");
    }
}

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

/**
 * 通过反射获取类中的方法并执行
 */
public class ReflectionDemo6 {
    public static void main(String[] args) throws Exception {
        //获取Animal的Class对象
        Class c = Class.forName("com.hang.reflection.Animal");
        //获取构造器
        Constructor constructor = c.getConstructor(int.class, String.class, int.class);
        //由构造器创建Animal对象
        Animal animal = (Animal) constructor.newInstance(001, "dahuang", 3);
        //通过反射获取类中的一个方法
        Method method = c.getDeclaredMethod("run",int.class,String.class,int.class);
        //设置访问权限,关闭安全检测
        method.setAccessible(true);
        //通过Method类的方法invoke执行获取到的方法
        method.invoke(animal,001,"wangcai",5);
    }
}

  7、通过反射操作泛型

   Java采用泛型擦除的机制来引入泛型 , Java中的泛型仅仅是给编译器javac使用的,确保数据
的安全性和免去强制类型转换问题 , 但是 , 一旦编译完成 , 所有和泛型有关的类型全部擦除。

代码演示:通过反射来操作泛型,向一个泛型为String类的集合中添加int类数据。

import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * 通过反射来操作泛型
 * 向一个泛型为String类的集合中添加int类数据
 */
public class ReflectionTest {
    public static ArrayList<String> list = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        list.add("dahuang");
        list.add("wangcai");
        //获取list对象的Class对象
        //Class c = Class.forName("java.util.ArrayList");
        //直接使用ArrayList集合的实例创建它的Class对象
        Class c = list.getClass();
        Method method = c.getDeclaredMethod("add", Object.class);
        method.invoke(list,123);
        method.invoke(list,1234);
        method.invoke(list,12345);
        System.out.println(list);
    }
}

执行结果:
在这里插入图片描述
  8、通过反射操作注解

package com.hang.reflection;

/**
 * 反射操作注解
 */

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

public class ReflectionDemo {
    public static void main(String[] args) throws Exception {
        Class c = Class.forName("com.hang.reflection.Student");
        //反射获取注解
        Annotation[] annotations = c.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //反射获取注解的value的值
        Hang hang = (com.hang.reflection.Hang) c.getAnnotation(Hang.class);
        String value = hang.value();
        System.out.println(value);

        //获取字段上的注解的value值
        Field name = c.getDeclaredField("name");
        FieldAnnotation annotation = name.getAnnotation(FieldAnnotation.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());
    }
}

//学生类
@Hang(value = "db_Student")
class Student {
    @FieldAnnotation(columnName = "db_id", type = "int", length = 10)
    int id;
    @FieldAnnotation(columnName = "db_name", type = "varchar", length = 10)
    String name;
    @FieldAnnotation(columnName = "db_age", type = "int", length = 10)
    int age;

    public Student() {

    }

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

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

//类的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface Hang {
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldAnnotation {
    String columnName();//列名

    String type();//类型

    int length();//长度
}

在这里插入图片描述

发布了58 篇原创文章 · 获赞 7 · 访问量 2281

猜你喜欢

转载自blog.csdn.net/weixin_42492089/article/details/103463627