简单认识Java反射

Java 反射定义

指在 Java 程序运行状态中,动态获取类的内容以及动态调用对象的方法和获取属性的机制.就叫做 JAVA 的反射机制

Java 反射的优缺点

优点:
1.增加程序的灵活性,避免将固有的逻辑程序写死到代码里
2.代码简洁,可读性强,可提高代码的复用率
缺点
1.在量大的情景下反射性能下降,就是慢
2.内部暴露和安全隐患
反射到底慢在哪些地方:
1.寻找类 Class 字节码的过程
2.安全管理机制的权限验证等等
3.调用 native 方法时,会使用JNI技术很消耗性能

反射技术的主要组成

学java的都知道万物皆对象,我们定义的类其实从面向对象的角度来分析,它其实也是一个具体的对象,它是一个描述类的实例.描述这个类中有哪些属性,行为等等内容。
比如,学生是不是都有姓名,年龄,发言权。这些学生共有的属性,行为我们可以抽取成一个公有的Student类来描述。

class Student{
        String name;
        int age;
        void talk(){
            System.out.println("学生可以发言");
        }
    }

Student类就相当于一个模板,我们可以基于这个模板创建具体不同的 Student 实例,而每一个实例都具有姓名,年龄,发言的行为。
那么,对于抽取这个思想,我们可以思考这样一个问题,在Java中是不是每一个类在定义的时候,是不是也可以抽取共性的东西,比如,每一个类都有包名,类名,属性定义,行为(方法),构造器等等。
所以说,我们能想到的东西,那James Gosling肯定比咱们想的周到,这个类定义的创建模板就是我们 java 语言中的 java.lang.Class 类。
深入Class 内部
在这里插入图片描述
通过上面的内容,我们已经了解到我们创建的每一个自定义的Class实例(也就是我们创建的每一个类)都是基于他的模板类 java.lang.Class
类。在大家每一个编写的类实例中,都会定义这个类的包名,类名,访问域,特征符,构造器,字段,函 数,父类,接口等等内容。这些内容在我们的 Class 类中都提供了对应的获取方法进行获取(既然是属性,肯定有对应的get方法是吧)。

注意:以下所有clazz 代表对应的 Class 类实例

简单说一下Class类实例的四种获取方式:
1.Class clazz = Student.class;
2.Class clazz = new Student().getClass();
3.Class clazz = Class.forName(“com.czy.demo.Student”);(会有ClassNotFoundException异常,需要捕获)
4.Class clazz = Main(当前类名).class.getClassLoader().loadClass(“com.czy.demo.Student”);(ClassNotFoundException异常,需要捕获)

反射-基本信息操作

int modifier = clazz.getModifiers(); //获取类的修饰符

注意:该返回的是int类型而不是字符串‘public’,‘private’ 等修饰符。
官方api中给出,修饰符所对应的数字:在这里插入图片描述
若类的定义为,public abstract Class ClassXXX{ } int modify = clazz.getModifers(); 返回值为 public 值+ abstract 的值 = 1025

Package package= clazz.getPackage(); //获取类的包名
String fullClassName = clazz.getName(); //获取类的全路径名称
String simpleClassName = clazz.getSimpleName(); //获取类的简单名称
ClassLoader classLoader = clazz.getClassLoader(); //获取类的类加载器
Class[] interfacesClasses = clazz.getInterfaces(); //获取类实现的接口列表
Class fc= clazz.getSuperclass(); //获取类的父类
Annotation[] annotations= clazz.getAnnotations(); //获取类的注解列表

反射-类的属性操作

