反射的讲解

本文深入解析Java反射机制,介绍反射的定义、作用及其在动态语言特性中的关键地位。涵盖Class对象、Method、Field、Constructor等核心API,以及如何通过反射获取类的信息、创建对象和调用方法。
摘要由CSDN通过智能技术生成
反射的定义:
  • Reflection (反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
  • Class.forName(“java.lang.String”)
  • 加载完类之后,在堆内存的方法区就产生一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息我们可以通过这个对我们的形象称之为:反射
反射相关的主要API

java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor

Class类

对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。 对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特 定某个结构
(class/interface/enum/annotation/primitive type/void/[])的有关信息。

  • Class 本身也是一个类
  • Class 对象只能由系统建立对象
  • 一个加载的类在 JVM 中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由哪个 Class 实例所生成
  • 通过Class可以完整地得到一个类中的所有被加载的结构
  • Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的 Class对象

Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的 Class对象
public final Class getClass()

Class常用方法
方法名功能说明
static ClassforName(String name)返回指定类名name的Class对象
Object newInstance()调用缺省构造函数,返回Class对象的一个实例
getName()返回此Class对象所表示的实体(类,接口,数组类或void)的名称
Class getSuperClass()返回当前Class对象的父类的Class对象
Class[] getinterfaces()获取当前Class对象的接口
ClassLoader getClassLoader返回该类的类加载器
Construtor[] getConstructors()返回一个包含某些Constructor
Method getMothed(String name,Class…)返回一个Method对象,此对象的形参类型为paramType
Field[] getDeclaredFields()返回Field对象的一个数组
哪些类型可以有Class对象?
  • class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
  • interface:接口
  • []:数组
  • enum:枚举
  • annotation:注解@interface
  • primitive type:基本数据类型
  • void
传统的方式
public class Reflection {
    public static void main(String[] args) throws Exception {
        //通过实例化 new 对象 对属性进行赋值
        Student2 s1 = new Student2(20, "小米", 01);
        Student2 s2 = new Student2(20, "小米", 01);
        System.out.println(s1.hashCode());//成员变量的属性相同但是HashCode值不一样
        System.out.println(s2.hashCode());//好比人相同的名字,年龄,号,但是不能代表是同一个人
        System.out.println(s1==s2);
        System.out.println(s1.equals(s2));

        Class class1 = Class.forName("org.westos.demo2.Student");
        Student student =(Student) class1.newInstance();
        student.setName("李华");
        student.setAge(20);
        student.setNumber(02);
        System.out.println(student.toString());

    }
}
class Student2 {
    private int age;
    private String name;
    private int number;

    public Student2() {}

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

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

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

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

public class Reflection2 {
    public static void main(String[] args) throws Exception {
    Serializable是序列化:
    想把的内存中的对象状态保存到一个文件中或者数据库中时候
    想把对象通过网络进行传播的时候
    
        /*
        Class 类是实现Serializable接口
        public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {
            private static final int ANNOTATION= 0x00002000;
            private static final int ENUM      = 0x00004000;
            private static final int SYNTHETIC = 0x00001000;

            private static native void registerNatives();
            static {
                registerNatives();
            }
         */

        //public final native Class<?> getClass();
        //native是一个本地方法

        //可执行 可实行的Executable;
        //采取多态的形式
        //把这个对象变成字节需要Serializable
        Tiger animals = new Tiger();
        System.out.println(animals.toString());
        //获取Class 对象的几种方式,其一
        Class class1 = animals.getClass();
        System.out.println(class1);
        //其二:
        Class class2 = Class.forName("org.westos.demo2.Tiger");
        System.out.println(class2);
        //其三:通过类.class 也可以获得
        Class class3 = Tiger.class;
        System.out.println(class3);
        //其四:正对包装类,内置基本类型,只对包装类型有效
        Class type = Integer.TYPE;
        System.out.println(type);
        //获得父类的类型
        Class class4 = class1.getSuperclass();
        System.out.println(class4);
    }
}
class Animals {
    public String name;

    public Animals() {}

    public Animals(String name) {
        this.name = name;
    }

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

}
class Tiger extends Animals {
    public Tiger() {
       this.name = "老虎";
    }
}

class Cat extends Animals {
    public Cat() {
        this.name = "猫";
    }

哪些类有Class类对象:

public class Reflection3 {
    public static void main(String[] args) {
        Class c1 = Object.class;//class 关键字
        Class c2 = Comparable.class;//接口
        Class c3 = String[].class;//数组
        Class c4 = String[][].class;//二维数组
        Class c5 = Override.class;//注解
        Class c6 = ElementType.class;//枚举类型
        Class c7 = void.class;//void
        Class c8 = Integer.class;
        Class c9 = 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(c8);
        System.out.println(c9);
        //数组中,和长度无关,只要是一个维度并且类型相同,就是同一个class
        int[] a = new int[10];
        String[] b = new String[100];
        Class c10 = a.getClass();
        Class c11 = b.getClass();
        System.out.println(c10);
        System.out.println(c11);
        System.out.println(c10==c11);
    }
}

public class Reflection4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
/*
获取类的信息
*/
Class<?> class1 = Class.forName(“org.westos.demo2.Student”);
System.out.println(class1.getName());//全类名 包名 + 类名
System.out.println(class1.getSimpleName());//类名
System.out.println("===============");
//获取字段:get、set
Field[] fields = class1.getFields();//只能获得public的属性
System.out.println(fields.length);//0

    Field[] fields1 = class1.getDeclaredFields();//返回全部的属性,包括获得私有的
    System.out.println(fields1.length);
    for (Field field : fields1) {
        System.out.println(field);
    }
    Field name = class1.getDeclaredField("name");//获取指定字段
    System.out.println(name);
    System.out.println("==============");

    //获得方法:执行 invoke
    Method[] methods = class1.getMethods();
    System.out.println(methods.length);
    for (Method method : methods) {
        System.out.println("methods: " + method);//获得的是当前类的方法和被继承类的public方法
    }

    System.out.println("==============");
    Method[] declaredMethods = class1.getDeclaredMethods();
    System.out.println(declaredMethods.length);
    for (Method declaredMethod : declaredMethods) {   //获得当前类的所有方法
        System.out.println("declaredMethods " + declaredMethod);
    }
    System.out.println("================");

    //如果只获得方法的名字就会有问题:重载!(参数类型)
    Method setName = class1.getMethod("setName", String.class);
    Method setAge = class1.getMethod("setAge", int.class);
    System.out.println(setName);
    System.out.println(setAge);
    System.out.println("================");
    //获得构造器:创建对象 newInstance()
    Constructor[] constructors = class1.getConstructors();
    System.out.println(constructors.length);
    for (Constructor constructor : constructors) {
        System.out.println(constructor);//获得所有public的构造方法
    }
    System.out.println("================");

    Constructor[] constructors1 = class1.getDeclaredConstructors();
    System.out.println(constructors1.length);
    for (Constructor constructor : constructors1) {//获得所有public构造方法
        System.out.println(constructor);
    }
    System.out.println("==================");
    //获得指定的构造器:重载,只能通过参数名判断 null指的是空参 有参的必须按照参数名顺序
    Constructor constructor = class1.getConstructor(null);
    Constructor constructor2 = class1.getConstructor(int.class,String.class,int.class);
    System.out.println(constructor);
    System.out.println(constructor2);

}

}

class Student {
private int age;
private String name;
private int number;

public Student() {
}

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

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

public int getNumber() {
    return number;
}

public void setNumber(int number) {
    this.number = number;
}

@Override
public String toString() {
    return "Student{" +
            "age=" + age +
            ", name='" + name + '\'' +
            ", number=" + number +
            '}';
}
不加setAccessible()方法报错与解决方法:

//System.out.println(s4.getName());//java.lang.IllegalAccessException: Class org.westos.demo2.Reflection5 can not access a member of class org.westos.demo2.Student with modifiers "private" 无法访问私有化的构造方法,普通方法,和私有属性。 // 解决方案: // 1. 将修饰类属性的 private 改为 public // 2. 调用setAccessible()方法,来设置或取消访问检查,以达到访问私有对象的目的

public class Reflection5 {
    public static void main(String[] args) throws Exception {
        Class c1 = Class.forName("org.westos.demo2.Student");
        //创建对象,new 无参,有参
        Student s1 =(Student) c1.newInstance();//创建对象
        System.out.println(s1);
        System.out.println("==============");

        //通过指定构造器创建对象 new Student(20,"小明",01);
        Constructor declaredConstructor = c1.getDeclaredConstructor(int.class, String.class, int.class);
        Student s2 =(Student) declaredConstructor.newInstance(20, "小明", 01);
        System.out.println(s2);
        System.out.println("==================");

        Student s3 =(Student) c1.newInstance();
        //s3.setName("小明");正常操作
        //1.获得你要操作的方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //2.通过invoke 方法执行方法
        //一个class可能存在多个对象,这个方法需要找到是那个对象使用的,给他赋值;
        setName.invoke(s3,"小明");
        System.out.println(s3.getName());
        System.out.println("==================");

        //获得字段
        Student s4 =(Student) c1.newInstance();
        Field name = c1.getDeclaredField("name");//反射无法直接破坏私有的
        //name.set(s4,"小明");
        //System.out.println(s4.getName());//java.lang.IllegalAccessException: Class org.westos.demo2.Reflection5 can not access a member of class org.westos.demo2.Student with modifiers "private"  无法访问私有化的构造方法,普通方法,和私有属性。
        //       解决方案:
        //    1. 将修饰类属性的 private 改为 public
        //    2. 调用setAccessible()方法,来设置或取消访问检查,以达到访问私有对象的目的

        //显示调用setAccessible为true,则可以访问private方法!

        name.setAccessible(true);
        name.set(s4,"小明");
        System.out.println(s4.getName());

    }
}

小结:

  • 在实际的操作中,取得类的信息的操作代码,并不会经常开发。
  • 一定要熟悉java.lang.reflect包的作用,反射机制。
  • 如何取得属性、方法、构造器的名称,修饰符等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值