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

Java基础—— 反射

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

Java基础—— 反射

【引入】

动态语言
        是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构
主要动态语言: Object--c、c JavaScript PHP、 Python等
静态语言
        与动态语言相对应的,运行时结构不可变的语言就是静态语言。如ava、C、C++。
虽然 java不是动态语言,但Java可以称之为“准动态语言”即java有一定的动态性我们可以利用反射机制获得类似动态语言的特性。java的动态性让编程的时候更加灵活!

一、反射概述

反射(Reflect)是Java被视为动态语言的关键,反射机制允许程序在执行期间,通过Reflect ApI取得任何类的内部信息,同时直接操作对象的内部属性以及方法。

 获取Class对象的三种方式:

  1. Class.forName("全类名"):将字节码加载进内存,返回class对象。
  2. 类名.class :通过类型属性class获取。
  3. 对象.getClass(): 通过方法调用获取。
public class Reflect1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //1、forName() ------> source(源代码阶段)
        Class person1 = Class.forName("com.reflect.model.Person");
        System.out.println(person1);
        //2、.Class文件 ------> class (字节码阶段)
        Class person2 = Person.class;
        System.out.println(person2);
        //3、getClass  ------> runtime(运行时阶段)
        Person person3=new Person();
        Class person3Class = person3.getClass();
        System.out.println(person3Class);
        System.out.println("=============================");
        System.out.println(person1==person2);
        System.out.println(person2==person3Class);
    }
}
二、Class对象的主要功能概述

1、获取成员变量

Field[] getFields()返回一个包含Field对象的数组,反映由这个class对象表示的类或接口的所有可访问的公共字段。
Field getField(String name)返回一个Field对象,该对象反映由这个class对象表示的类或接口的指定公共成员字段。name参数是一个String,指定所需字段的简单名称。
Field[] getDeclaredFields()返回一个Field对象数组,反映由这个class对象表示的类或接口声明的所有字段。这包括公共、受保护、默认(包)访问和私有字段,但不包括继承字段。
Field getDeclaredField返回一个Field对象,该对象反映由这个class对象表示的类或接口的指定声明字段。name参数是一个String,它指定所需字段的简单名称。
public class Reflect2_1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        Class cls = Class.forName("com.reflect.model.Person");
        //1、变量
        System.out.println("================1、变量===============");
        Field msg = cls.getField("msg");
        Person person=new Person();
        System.out.println(msg.get(person));
        msg.set(person,"hello");
        System.out.println(msg.get(person));

        Field age = cls.getDeclaredField("age");
        age.setAccessible(true);
        System.out.println(age.get(person));
        age.set(person,12);
        System.out.println(age.get(person));
    }
}

2、获取成员方法

Method getMethod(String name, Class... parameterTypes)返回一个Method对象,该对象反映由这个class对象表示的类或接口的指定公共成员方法。name参数是一个String,用于指定所需方法的简单名称。parameterTypes参数是一个Class对象数组,按声明的顺序标识方法的形式参数类型。如果parameterTypes为空,则将其视为空数组。
Method[] getMethods()返回一个包含Method对象的数组,该数组反映由这个class对象表示的类或接口的所有公共方法,包括由类或接口声明的方法和从超类和超接口继承的方法。
Method[] getDeclaredMethods()返回一个包含Method对象的数组,该数组反映由这个class对象表示的类或接口的所有声明方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
Method getDeclaredMethod(String name, Class... parameterTypes)返回一个Method对象,该对象反映由这个class对象表示的类或接口的指定声明方法。name参数是一个String,用于指定所需方法的简单名称,parameterTypes参数是一个Class对象数组,按声明的顺序标识方法的形式参数类型。
public class Reflect2_2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        Class cls = Class.forName("com.reflect.model.Person");
        //2、方法
        System.out.println("=================2、方法==============");
        Method setAge = cls.getMethod("setAge", int.class);
        System.out.println(person.toString());
        setAge.invoke(person, 23);
        System.out.println(person.toString());
    }
}

