java反射 setAccess,简单认识Java反射-Go语言中文社区

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 内部

330837e9cf0ae0a39c2fd958c90c842f.png

通过上面的内容,我们已经了解到我们创建的每一个自定义的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中给出,修饰符所对应的数字:

b624e92dca56deadf41dc29a4b3536dc.png

若类的定义为,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()默认调用无参的构造函数

32539a1d18651cca05ab1d94bbcce239.png

单例模式也许并不单例

单例模式的特征:

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是用反射机制如何实现的思路

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值