码迷,mamicode.com
首页 > 编程语言 > 详细

java基础-反射(细节)

时间:2020-08-04 09:48:54      阅读:55      评论:0      收藏:0      [点我收藏+]

标签:完整   ext   min   特性   文件   def   java语言   大型   使用   

java面试题--java反射机制?


Java反射机制的作用:
1)在运行时判断任意一个对象所属的类。
2)在运行时判断任意一个类所具有的成员变量和方法。
3)在运行时任意调用一个对象的方法
4)在运行时构造任意一个类的对象
拓展:
1、什么是反射机制?
简单说,反射机制值得是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。

2、java反射机制提供了什么功能?
在运行时能够判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任一对象的方法
在运行时创建新类对象

3、哪里用到反射机制?
jdbc中有一行代码:Class.forName(‘com.mysql.jdbc.Driver.class‘).newInstance();那个时候只知道生成驱动对象实例,后来才知道,这就是反射,现在
很多框架都用到反射机制,安卓的EventBus框架,hibernate,struts都是用反射机制实现的。

4、反射机制的优缺点?
静态编译:在编译时确定类型,绑定对象,即通过
动态编译:运行时确定类型,绑定对象。动态编译最大限度的发挥了java的灵活性,体现了多态的应用,有利于降低类之间的耦合性。

一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中
它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编
译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如
这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能
的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功
能。
--缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它
满足我们的要求。这类操作总是慢于只直接执行相同的操作。

反射原理:
编译时,Java类都会被编译成一个.class 文件,这些 Class 对象承载了这个类型的父类、接口、构造函数、方法、属性等原始信息,这些 class 文件在程序运行时会被ClassLoader加载到虚拟机中,程序在运行时,当一个类被加载以后,Java虚拟机就会在内存中自动产生一个Class对象。
Java中一切都是对象,其中所有类型包括基本类型,数组,都有对应的 Class类的对象。java中可以通过类名里来获取该类的class对象。
有个这个class对象,就可以做很多操作了。

========
关于反射:
反射是可以在运行时获取类的函数、属性、父类、接口等 Class 内部信息的机制。通过反射还可以在运行期实例化对象,调用方法,通过调用 get/set 方法获取变量的值,(包括私有的方法也可以)。这种机制在框架源码中很常见。
一个比较常见的场景就是编译时对于类的内部信息不可知,必须得到运行时才能获取类的具体信息。
比如ORM 框架,在运行时才能够获取类中的各个属性,然后通过反射的形式获取其属性名和值,存入数据库。


java中提供的API:
1 获取Class对象:
// 加载指定的 Class 对象,参数 1 为要加载的类的完整路径 :包名+类名 ( 常用方式 )
public static Class<?> forName (String className)
// 加载指定的 Class 对象,参数 1 为要加载的类的完整路径;
// 参数 2
为是否要初始化该 Class 对象
,参数 3
为指定加载该类的 ClassLoader
.
public static Class<?> forName (String className, boolean shouldInitialize, ClassLoader classLoader)
注意:在调用 Class.forName()方法时,没有在编译路径下(classpath)找到对应的类,那么将会抛出 ClassNotFoundException。

2 通过反射构造对象,首先要获取类的 Constructor(构造器)对象,然后通过 Constructor 来创建目标类的对象。
Constructor<?> constructor = clz.getConstructor(String.class);
// 设置 Constructor 的 Accessible

constructor.setAccessible(true);
注意:通过反射获取到 Constructor、Method、Field 后,在反射调用之前将此对象的 accessible 标志设置为 true,以此来提升反射速度。
值为 true 则指示反射的对象在使用时应该取消Java语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。

3 反射获取类中函数
// 获取 Class 对象中指定函数名和参数的函数,参数一为函数名,参数 2 为参数类型列表
public Method getDeclaredMethod (String name, Class...<?> parameterTypes)
// 获取该 Class 对象中的所有函数( 不包含从父类继承的函数 )
public Method[] getDeclaredMethods ()
// 获取指定的 Class 对象中的**公有**函数,参数一为函数名,参数 2 为参数类型列表
public Method getMethod (String name, Class...<?> parameterTypes)
// 获取该 Class 对象中的所有**公有**函数 ( 包含从父类和接口类集成下来的函数 )
public Method[] getMethods ()
注意: getDeclaredMethod 和 getDeclaredMethods 包含 private、protected、default、public 的函数,并且通过这两个函数获取到的只是在自身中定义的函数,从父类中集成的函数不能够获取到。而 getMethod 和 getMethods 只包含 public 函数,父类中的公有函数也能够获取到。

