java(19)---反射机制

java---反射机制

java语言允许通过程序化的方式间接对Class进行操作,Class文件由类加载器装载后,在JVM中形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如

构造函数、属性和方法等。

java允许用户借由这个Class相关的元信息对对象间接调用Class对象的功能。

11.1、什么是反射?

反射机制是在运行状态中:

对于任意的一个类,都能够知道这个类的所有属性和方法

对于任意的一个对象,都能够调用它的任意一个方法和属性。

 

11.2、反射提供的功能有:

1)、在运行时判断任意一个所属的类

2)、在运行时构造任意一个类的对象

3)、在运行时判断任意一个类所具有的成员变量和方法

4)、在运行时调用任意一个对象的方法

5)、生成动态代理

 

11.3、获取反射对象的三种方式

第一种、Class.forName(全类名),推荐使用,可以捕获异常ClassNotFoundException

package com.cn.fanshe;

 

public class Test {

   public static void main(String[] args) {

      //获取反射对象(反射入口)::

      /**

       * 获取反射对象有3种方式:

       * 第一种、Class.forName(全类名)

       * 第二种、类名.class

       * 第三种、对象.getClass()

       * */

      try {

         Class<?> userClazz=Class.forName("com.cn.fanshe.User");

         System.out.println(userClazz);

      } catch (ClassNotFoundException e) {

         e.printStackTrace();

      }

   }

}

 

第二种、类名.class

Class<?> userClazz=User.class;

System.out.println(userClazz);

 

 

第三种、对象.getClass()

//1.创建对象

User user=new User();

Class<?> userClazz=user.getClass();

System.out.println(userClazz);

 

11.4、获取反射类中的所有公共方法

package com.cn.fanshe;

 

import java.lang.reflect.Method;

/**

 * 1、获得所有的公共方法(本类、父类以及接口中的所有方法,符合访问修饰符的public方法,但不包括private方法)

 * */

public class Test {

   public static void getAllMethod(){

      //1.获得反射对象

      Class<?> userClazz=null;

      try {

         userClazz=Class.forName("com.cn.fanshe.User");

      } catch (ClassNotFoundException e) {

         e.printStackTrace();

      }

      //2.获得所有的公共方法

      Method[] methods=userClazz.getMethods();

      //3.遍历所有的公共方法

      for(Method method:methods){

         System.out.println(method);

      }

   }

  

   public static void main(String[] args) {

      Test.getAllMethod();

   }

}

 

11.5、获得反射类中的所有接口

//1.获得反射对象

Class<?> userClazz=null;

try {

      userClazz=Class.forName("com.cn.fanshe.User");

} catch (ClassNotFoundException e) {

      e.printStackTrace();

}

Class<?>[] userInterfaces=userClazz.getInterfaces();

for(Class<?> inter:userInterfaces){

   System.out.println(inter);

}

 

11.6、获得所有的父类,父类只有1个

Class<?> superClass=userClazz.getSuperclass();

System.out.println(superClass);

 

11.7、获得所有的构造方法

Constructor<?>[] constructors=userClazz.getConstructors();

for(Constructor<?> con:constructors){

   System.out.println(con);

}

 

11.8、获取所有的公共属性

Field[] fields=userClazz.getFields();

for(Field fie:fields){

   System.out.println(fie);

}

 

注:获取所有公共属性和方法,则修改为如下:

Field[] fields=userClazz.getDeclaredFields();

 

11.9、获取对象的实例,并操作对象

package com.cn.fanshe;

 

import java.lang.reflect.Field;

/**

 * 1、获得所有的公共方法(本类、父类以及接口中的所有方法,符合访问修饰符的public方法,但不包括private方法)

 * */

public class Test {

   public static void test() throws InstantiationException, IllegalAccessException{

      //1.获得反射对象

      Class<?> userClazz=null;

      try {

         userClazz=Class.forName("com.cn.fanshe.User");

      } catch (ClassNotFoundException e) {

         e.printStackTrace();

      }

      //2.获取对象实例

      User user=(User) userClazz.newInstance();

      user.setName("Jerry");

      user.setAge(21);

      System.out.println(user.getName()+","+user.getAge());

   }

  

   public static void main(String[] args) throws InstantiationException, IllegalAccessException {

      Test.test();

   }

}

 

11.10、创建对象实例并操作对象属性

//1.获得反射对象

Class<?> userClazz=null;

try {

      userClazz=Class.forName("com.cn.fanshe.User");

} catch (ClassNotFoundException e) {

      e.printStackTrace();

}

//2.获取对象实例

User user=(User) userClazz.newInstance();

Field nameField=userClazz.getDeclaredField("name");

nameField.set(user, "张三");

System.out.println(user.getName());

此时会报异常,如下:

Exception in thread "main" java.lang.IllegalAccessException: Class com.cn.fanshe.Test can not access a member of class com.cn.fanshe.User with modifiers "private"

   at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:95)

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

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

   at java.lang.reflect.Field.doSecurityCheck(Field.java:983)

   at java.lang.reflect.Field.getFieldAccessor(Field.java:927)

   at java.lang.reflect.Field.set(Field.java:680)

   at com.cn.fanshe.Test.test(Test.java:19)

   at com.cn.fanshe.Test.main(Test.java:24)

 

原因是访问的是私有的name,需要修改属性的访问权限,如果因为访问修饰符限制造成的异常,可以通过属性或方法.setAccessible(true),暂时性的打开权限。

如下:

//2.获取对象实例

      User user=(User) userClazz.newInstance();

      Field nameField=userClazz.getDeclaredField("name");

      nameField.setAccessible(true);

      nameField.set(user, "张三");

      System.out.println(user.getName());

 

注:方法的操作类似属性,但是方法的调用用invoke()

如下:

//2.获取对象实例

User user=(User) userClazz.newInstance();

//interfaceMethod2是方法名,null是参数类型

Method method=userClazz.getDeclaredMethod("interfaceMethod2", null);

method.invoke(user, null); //常规方法调用如user.say(参数)

 

11.11、反射的适用场景?

1)、java的反射机制在做基础框架时十分有用,即反射机制是很多java框架的基石。

最经典的就是在XML文件或Properties里面写好配置,然后在java类里面解析XML或properties里面的内容,得到一个字符串,然后用反射机制,根据这个字符串获得某个类的Class实例,这样就可以动态配置一些东西,不用每次都要在代码里面去new或者做其它事情,以后要改的话直接修改配置文件,代码维护起来就方便了。

2)、java类里面不一定能直接调用另外的方法,这时可以通过反射机制来实现。

3)、在编码阶段不知道那个类名,要在运行期从配置文件读取类名,这时就没办法硬编码new ClassName();而必须用到反射才能创建这个对象,反射的目的就是为了扩展未知的应用。

 

11.12、反射的性能问题

反射机制是一种程序自我分析的能力,用于获取一个类的变量、构造函数、方法、修饰符

优点:运行期类型的判断,动态类加载,动态代理使用反射

缺点:性能是一个问题,反射相当于一系列解释操作,通知JVM要做的事情,性能比直接的java代码要慢很多。

 

11.13、程序员在自己的业务开发中应该尽量远离反射

反射:在流行的库如hibernate和spring中,反射自然有其用武之地。不过内省业务代码在很多时候都不是一件好事,原因有很多,总之不建议使用反射。

首先是代码可读性和工具支持,打开IDE,寻找你的java代码的内部依赖,很容易吧。

现在使用反射来替换掉你的代码然后再试一下,结果如何呢?如果通过反射来修改已经封装好的对象状态,那么结果将会变得更加不可控。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值