好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Java的枚举,注解和反射(二)

反射

 

什么是反射?

反射是指在程序运行期间,可以通过Reflection Api提供方法可以获取任何类的内部的信息,并能直接操作任意类的方法和属性。反射被视为动态语言的关键。

//在反射之前可以做的事情 @Test public void Test1 () { //创建Person类的对象 Person person = new Person ( "name" , 78 ); //通过对象调用其内部的方法和属性 person . setAge ( 20 ); System . out . println ( person . toString ()); person . show (); //在Person类的外部,不能通过对象调用其内部的私有的结构 } //在反射之后可以做的事情 @Test public void Test2 () throws Exception { //通过反射创建Person类的对象 Class classPerson = Person . class ; Constructor constructor = classPerson . getConstructor ( String . class , int . class ); Object object = constructor . newInstance ( "Tom" , 13 ); Person person = ( Person ) object ; System . out . println ( person . toString ()); //通过反射获取Person内部的属性和方法 Field name = classPerson . getField ( "name" ); name . set ( person , "Jack" ); System . out . println ( person . toString ()); //调方法 Method show = classPerson . getDeclaredMethod ( "show" ); show . invoke ( person ); //调用私有的构造方法 Constructor constructor1 = classPerson . getDeclaredConstructor ( String . class ); constructor1 . setAccessible ( true ); Person person1 = ( Person ) constructor1 . newInstance ( "Marry" ); System . out . println ( person1 ); //调用私有的方法 Method showNation = classPerson . getDeclaredMethod ( "showNation" , String . class ); showNation . setAccessible ( true ); showNation . invoke ( person1 , "中国" ); }

结果:

未使用反射

使用反射:

Person类