4 反射获取类中的属性

public Method getDeclaredField (String name) // 获取 Class 对象中指定属性名的属性,参数一为属性名
public Method[] getDeclaredFields ()// 获取该 Class 对象中的所有属性( 不包含从父类继承的属性 )
public Method getField (String name)// 获取指定的 Class 对象中的**公有**属性,参数一为属性名
public Method[] getFields ()// 获取该 Class 对象中的所有**公有**属性 ( 包含从父类和接口类集成下来的公有属性 )
5 反射获取指定类型的注解
// 获取指定类型的注解
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) ;
// 获取 Class 对象中的所有注解
public Annotation[] getAnnotations() ;

=========

1 反射机制的基本概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

2 反射是如何实现的

1.简单介绍Class
——java基于此基础,才能够实现反射。
Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。
虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。
也就是说,ClassLoader找到了需要调用的类时(java为了调控内存的调用消耗,类的加载都在需要时再进行,很抠但是很有效),就会加载它,然后根据.class文件内记载的类信息来产生一个与该类相联系的独一无二的Class对象。该Class对象记载了该类的字段,方法等等信息。以后jvm要产生该类的实例,就是根据内存中存在的该Class类所记载的信息(Class对象应该和我所了解的其他类一样会在堆内存内产生、消亡)来进行。
而java中的Class类对象是可以人工自然性的(也就是说开放的)得到的(虽然你无法像其他类一样运用构造器来得到它的实例,因为Class对象都是jvm产生的。不过话说回来,客户产生的话也是无意义的),而且,更伟大的是,基于这个基础,java实现了反射机制。
我的理解:在JVM中,根据.class文件加载后,产生了独一无二的Class对象(这个是由JVM创建的,根据
图中所示,Class内部的私有构造器),而后如果还要产生该类的实例,就根据刚才生成的Class对象,通过newInstance得到,但是不能利用构造器得到实例了。

2.如何做到反射?
反射其实就是一个文本扫描器,扫描.class文件。

3.Reflection动态相关机制
3.1动态语言
Reflection是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过ReflectionAPIs取得任何一个已知名称的class的内部信息。
包括其modifiers(诸如public、static等)、superclass(例如Object)、实现了的 interfaces (例如Serializable)、也包括其fields和methods的所有信息,并可于运行时改变fields内容或调用methods。
换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。

这种“看透”class的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。


3.2Java反射机制提供的功能

1.在运行时判断任意一个对象所属的类。
2.在运行时构造任意一个类的对象。
3.在运行时判断任意一个类所具有的成员变量和方法。
4.在运行时调用任意一个对象的方法。


3.3Java Reflection API 简介和使用
在JDK中,主要由以下类来实现Java反射机制,这些类(除了第一个)都位于java.lang.reflect包中:
Class类:代表一个类,位于java.lang包下。
Field类:代表类的成员变量(成员变量也称为类的属性)。
Method类:代表类的方法。
Constructor类:代表类的构造方法。
Array类:提供了动态创建数组,以及访问数组的元素的静态方法。

3.3.1Class对象

要想使用反射,首先需要获得待操作的类所对应的Class对象。
Java中,无论生成某个类的多少个对象,这些对象都会对应于同一个Class对象。
这个Class对象是由JVM生成的,通过它能够获悉整个类的结构。

获取Class对象的3种方式(以User类为例):
使用Class类的静态方法,如:
Class<?> clazz = Class.forName("com.bobo.User");
2.使用类的.class语法,如
Class clazz = User.class;
3.使用对象的getClass()方法,如
User user =new User();
Class<?> clazz =user.getClass();
注:getClass()方法定义在Object类中,不是静态方法,需要通过对象来调用,并且它声明为final,表明不能被子类所覆写。