3、获取构造方法

Constructor[] getConstructors()返回一个包含构造函数对象的数组,该对象反映由这个class对象表示的类的所有公共构造函数。如果类没有公共构造函数,或者类是数组类,或者类反映了原始类型或void,则返回长度为O的数组。
Constructor getConstructor(Class... parameterTypes)返回一个构造函数对象,该对象反映由这个class对象表示的类的指定公共构造函数。parameterTypes形参是一个Class对象数组,按声明的顺序标识构造函数的形式形参类型。如果此Class对象表示在非静态上下文中声明的内部类,则形式形参类型包括显式的封闭实例作为第一个形参。
public class Reflect2_3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        Class cls = Class.forName("com.reflect.model.Person");
        //3、构造器
        System.out.println("================3、构造器=============");
        Person person2 = (Person) cls.newInstance();
        System.out.println(person2.toString());
        Constructor constructor = cls.getConstructor();
        Person person3 = (Person) constructor.newInstance();
        System.out.println(person3.toString());
    }
}
三、反射应用实例

【需求】不改变代码,可以创建任意对象,运行任一方法

src目录下创建 info.properties文件

读取配置文件,获取对象,执行方法

public class Reflect3 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //1、获取配置信息
        Properties pro=new Properties();
        ClassLoader classLoader = Reflect3.class.getClassLoader();
        InputStream input = classLoader.getResourceAsStream("info.properties");
        pro.load(input);
        //2、获取配置文件数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
        //3、将该类加载进入内存
        Class cls= Class.forName(className);
        //4、通过反射执行方法
        Cat cat= (Cat) cls.newInstance();
        Method method = cls.getMethod(methodName,String.class);
        method.invoke(cat,"你好!");
    }
}
 四、反射的应用场景

1、在运行时分析代码

        Field类有一个getType方法,用来返回描述字段类型的一个对象,这个对象的类型同样是Class Method 和Constructor类有报告参数类型的方法,Method类还有一个报告返回类型的方法这三个类都有一个名为 getModifiers方法,它将返回一个整数,用不同的0/1位描述所使用的修饰符,如 public和 static另外,还可以利用javalang. reflect包中 Modifier类的静态方法分析 getModifiers返回的这个整数。例如,可以使用 Nodifier类中的 isPublic、 isPrivate或isFinal判断方法或构造器是 public、 private还是 final我们需要做的就是在 getModifiers回的整数上调用 Modifier类中适当的方法,另外,还可以利用 Modifier. toString方法将修饰符打印出来。

2、运行时检查对象

如利用Field[] getDeclaredFields() 方法,获取全部子段,编写一个通用的toString方法( )。

3、实现泛型数组操作代码

Class getComponentType() :返回表示数组组件类型的Class。如果这个类不表示数组类,这个方法返回null。

五、反射破坏单例模式 

        由于反射的特殊性,导致很多时候,需要单例模式的场景下,反射直接回破坏单例模式。如通过getConstructors( ) 获取构造器,利用构造器方法newInstance()直接创建对象,单例模式由此失效。但是有一种对象,天生就是单例模式——枚举

public enum SingleEnum {
    INSTANCE;

    private static SingleEnum singleEnum=null;

    private SingleEnum(){
    }

    static class User{

        private static User user=null;

        private User(){

        }

        public static User getInstance() {
            if(user!=null){
                user=new User();
            }
            return user;
        }
    }

    public SingleEnum getInstance() {
        return INSTANCE;
    }
}

class Newtest{
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Constructor userConstructor = SingleEnum.class.getDeclaredConstructor(String.class,int.class);
        userConstructor.setAccessible(true);
        SingleEnum u1 = userConstructor.newInstance();
        System.out.println(u1);
    }
}

【运行结果】

 无法通过反射创建对象。

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

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

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