package reflection ; /** * user:ypc; * date:2021-06-20; * time: 13:55; */ public class Person { public String name ; private int age ; public String getName () { return name ; } public void setName ( String name ) { this . name = name ; } public Person () { } public int getAge () { return age ; } public void setAge ( int age ) { this . age = age ; } public Person ( String name , int age ) { this . age = age ; this . name = name ; } private Person ( String name ) { this . name = name ; } @Override public String toString () { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}' ; } public void show () { System . out . println ( "I am a person" ); } private String showNation ( String nation ) { return nation ; }   }

反射的用途

1、在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法 。

2、反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。

Java程序中许多对象在运行时会出现两种类型:运行时类型(RTTI)和编译时类型,例如Person p = new Student();这句代码中p在编译时类型为Person,运行时类型为Student。程序需要在运行时发现对象和类的真实信息。而通过使用反射程序就能判断出该对象和类属于哪些类。

在类被加载完成之后,就会在堆区,产生一个Class对象,这个对象就包含了存这个类的全部的结构信息。我们就可以通过这个对象看到这个类的全部的信息。

这个对象就像一面镜子,通过这个镜子可以看到这个类的全部的信息结构。所以称之为反射。

正常的方式 :通过引入需要导入的包类的名称---->通过new来实例化---->得到实例化的对象

反射的方式 :实例化对象---->通过getClass()方法---->得到完整的包类的名称

反射的具体作用

在运行的时候判断任意的一个对象所属的类 在运行的时候构造任意一个类的对象 在运行 的时候判断任意一个类的成员变量和方法 在运行的时获取泛型的信息 在运行的时候调用任意一个类的成员变量和方法 在运行的时候处理注解 生成动态代理

反射的主要API

类名 用途

Class类 代表类的实体,在运行的Java应用程序中表示类和接口

Field类 代表类的成员变量/类的属性

Method类 代表类的方法

Constructor类 代表类的构造方法

通过直接new 的方式和反射 都可以直接调用公共的结构,在开发的时候应该使用哪一个呢?

建议 :使用new 的方式来创建对象。

什么时候使用反射呢?

反射的特性:动态性。就是在编译的时候不知道要创建什么样的对象的时候,可以使用反射方式来创建对象。比如在后端部署的服务器,前端传来的时登录的请求的话,就创建登录对应的对象。前端传来的是注册所对应的请求的话,就创建登录所对应的对象,这就是反射的动态特性。

反射的机制和封装是不矛盾的呢?

封装是告诉你不要调,反射可以调。

Class类

在Object类中定义了以下的方法,此方法将被所有子类继承:

public final Class getClass ()

以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即可以通过对象反射求出类的名称。

对象使用反射后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个结构( class/interface/enum/annotation/primitive type/void/[])的有关信息。也就是这些类型可以有Class对象:class 成员内部类、 静态内部类、 局部内部类 、 匿名内部类、接口、数组、枚举、注解、基本的数据类型、void等。

注意:

Class本身也是一个类

Class对象只能由系统建立对象

一个加载的类在JVM中只会有一个Class实例

一个Class对象对应的是一个加载到JVM中的一个.class文件

每个类的实例都会记得自己是由哪个Class实例所生成

通过Class可以完整地得到一个类中的所有被加载的结构

Class类是Reflection的根源,针对任何你想动态加载、运行的类,只有先获得相应的Class对象,才能继续下去。

关于java.lang.Class的理解:

类的加载过程:

程序通过javac.exe命令,生成一个或多个字节码文件。接着使用java.exe命令来对某个字节码文件来解释运行。将字节码文件加载到内存中,这个过程称为类的加载。加载到内存中的类,就被称为运行时类,此运行使类就称为Class 的一个实例。

Class 实例就对应着一个运行时类,加载到内存中的运行时类,会缓存一段时间。在此时间之内,可以通过不同的方式来获取运行时类。

获取Class实例的四种方式

// Class 实例就对应着运行时类 @Test public void test3 () throws ClassNotFoundException { //方式1 调用运行时类的属性:.class Class clazz1 = Person . class ; System . out . println ( clazz1 ); //方式2 通过运行时类的对象来调用 Person person = new Person (); Class clazz2 = person . getClass (); System . out . println ( clazz2 );   //方式3 通过Class的静态方法 forName(类的全路径名称) Class clazz3 = Class . forName ( "reflection.Person" ); System . out . println ( clazz3 ); //方式4 通过类加载器:ClassLoader ClassLoader classLoader = ReflectionDemo1 . class . getClassLoader (); Class clazz4 = classLoader . loadClass ( "reflection.Person" ); System . out . println ( clazz4 ); System . out . println ( clazz1 == clazz2 ); System . out . println ( clazz1 == clazz3 ); System . out . println ( clazz1 == clazz4 ); }

通过反射创建运行时类的对象

package reflection ; import org . junit . Test ; import java . util . Random ; /** * user:ypc; * date:2021-06-21; * time: 20:36; */ public class NewInstanceDemo { @Test public void test1 () throws IllegalAccessException , InstantiationException { Class < Person > personClass = Person . class ; /* newInstance()方法可以创建运行时类的实列,其内部也时调用内的无参的构造方法来创建对象 */ Person person = personClass . newInstance (); System . out . println ( person ); } @Test public void test2 () throws IllegalAccessException , InstantiationException , ClassNotFoundException { //在编译的时候不知道要创建的对象。只有运行的时候才知道要创建的对象 for ( int i = 0 ; i < 100 ; i ++) { int num = new Random (). nextInt ( 3 ); String classPath = "" ; switch ( num ) { case 0 : classPath = "java.util.Date" ; break ; case 1 : classPath = "java.lang.Object" ; break ; case 2 : classPath = "reflection.Person" ; break ; } Object object = getInstance ( classPath ); System . out . println ( object ); } } //创建一个指定类的对象 public Object getInstance ( String classPath ) throws ClassNotFoundException , IllegalAccessException , InstantiationException { Class clazz = Class . forName ( classPath ); return clazz . newInstance (); } }

通过反射获取运行类的属性及权限修饰符、变量名 、数据的类型

@Test public void test1 (){ //getFields()获取的是运行时类及其父类中public的属性 Class clazz = Person . class ; Field [] fields = clazz . getFields (); for ( Field field : fields ) { System . out . println ( field ); } System . out . println (); //getDeclaredFields():获取当前运行类的所有属性 Field [] declaredFields = clazz . getDeclaredFields (); for ( Field field : declaredFields ) { System . out . println ( field ); } }

//权限修饰符 变量名 数据的类型 @Test public void test2 (){ Class clazz = Person . class ; Field [] declaredFields = clazz . getDeclaredFields (); for ( Field field : declaredFields ) { //权限修饰符 System . out . println ( Modifier . toString ( field . getModifiers ())+ "\t" );   //变量名 System . out . println ( field . getType ()+ "\t" ); //数据的类型 System . out . println ( field . getName ()+ "\t" ); } }

通过反射获取运行时类的方法结构及其内部结构

package reflection2 ; import org . junit . Test ; import java . lang . annotation . Annotation ; import java . lang . reflect . Method ; import java . lang . reflect . Modifier ; /** * user:ypc; * date:2021-06-22; * time: 13:32; */ public class MethodDemo { @Test public void test1 () { //获取当前运行时类及其父类中所有声明为public的方法 Class clazz = Person . class ; Method [] methods = clazz . getMethods (); for ( Method method : methods ) { System . out . println ( method ); } System . out . println (); //获取当前运行时类所有的方法 Method [] declaredMethods = clazz . getDeclaredMethods (); for ( Method method : declaredMethods ) { System . out . println ( method ); } } //@xxx注解 //权限修饰符 方法结构 返回值的类型 @Test public void test2 () { Class clazz = Person . class ; Method [] declaredMethods = clazz . getDeclaredMethods (); for ( Method method : declaredMethods ) { //获取方法的注解 Annotation [] annotations = method . getDeclaredAnnotations (); for ( Annotation annotation : annotations ) { System . out . print ( annotation ); } //获取权限的修饰符 System . out . print ( Modifier . toString ( method . getModifiers ()) + "\t" ); //获取返回值的类型 System . out . print ( method . getReturnType (). getName () + "\t" ); //方法名 System . out . print ( method . getName ()); System . out . print ( "(" ); //获取形参的列表 Class [] parameterTypes = method . getParameterTypes (); if (!( parameterTypes == null && parameterTypes . length == 0 )) { for ( int i = 0 ; i < parameterTypes . length ; i ++) { if ( i == parameterTypes . length - 1 ) { System . out . print ( parameterTypes [ i ]. getName () + " args__" + i ); } else { System . out . print ( parameterTypes [ i ]. getName () + " args__" + i + "," ); } } } System . out . print ( ")" ); //获取方法的异常 Class [] exceptionTypes = method . getExceptionTypes (); if ( exceptionTypes . length != 0 ) { System . out . print ( "throws" ); for ( int i = 0 ; i < exceptionTypes . length ; i ++) { if ( i == exceptionTypes . length - 1 ) { System . out . print ( exceptionTypes [ i ]. getName ()); } else { System . out . print ( exceptionTypes [ i ]. getName () + "," ); } } } System . out . println (); } } }

test1():

test2():

通过反射获取运行时类的构造结构

@Test public void test1 () { Class clazz = Person . class ; //获取运行时类的public构造方法 Constructor [] constructors = clazz . getConstructors (); for ( Constructor constructor : constructors ) { System . out . println ( constructor ); } System . out . println (); //获取当前运行时类中的所有的构造方法 Constructor [] declaredConstructors = clazz . getDeclaredConstructors (); for ( Constructor declaredConstructor : declaredConstructors ) { System . out . println ( declaredConstructor ); } }

通过反射获取运行时类的父类和父类的泛型、注解、接口、所在包

反射所使用到的包、接口、类、注释等

查看更多关于Java的枚举,注解和反射(二)的详细内容...

  阅读:10次