写点什么

Java 反射的深入浅出,mongodb 优化面试

用户头像
极客good
关注
发布于: 刚刚

个人理解:反射是一种很牛 x 的技术,使用反射的条件是程序猿是一个大猿,对 java 的特性非常理解。反射的牛逼之处在于他可以完成一些非常规操作。


举个栗子来说明一下:


稍微想了一下,觉得用煮饭这个栗子来说明吧,不知道准不准确(^,^)。平时我们在家里一般是用电饭煲来煮饭的,煮饭的步骤一般是:淘米——>擦干锅底——>把锅放到电饭煲里——>合上盖子,通电,电饭煲工作——>饭煮熟了,可以吃了,但现在有个需求,我要在煮饭的过程中加个鸡蛋,这时怎么解决呢?是不是打开正在通电煮饭的电饭煲,然后把鸡蛋放进去呢?(来自吃货的需求^_^)其实反射就相当于刚才加鸡蛋的过程。所以反射很牛逼,他不按常规套路出牌,在程序运行的过程中搞一些小动作,以达到“吃货”的目的。补充一下:“淘米——>擦干锅底——>把锅放到电饭煲里——>”这个过程可以看做编码编译过程,“——>合上盖子,通电,电饭煲工作”可以看做是程序运行过程,“——>饭煮熟了,可以吃了”可以看做程序运行结束。



2.java 中的反射机制


============


2.1 反射中常见的类




理解反射机制时,首先熟悉一下几个类:


1)Class 类


Class 类实例表示正在运行的 Java 应用程序中的类和接口。Class 是普通类、接口、枚举类、数组等的抽象,即它们的类型就是 Class,它们是 Class 的实例。


既然 Class 代表着类和接口,那么我们可以通过他的实例(字节码文件)来获取对应类或接口的信息,如:注解、修饰符、类型、类的名称、属性、方法、构造方法、直接父类和子类等,还有可以创建它的实例,但只能调用无参构造方法来创建。


什么看不懂?举个栗子,我们都知道,生物可以分为动物、植物、微生物和病毒等,而动物又有人、喵星人、小狗等,植物、微生物和病毒也一样。同样,我们可以类比一下,生物就是 Class,动物是普通类,植物是接口,微生物是枚举类、病毒是数组(枚举和数组是特殊的类),而人、喵星人、小狗是我们熟悉的对象,如图



这下可整明白了吧,普通类、接口、枚举、数组其实都可以当做 Class 的对象。


2)Field 类


Field 表示类的属性,属性含有修饰符、类型、属性名称和值。所以可以通过 Field 的实例获取属性的修饰符、类型、属性名称,并且可以修改属性的值。


3)Method 类


Method 表示类的成员方法,方法包括注解、修饰符、返回类型、方法名,参数等。所以可以通过 Method 的实例获取方法的的信息,如,注解、修饰符、返回类型、方法名并且可以调用所表示的方法。


4)Constructor 类


Constructor 表示构造方法,可以通过 Constructor 的实例获取构造方法的信息,如,修饰符等,并且可以通过它来创建它所在类的的实例。


5)Modifier 类


Modifier 表示修饰符,可通过它来获取修饰符的信息,例如何种修饰符等


6)Annotation


Annotation 代表注解


以上类都位于 java.lang 中


2.2 获取 Class 对象的方法




了解了什么是反射后,是不是也想体验一下反射这种骚操作?


想秀操作,首先要获取 Class 对象吧,因为 Class 对象是代表着各种类,有了它之后才可以得到类的各种信息。获取方法如下:


1)通过 object.getClass()


public static void main(String[] args) {


Car car = new Car();


Class clazz = car.getClass


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


();


}


注意:此方法不适用于 int、float 等类型


2)通过(类型名).class、包装类.Type


public static void main(String[] args) {


Class clazz = Car.class;


Class cls1 = int.class;


Class cls2 = String.class;


Class cls3=Iteger.Type


}


3)通过 Class.forClass(String 类的全限定名)


1 try {


2 Class clz = Class.forName("com.frank.test.Car");


3 } catch (ClassNotFoundException e) {


4 e.printStackTrace();


5 }


采 用哪种方法来获取,看实际情况而定。


2.3 获取类信息




