龙空技术网

反射的深入理解

重庆源码时代 108

前言:

而今看官们对“反射机制有什么用”都比较关怀,朋友们都需要了解一些“反射机制有什么用”的相关知识。那么小编在网摘上汇集了一些关于“反射机制有什么用””的相关知识,希望大家能喜欢,各位老铁们一起来学习一下吧!

2.1. 什么是反射

1. 建立知识共识

1) 要让Java程序能够运行,那么就得让Java类要被Java虚拟机加载;

2) Java类如果不被Java虚拟机加载,是不能正常运行的;

3) 我们运行的所有的程序都是在编译期的时候就已经知道了你所需要的那个类已经被加载了;

2. 相对官方解释

1) 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力;

2) 在运行时期,动态地去获取类中的信息(类的信息,方法信息,构造器信息,字段等信息);

3. 前面所学知识涉及到反射的地方

1) 获得运行时类型 Object的getClass方法

class A{}class B extends A{}A a = new B();

在编译的时候想得到a的运行时类型

a.getClass();

2) 线程同步监听对象之类的字节码对象例如 String.class

3) 获得默认无参构造方法

class A{}

4) 单例模式

5) Eclipse的OutLine功能

6) 面向对象的思想看待反射

4. 反射的作用

1) 增加程序的灵活性,避免将程序写死到代码里(解除硬编码的问题);

2) Java的反射机制它知道类的基本结构,可以动态的去获取类这样的结构的结构;

3) 可以让程序员在不知道其它程序员会有什么类的时候就编写完成自己的代码;

4) 反射的优点:灵活,功能强大(可以拿到私有的....);

5) 反射的缺点:破坏封装,影响性能;

1.1. 反射常用API

1. java.lang.Class

2. java.lang.reflect.Constructor

3. java.lang.reflect.Method

4. java.lang.reflect.Field

5. ...

6. 注意: lang包下面的直接类型是自动导入的,但是lang包的子包中的类型需要我们自己导入的,到时候不要忘记了哦!

学习下面的知识之前定几个目标

1. 验证一个类中有默认无参数构造方法

2. 获得任意一个类(或者接口)例如String 内部有哪些成员(字段,方法,构造方法。。。)

3. 想办法去创建单例模式的类的多个对象

4. 验证元注解@Inherited,加强对@Inherited的理解。

1.2. Class类与实例2.1.1. 3.4.1 Class类

简单说Class 类就是一个类而已,呵呵。。。

2.1.2. 3.4.2 Class实例

1.其实就是一些类型的字节码对象

2.Class 类的实例表示正在运行的 Java 应用程序中的类和接口;

3.枚举是一种类,注释(指的是注解Annotation)是一种接口;

4.每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象;

5.基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象;

注意

1、Class类 和它的实例的产生: Class的实例是已经存在的类型,所以不能够直接new一个Class对象出来,而通过已知的类型和Class来获得

2、同一种类型不管通过什么方式得到Class的实例都是相等的;一个类型的字节码对象只有一份!

3、Class的实例就看成是Java中我们学过的所有的数据类型在JVM中存在的一种状态(字节码对象)

String.class   int.class  List.class  int[].class
2.1.3. 3.4.3 Class实例的获得方式

1.

1) Class 类中的静态方法 static Class<?> forName(String className) className是类或者接口的权限定名

2) 类型.class 例如 String.class

3) 对象名.getClass() Object中,所有的对象都可以调用

Class c1= String.class;Class c2= "abc".getClass();Class c3= Class.forName("java.lang.String");System.out.println(c1==c2);//trueSystem.out.println(c2==c3);//true

2. 接口

1) static Class<?> forName(String className) className是类或者接口的权限定名

2) 类型.class

Class clz1= Class.forName("java.util.List");Class clz2= List.class;Class clz3= newArrayList().getClass();System.out.println(clz1==clz2);//trueSystem.out.println(clz2==clz3);//false

3. 数组

每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。

1.类型.class 例如 int[].class

2.对象名.getClass() Object中,所有的对象都可以调用

int[] arr1= newint[10];int[] arr2= newint[12];int[][] arr3= newint[12][];System.out.println(arr1.getClass() == arr2.getClass());System.out.println(arr1.getClass() == int[].class);

4. 基本数据类型+void

1.类型.class 例如 String.class

2.基本类型的包装类中都分别提供了一个字段保存其基本数据类型的对应的Class实例

3.int和Integer是否是同一个类型 ; 对应的Class实例是否一样

Class cla5= int.class;Class cla6= Integer.class;Class cla7= Integer.TYPE;System.out.println(cla5== cla6);System.out.println(cla5== cla7);Classcla8= void.class;Classcla9= Void.class;Classcla10= Void.TYPE;System.out.println(cla8==cla9);System.out.println(cla8==cla10);
1.3. 反射的运用

通过反射获得以下结构中的结构

Class  c  =  String.class;
1.3.1. 获得构造方法

Class文档里获得构造方法的方法摘要有(建议直接看API文档):

1.3.1.1. 获得构造器结构的方式

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

通过一个条件得到一个对应的构造方法对象

条件就是构造方法中的形成的类型对应的Class实例Class cla= Student.class;Constructor con= cla.getConstructor(String.class);//获得指定参数的构造方法System.out.println(con);2. Constructor<?>[]  getConstructors()

获得一个类中的所有的构造方法

Constructor[] constructors= cla.getConstructors();for(Constructor con: constructors) {System.out.println(con);}

注意 上面1 2 得到是公共的public修饰的;3 4 得到所有的,和访问权限无关

5 验证获得一个类中的默认无参数的构造方法(private修饰私有的构造方法)

