栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

面试系列之Java反射

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

面试系列之Java反射

反射指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类、方法和字段,这种动态获取程序信息以及动态调用对象的功能称为Java的反射机制。

在Java中,除了int、double等基本类型外,Java的其他类型全部都是class,

class是由JVM在执行过程中动态加载的,每加载一种class,JVM就为其创建一个Class实例。通过Class实例获取class信息的方法称为反射;

只有JVM能创建Class实例,我们自己的java程序是无法创建Class实例的。

每个Java文件都会被编译成.class文件,这些class文件在程序运行时会被ClassLoader加载到JVM中,当一个类被加载以后,JVM就会在内存中自动产生一个Class对象。

由于JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,因此如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class所有信息。

获取Class实例的三种方式

  • 通过一个class的静态变量获取
  • 通过静态变量提供的getClass()获取
  • 通过静态方法Class.forName()获取
        //方法一、直接通过一个class的静态变量获取
        Class cls = String.class;

        //方法二、通过实例变量提供的getClass()获取
        String s = "Hello";
        Class cs = s.getClass();

        //方法三、如果知道一个class的完整类名,可以通过静态方法Class.forName()获取
        Class ss = Class.forName("java.lang.String");

        System.out.println(s1 == s2); //true
        System.out.println(s1 == s3); //true

因为Class实例在JVM中是唯一的,所以上述方法获取的Class实例是同一个实例。

通过Class实例我们可以创建对应类型的实例,相当于new String(),不过只能调用public的无参构造方法。

        Class aa = String.class;
        String str = (String)aa.newInstance();

利用反射获取成员变量

  • Field getField(name):根据字段名获取某个public的field(包括父类)
  • Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
  • Field[] getFields():获取所有public的field(包括父类)
  • Field[] getDeclaredFields():获取当前类的所有field(不包括父类)
        Class stu = Student.class;
        for(Field ff:stu.getDeclaredFields()) {
            System.out.println(ff);
        }
        //获取所有public的成员变量
        System.out.println(stu.getFields());
        //获取所有非public的成员变量
        System.out.println(stu.getDeclaredFields());
        //根据Name获取变量
        System.out.println(stu.getDeclaredField("paperNo"));


        执行结果:
        private java.lang.String com.garin.springboot.demo.Student.name
        private int com.garin.springboot.demo.Student.age
        private int com.garin.springboot.demo.Student.id
        private java.lang.String com.garin.springboot.demo.Student.paperNo
        private java.lang.String com.garin.springboot.demo.Student.mobile
        private java.lang.String com.garin.springboot.demo.Student.mail
        private java.util.Date com.garin.springboot.demo.Student.createTime
        private java.util.Date com.garin.springboot.demo.Student.updateTime
        [Ljava.lang.reflect.Field;@10f87f48
        [Ljava.lang.reflect.Field;@b4c966a
        private java.lang.String com.garin.springboot.demo.Student.paperNo
@Data
public class Student {

    private String name;
    private int age;
    private int id;
    private String paperNo;
    private String mobile;
    private String mail;
    private Date createTime;
    private Date updateTime;

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

如果利用set、get方法来获取和设置private、protected修饰的成员变量时,需要利用setAccessibl(true)来忽略访问修饰符的检查,否则程序将报错。

利用反射获取方法

  • Method getMethod(name, Class...):获取某个public的Method(包括父类)
  • Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
  • Method[] getMethods():获取所有public的Method(包括父类)
  • Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
        Class stu = Student.class;
        // 获取public方法getScore,参数为String:
        System.out.println(stu.getMethod("getName"));
        // 获取所有的public方法:
        System.out.println(stu.getDeclaredMethods());
        //循环打印每个方法名
        for (Method mm:stu.getDeclaredMethods()) {
            System.out.println("方法名:"+ mm);
        }
        // 获取所有的private方法:
        System.out.println(stu.getMethods());

获取到类的成员方法之后,如果要执行某一个方法,可以使用invoke()方法来执行。

获取构造方法:

  • getConstructor(Class...):获取某个public的Constructor;
  • getDeclaredConstructor(Class...):获取某个Constructor;
  • getConstructors():获取所有public的Constructor;
  • getDeclaredConstructors():获取所有Constructor。

调用非public的时候,需要设置setAccessible(true)可以访问非public方法

        Class st = Student.class;
        ClassLoader cd = st.getClassLoader();
        System.out.println("类加载器"+cd);
        //获取所有构造方法
        Constructor[] ct = st.getConstructors();
        //带参构造方法
        Constructor cs = st.getConstructor(String.class);
        Student ss = (Student)cs.newInstance("studentA");
        System.out.println(ss);

学了这么多反射的知识后,我们来看下反射的面试题:

1、获取字节码的方式有几种 ??

获取字节码的三种方法:

  • Class.forName() //Class ss = Class.forName("java.lang.String");
  • 类名.class // Class cls = String.class;
  • this.getCLass() // String s = "Hello"; Class cs = s.getClass();

2、Java反射API有几类??

  • Field类:提供有关类的属性信息
  • Constructor类:提供有关类的构造方法的信息
  • Method类:提供有关类的方法的信息,包括抽象方法
  • Class类:表示正在运行的Java应用程序的类的实例
  • Object类:Object类是所有Java类的父类,所有对象都默认实现了Object类的方法

3、实例化对象的方式有几种 ?

实例化对象的五种方式:

  • 通过new语句创建对象
  • 通过工厂方法返回对象,如String str = String.valueOf(123);
  • 运用反射手段, Class.newInstance()
  • 调用对象的clone()方法
  • 通过I/o流,调用java.io.ObjectInputStream对象的readObject()方法

4、反射机制的优缺点?

优点:

  • 在程序运行过程中可以操作类对象,增加了程序的灵活性
  • 解耦,从而提高程序的可扩展性,提高代码的复用率,方便外部调用
  • 对于任何一个类,当知道它的类名后,就能够知道这个类的所有属性和方法。

缺点:

性能问题:Java反射中包含了一些动态类型,JVM无法对这些动态代码进行优化,因此通过反射来操作的方式比正常操作效率低

安全问题:使用反射时要求必须在一个没有安全限制的环境中运行,如果程序安全限制,就不能使用反射

程序健康性:反射允许代码执行一些平常不被允许的操作,破坏了程序结构的抽象性。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/837676.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号