有了 Class 对象后,就可以获取类的成员(方法+属性)、注解和类的修饰符等。上面也说了,java 中方法用 Method 类表示、属性用 Field 类表示、注解用 Annotation 类来表示、修饰符用 Modifier 类表示。Class 类中有对应的方法来获取他们。如下:

2.3.1 获取属性 Field 的对象

1 //获取所有的属性,但不包括从父类继承下来的属性


2 public Field[] getDeclaredFields() throws SecurityException


3 //获取自身的所有的 public 属性,包括从父类继承下来的。


4 public Field[] getFields() throws SecurityException


5 //获取在本类中声明的指定的属性,参数为属性的名称


6 public Field getDeclaredField(String name)


7 //获取指定的公有属性,包括父类的,参数为属性的名称


8 public Field getField(String name)

2.3.2 获取方法 Method 对象

//获取本类声明指定的的方法,第一个参数是方法的名称,后面的参数是方法参数类型的类,


//如获取 setName(String name)方法,getDeclareMethod(“setName”,String.Class)


public Method getDeclaredMethod(String name, Class<?>... parameterTypes)


//获取公有的方法,包括父类的


public Method getMethod(String name, Class<?>... parameterTypes)


//获取本类中声明的所有方法


public Method[] getDeclaredMethods()


//获取所有的公有方法,包括父类的


public Method[] getMethods()

2.3.3?获取构造器 Constructor 对象

//获取本类中指定的构造方法


public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)


//获取指定的公有构造方法


public Constructor<T> getConstructor(Class<?>... parameterTypes)


//获取本类中所有的构造方法


public Constructor<?>[] getDeclaredConstructors() throws SecurityException


//获取本类中所有的公有构造方法


public Constructor<?>[] getConstructors()


构造方法的获取与普通方法的获取大致是一样的。

------------------------------------------------------------------

以上的方法都是在 Class 类中,别傻傻不知道(别问我怎么知道的>_>),然后通过 Class 对象调用就可以了。


这里只是列举了常用类信息的的获取方法,其他信息的获取方法,看 API 文档吧,如注解、类的 Class 的对象(额好像有点绕。。。)等.


2.4 获取类成员信息




上面只是获取了类的成员所代表类的对象,我们还要使用他们或者获取成员的信息(名称、修饰符等)。因为有了代表成员的对象,使用对象调用实例方法就可以了。

2.4.1 Field 类

Field 类的方法大概可以分为两种,一种是获取属性的信息,另外一种是设置属性的值。


第一种:


1 //返回由此 Field 对象表示的字段的名称


2 String getName()


3 //返回一个 类对象标识了此表示的字段的声明类型 Field 对象。


4 Class<?> getType()


5 //返回由该 Field 对象表示的字段的 Java 语言修饰符,作为整数。把整数作为 Modifier 的构造方法的参数,就可以获取该整数代表的修饰符类的对象了


6 int getModifiers()


7 ----------------------------------------------------------------


8


9 //获取类型为 int 的静态或实例字段的值,或通过扩展转换转换为类型 int 的另一个原始类型的值。


10 int getInt(Object obj)


11 //获取类型为 long 的静态或实例字段的值,或通过扩大转换获得可转换为类型 long 的另一个基本类型的值。


12 long getLong(Object obj)


13 ......此处省略一堆 get**(Object obj)的方法,属性是什么基本类型,就 get 什么就行了


14 属性是引用类型,那么就调用以下方法


15 //返回该所表示的字段的 Field ,指定的对象上。 16 Object get(Object obj)


第二种:


1 //设置作为一个字段的值 double 指定的对象上。


2 void setDouble(Object obj, double d)


3 //设置作为一个字段的值 float 指定的对象上。


4 void setFloat(Object obj, float f)


5 //设置作为一个字段的值 int 指定的对象上。


6 void setInt(Object obj, int i)


7 ........此处省略一堆 set**()方法,属性是什么基本类型就 set 什么就行了


8 属性是引用类型,那么就调用以下方法


9 //将指定对象参数上的此 Field 对象表示的字段设置为指定的新值。


10 void set(Object obj, Object value)


注意啦:如果没有访问权限的话,默认是不能设置属性值的,那怎么办呢?是不是就秀不了操作了?然而,前面也说了,反射很牛逼,可以来一些非常规操作,

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Java反射的深入浅出,mongodb优化面试