Constructor declaredConstructor= cla.getDeclaredConstructor(double.class);System.out.println(declaredConstructor);
1.3.1.2. 创建对象的方式
classPerson{publicPerson(){}privatePerson(String name){}publicPerson(String name,intage){}privatePerson(doublescore){}}

1. 直接调用类的构造方法 new XXX();

必须是有权限访问到对应的构造方法

2. Class类中有对应的方法

1) T newInstance() 创建此 Class 对象所表示的类的一个新实例

2) 如同用一个带有一个空参数列表的 new 表达式实例化该类。

3) 注意:只能够调用无参数的构造方法,

4) 无参数的构造方法必须是有权限被访问到的

//获取有public权限构造方法Constructorconstructor= cla.getConstructor();//使用公共权限的构造方法创建对象Object pson = constructor.newInstance("name");System.out.println(pson);

3. 获得构造器对象之后,通过构造器来创建对象

1) 获得Person类对应的Class实例

2) 通过Class实例得到指定的构造方法

3) 通过得到的构造方法对象来创建Person的实例

4) 使用到了Constructor中的方法:

5) T newInstance(Object... initargs)

6) initargs 创建对象向构造方法中的传入的给对象那个初始化值的数据

Constructor con= cla.getConstructor(String.class,int.class);Person pson= con.newInstance("二狗",18);System.out.println(pson);

4. 构造器是私有的如何在外部创建对象?(单例模式外面还能创建对象吗?)

//获取私有化的构造方法[declared忽略权限]

Constructor declaredConstructor= cla.getDeclaredConstructor(double.class);

Object pson= declaredConstructor.newInstance(1.0);

System.out.println(pson);

: Class cn.itsource._10ClassConstructorCreatObject.TestClassGetConstructor can not access a member of class cn.itsource._10ClassConstructorCreatObject.Student with modifiers "private"

at sun.reflect.Reflection.ensureMemberAccess()

at java.lang.reflect.AccessibleObject.slowCheckMemberAccess()

at java.lang.reflect.AccessibleObject.checkAccess()

at java.lang.reflect.Constructor.newInstance()

at cn.itsource._10ClassConstructorCreatObject.TestClassGetConstructor.main()

如果一个类的构造方法是私有的,通过反射得到构造方法来创建对象也会报错!

1.3.1.3. 让访问权限失效

AccessibleObject|-- Constructor,|-- Field|-- Method

它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力

void setAccessible(boolean flag)

值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查

思考:

为什么私有的成员在外部类中就不能访问呢? Java规定的

//获取私有化的构造方法[declared忽略权限]Constructor declaredConstructor= cla.getDeclaredConstructor(double.class);//取消默认 Java 语言访问控制检查的能力declaredConstructor.setAccessible(true);Object pson= declaredConstructor.newInstance(1.0);System.out.println(pson);

通过上面的设置,现在我们来直接调用 Person中有一个String 参数的构造方法能够创建对象了吗?

不能,通过上面的方式对Person来讲没有任何改变

1.3.2. 获得方法1.3.2.1. 获得方法结构的方式

interfaceC{voidt5();}public  classB{privatevoidtb1(){System.out.println("B t1");}public*void*tb2(inti){System.out.println("B t2");}}public  abstract*class*A extendsB implementsC{privatevoidt1(){System.out.println("A t1");}private*void*t2(inti){System.out.println("A t2");}private*void*t3(String  s,inti){System.out.println("A 3");}}

注意 下面的1 2 找公共的,包括了本类(接口)以及父类和实现的接口中的公共的方法

下面的3 4 只在本类(接口)中找,和访问权限没有关系

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

Class clza= A.class;Method m1= clza.getMethod("t2", int.class);//获得类中的公共的System.out.println(m1);Method m2= clza.getMethod("tb2", int.class);//父类中的Method m3= clza.getMethod("t5");//接口中的System.out.println(m3);

2. Method[] getMethods()

Class clza= A.class;//获得Class对象得到所有的公共的方法Method[] methods= clza.getMethods();for(Method m: methods) {System.out.println(m);}

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

4. Method[] getDeclaredMethods()

1.3.2.2. 通过反射执行方法

1.传统的调用一个方法

public classA extendsB implementsC{

private*void*{

System.*out.println("A t1");

}

*pubic static void{

System.out.println("A t2");

}

private*void* {

System.out.println("A 3");

}

@Override

public**voidt5() {

}

}

//测试类................................

public*class*TestBalala {

public*static*voidmain(String[] args){

A a= newA();

a.tb2(10);

}

}

2.通过反射调用方法

1. 获得A对应的Class实例;

2. 通过反射得到A中的指定的方法 t3

3. 通过反射(Method类)来调用t3 方法

Method中的方法:Object invoke(Object obj, Object... args)Class clz= A.class;Method m= clz.getMethod("t3", String.class,int.class);A a= newA();m.invoke(a, "小猪猪",10);

注意: m 只是一个方法的对应对象;

a 是A的一个实例

m 对应的这个方法,应该由m对应的方法所在的类的对象(a)来调用

"小猪猪",10调用方法的时候传入实际参数

如果是静态方法呢?

传入对象的地方传入一个null 就可以了

Class clz= A.class;Method m= clz.getMethod("t2",int.class);A a= newA();m.invoke(null,10);
1.3.2.3. 验证调用私有的方法

1.得到 Class实例

2.通过1 得到指定的私有的方法 m

3.m. void setAccessible(true) ;//取消java权限检查

4.m.invoke(...);

1.3.3. 获得字段1.3.3.1. 获得字段的方式

1. Field getField(String name)

2. Field[] getFields()

3. Field getDeclaredField(String name)

4. Field[] getDeclaredFields()

标签: #反射机制有什么用