Field[] fields = clazz.getFields(); 获取类中所有的公有字段 包含继承
Field field=clazz.getField(“xxx”); 获取类中拥有的具体属性名的公有属性 (含继承,实现)
Field[] fields=clazz.getDeclaredFields(); 获取当前类定义的所有属性(公有,私有)
Field field=clazz.getDeclaredField(“xxx”); 获取当前类定义的具体属性名的属性(公 有,私有)
Field 对象操作
int modifers =filed.getModifers() 获取变量的修饰(参见类的修饰)
field.get(object) 获取 object 对象的具体属性值
field.set(object,objectValue) 给指定的对象的属性赋值
field.set(null,objectValue) 给静态变量赋值 objectValue(static 修饰)(指定对象可为任意对象,约定规范为null)
如果属性是私有的private 修饰 ,需在set方法或者 setXXX 调用前,设置可访问权限filed.setAccessable(true);也就是强制访问私有的属性

反射-类的方法操作

Method[] methods = clazz.getDeclaredMethods(); //获取当前类中定义的全部方法(公有,私有)
Method pugMethod = clazz.getDeclaredMethod("methodName",String.calss) //获取类中定义指定名称和参数类型的方法
Method[] methods = clazz.getMethods(); //获取类中拥有的公有方法(含继承,实现)
Method method = clazz.getMethod(“xxx”); //获取类中拥有的指定名公有方法(含继承,实现)
method对象操作
int modifers = method.getModifers(); //获取方法的修饰符
Class cls = method.getReturnType(); //获取方法的返回值类型
String methodName = m.getName(); //获取方法的名字
Class[] clazzes = m.getParameterTypes(); //获取方法参数列表的类型
Class[] clazzes =m.getExceptionTypes(); //获取方法抛出的异常类型
Object obj=method.invoke(obj,args); //在指定的对象上执行方法
Object obj=method.invoke(null,args); //执行类的静态方法
若方法是私有方法,权限不允许操作,可以执行 method.setAccessable(true)来强制使用,设置方法使用权之后,在执行 invoke

反射-类的构造器操作

Constructor[] cons = clazz.getConstructors(); //获取类中所有的公有构造器
Constructor[] cons = clazz.getDeclaredConstructors(); //获取类中所有的构造器
Constructor conNoParam= clazz.getDeclaredConstructor(); //获取类中无参的构造器
Constructor con= clazz.getDeclaredConstructor(String.class,String.class); //获取类中有参构造
constructor 对象操作
int modifers = con.getModifiers(); //获取构造器的修饰符
con.newInstance(); //无参构造器实例对象
con.newInstance('xxx','xxx'); //有参构造器实例对象
con.setAccessible(true); //指定构造器强制访问

class.newInstacne(); //class直接调用newInstacne(),底层还是用con.newInstance()默认调用无参的构造函数

加粗样式

单例模式也许并不单例

单例模式的特征:
1.私有化构造函数
2.全局唯一的公有访问点
这里我们就已懒汉式单例模式代码为例:

public class Lazy {
    private static Lazy instance;
    private Lazy(){}
    public static Lazy getInstance(){
        if (instance == null){
            synchronized (Lazy.class){
                if (instance == null) {
                    instance = new Lazy();
                }
            }
        }
        return instance;
    }
}

反射如何破坏单例:

public class SingletonDestroyer {
    public static void main(String[] args) throws Exception {
        Lazy lazy = Lazy.getInstance();//这是Lazy对外提供的获取方式
        Constructor constructor = Lazy.class.getDeclaredConstructor();
         //因为Lazy的构造函数私有了,所以这里要设置强制访问
        constructor.setAccessible(true);
        Lazy lazyInstanceReflect = (Lazy) constructor.newInstance();//这是反射机制用构造器获取的Lazy
        System.out.println(lazy  == lazyInstanceReflect);//--> false
    }
}

输出结果为false。可以试一下,所以说反射是能破坏单例的,单例模式也许并不单例。

要说把Java反射机制发挥的淋漓尽致的那肯定非SpringIoc莫属。
下一篇:简单学习下springIoc是用反射机制如何实现的思路

发布了17 篇原创文章 · 获赞 29 · 访问量 6491

猜你喜欢

转载自blog.csdn.net/weixin_45240169/article/details/104183377
今日推荐