3.3.2生成对象
若想通过类的不带参数的构造方法来生成对象,我们有两种方式:
1.先获得Class对象,然后通过该Class对象的newInstance()方法直接生成即可:
Class<?> classType = User.class;
Object obj = classType.newInstance();

2.先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成 (其中User是一个自定义的类,有一个无参数的构造方法,也有带参数的构造方法):

Class<?> classType = User.class;

// 获得Constructor对象,此处获取第一个无参数的构造方法的
Constructor cons = classType.getConstructor(new Class[] {});
// 通过构造方法来生成一个对象
Object obj = cons.newInstance(new Object[] {});


若想通过类的带参数的构造方法生成对象,只能使用下面这一种方式:
(User为一个自定义的类,有无参数的构造方法,也有一个带参数的构造方法,传入字符串和整型)
Class<?> classType = User.class;
Constructor cons2 = classType.getConstructor(new Class[] {String.class, int.class});
Object obj2 = cons2.newInstance(new Object[] {"ZhangSan",20});


小结: 可以看出调用构造方法生成对象的方法和调用一般方法的类似,不同的是从Class对象获取Constructor对象时不需要指定名字,而获取Method对象时需要指定名字。

3.3.3获取类的构造器
首先介绍一下Constructor类,这个类用来封装反射得到的构造器,Class有四个方法来获得Constructor对象
public Constructor<?>[] getConstructors() 返回类中所有的public构造器集合,默认构造器的下标为0
public Constructor<T> getConstructor(Class<?>... parameterTypes) 返回指定public构造器,参数为构造器参数类型集合
public Constructor<?>[] getDeclaredConstructors() 返回类中所有的构造器,包括私有
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回任意指定的构造器
从名字来看,还是很好懂的,带上Declared的都是获得所有的构造方法,包括私有,哈,这下我们就可以调用原本不允许调用的私有构造器了,看代码。

例:
//指定参数列表获取特定的方法
Constructor con = cls1.getDeclaredConstructor(new Class[]{String.class});
con.setAccessible(true); //设置可访问的权限
Object obj = con.newInstance(new Object[]{"liyang"});
System.out.println(obj); //打印一下这个对象的信息

//获取所有的构造方法集合
Constructor con1[] = cls1.getDeclaredConstructors();
con1[1].setAccessible(true);
Object obj1 = con1[1].newInstance(new Object[]{"tom"});
System.out.println(obj1);

3.3.4获取类的成员变量
了解了构造器,其实你可以猜到成员变量的获取方法了,成员变量用Field类进行封装。
主要的方法非常的类似:
public Field getDeclaredField(String name) 获取任意指定名字的成员
public Field[] getDeclaredFields() 获取所有的成员变量
public Field getField(String name) 获取任意public成员变量
public Field[] getFields() 获取所有的public成员变量
例:
Field mem = cls1.getDeclaredField("name");
mem.setAccessible(true); // 设置可访问的权限
System.out.println("we get form field :"+mem.get(obj));

3.3.5获取类的方法
封装类的方法的类是Method.获取method也有四个方法:
public Method[] getMethods() 获取所有的共有方法的集合
public Method getMethod(String name,Class<?>... parameterTypes) 获取指定公有方法 参数1:方法名 参数2:参数类型集合
public Method[] getDeclaredMethods() 获取所有的方法
public Method getDeclaredMethod(String name,Class<?>... parameterTypes) 获取任意指定方法
例:
Method f = clazz.getMethod("getName", null);
Object name = f.invoke(obj, null);
System.out.println("we invoke method : "+ name);
这个很简单吧,无参的时候我们只要传null就行了。

4反射的实际应用

配置文件:
通过配置文件就可以让我们获得指定的方法和变量,在我们创建对象的时候都是通过传进string实现的,就好像你需要什么,我们去为你生产,还有我们一直在用Object,这就说明java语言的动态特性,依赖性大大的降低了。
AOP,Struts就是应用了这个。

5反射的优缺点
5.1优点
反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。

5.2缺点
对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

 -----

 

 推荐 太湖在哪?

java基础-反射(细节)

标签:完整   ext   min   特性   文件   def   java语言   大型   使用   

原文地址:https://www.cnblogs.com/1994jinnan/p/13430873.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!