11_Java反射机制

  • Class类

    (1) 位于 java.lang 下

    (2) JavaDoc的介绍

    1° Class代表类的类或者接口的类(enum是一种类,注解是一种接口)

    Class类没有public构造器,所以Class类的对象实例时由JVM自动在类被加载时构造出来的

    3° 获取对应的Class实例的方法: 如果是对象,则可以用 对象.getClass()方法获得(getClass()方法是Object类的方法);如果是类,直接用 类名.class(小写)获得

      /**
       * Instances of the class {@code Class} represent classes and
       * interfaces in a running Java application.  An enum is a kind of
       * class and an annotation is a kind of interface.  Every array also
       * belongs to a class that is reflected as a {@code Class} object
       * that is shared by all arrays with the same element type and number
       * of dimensions.  The primitive Java types ({@code boolean},
       * {@code byte}, {@code char}, {@code short},
       * {@code int}, {@code long}, {@code float}, and
       * {@code double}), and the keyword {@code void} are also
       * represented as {@code Class} objects.
       *
       * <p> {@code Class} has no public constructor. Instead {@code Class}
       * objects are constructed automatically by the Java Virtual Machine as classes
       * are loaded and by calls to the {@code defineClass} method in the class
       * loader.
       *
       * <p> The following example uses a {@code Class} object to print the
       * class name of an object:
       *
       * <blockquote><pre>
       *     void printClassName(Object obj) {
       *         System.out.println("The class of " + obj +
       *                            " is " + obj.getClass().getName());
       *     }
       * </pre></blockquote>
       *
       * <p> It is also possible to get the {@code Class} object for a named
       * type (or for void) using a class literal.  See Section 15.8.2 of
       * <cite>The Java&trade; Language Specification</cite>.
       * For example:
       *
       * <blockquote>
       *     {@code System.out.println("The name of class Foo is: "+Foo.class.getName());}
       * </blockquote>
       *
       * @param <T> the type of the class modeled by this {@code Class}
       * object.  For example, the type of {@code String.class} is {@code
       * Class<String>}.  Use {@code Class<?>} if the class being modeled is
       * unknown.
    
  • 获取Class对象的3种方式(上面其实已经说过2个了)

    (1) Class c1 = Test.class;

    任何一个类都有一个隐含的__static__成员变量class

    (2) Class c2 = test.getClass();

    通过对象的getClass()方法获得

    (3) Class c3 = Class.forName(“com.myself.Test”);

    Class类提供了静态方法

      public static Class<?> forName(String className)
              throws ClassNotFoundException
    

    其中className是类的全限定名

  • 值得注意的是,无论通过上面的哪种方式获得Class对象,它们获得的Class实例是相同的(注意Class.forName()的写法使用的是Object类的全限定名)

      class Solution {
    
          public static void main(String[] args) {
    
              Class c1 = Object.class;
              Class c2 = new Object().getClass();
              Class c3 = null;
              Class c4 = new Object().getClass();
    
              try {
                  c3 = Class.forName("java.lang.Object");
              } catch (ClassNotFoundException e) {
                  e.printStackTrace();
              }
    
              System.out.println(c1 == c2);
              System.out.println(c1 == c3);
              System.out.println(c1 == c4);
          }
      }
    

    输出

      true
      true
      true
    
  • Class类是反射的基础,得到Class类对象之后,我们就可以利用Class类中提供的一系列方法实现反射了

  • 反射简介

    (1) java的反射机制是指在程序__运行__状态中:给定任意一个类,都可以获取到这个类的属性和方法;给定任意一个对象都可以调用这个对象的属性和方法,这种__动态__的获取类的信息和调用对象的方法的功能称之为java的反射机制

    (2) 反射的主要功能

    1° 运行时构造对象

    2° 运行时获取类的成员变量和方法

    3° 运行时获取对象的成员变量和方法

    4° 生成__动态代理__(Proxy和InvocationHandler两件套)

  • 反射操作__构造函数__

    构造函数变成了java.lang.reflect.Constructor对象

    (1) 获取全部构造函数:getDeclaredConstructors

    包括public, protected, default, private,但是不包括父类的构造函数。如果当前Class是interface、基本类型、数组或void,则返回长度为0的数组。返回值是无序的。

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

    示例

      class Point {
    
          int x, y, z;
    
          private Point() {
          }
    
          Point(int x) {
              this.x = x;
          }
    
          protected Point(int x, int y) {
              this.x = x;
              this.y = y;
          }
    
          public Point(int x, int y, int z) {
              this.x = x;
              this.y = y;
              this.z = z;
          }
      }
    
      class Solution {
    
          public static void main(String[] args) {
    
              Class clazz = Point.class;
    
              Constructor<?>[] constructors = clazz.getDeclaredConstructors();
    
              System.out.println(constructors.length);
    
              for (Constructor<?> constructor: constructors) {
                  
                  System.out.println(constructor.toString());
    
                  if (constructor.toString().startsWith("private")) {
                      try {
                          constructor.setAccessible(true);   //要想使用private构造函数,必须先setAccessible为true
                          Point point = (Point) constructor.newInstance();
                          System.out.println(point.x + " " + point.y + " " + point.z);
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
      }
    

    输出结果

      4
      public Point(int,int,int)
      protected Point(int,int)
      Point(int)
      private Point()
      0 0 0
    

    说明getDeclaredConstructors可以成功返回所有构造函数(4个),并且我们还成功的使用了private构造函数创建Point对象

    (2) 获取全部public构造器:getConstructors

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

    示例

      class BasePoint {
    
          int id;
    
          public BasePoint(int id) {
              this.id = id;
          }
      }
    
      class Point extends BasePoint {
    
          int x, y, z;
    
          private Point() {
              super(0);
          }
    
          Point(int x) {
              super(x);
              this.x = x;
          }
    
          protected Point(int x, int y) {
              super(x);
              this.x = x;
              this.y = y;
          }
    
          public Point(int x, int y, int z) {
              super(x);
              this.x = x;
              this.y = y;
              this.z = z;
          }
    
          public Point(int id, int x, int y, int z) {
    
              super(id);
              this.x = x;
              this.y = y;
              this.z = z;
          }
      }
    
      class Solution {
    
          public static void main(String[] args) {
    
              Class clazz = Point.class;
    
              Constructor<?>[] constructors = clazz.getConstructors();
    
              System.out.println(constructors.length);
    
              for (Constructor<?> constructor : constructors) {
    
                  System.out.println(constructor.toString());
              }
          }
      }
    

    (3) 无论是getConstructors()方法还是getDeclaredConstructors()方法都提供了只返回一个构造器的方法getConstructor()和getDeclaredConstructor(),它们的参数列表都是Class<?>… parameterTypes,用于指定构造函数中的参数

    示例

      class Solution {
    
          public static void main(String[] args) {
    
              Class clazz = Point.class;
              Constructor<Point> constructor = null;
    
              try {
                  constructor = clazz.getDeclaredConstructor(int.class, int.class, int.class, int.class);
                  System.out.println(constructor.toString());
    
                  constructor = clazz.getDeclaredConstructor();
                  System.out.println(constructor.toString());
    
                  constructor = clazz.getConstructor(int.class, int.class, int.class, int.class);
                  System.out.println(constructor.toString());
    
                  constructor = clazz.getConstructor();
                  System.out.println(constructor.toString());
    
              } catch (NoSuchMethodException e) {
                  e.printStackTrace();
              }
          }
      }
    

    输出

      public Point(int,int,int,int)
      private Point()
      public Point(int,int,int,int)
      java.lang.NoSuchMethodException: Point.<init>()
          at java.base/java.lang.Class.getConstructor0(Class.java:3302)
          at java.base/java.lang.Class.getConstructor(Class.java:2110)
          at Solution.main(Solution.java:68)
    
  • 反射操作__成员变量__

    类的成员变量是java.lang.reflect.Field类的对象

    (1) 获取全部变量:getDeclaredFields

    包括静态/非静态、public/protected/default/private,但是不包括继承的成员变量

      public Field[] getDeclaredFields() throws SecurityException
    

    示例

      class BaseObject {
    
          public static int a = 6;
          private static int b = 7;
    
          private int c = 200;
          public int d = 1000;
      }
    
      class MyObject extends BaseObject {
    
          public static int x = 3;
          private static String y = "haha";
    
          public String z;
          private int w;
    
          public MyObject(String z, int w) {
              this.z = z;
              this.w = w;
          }
      }
    
      class Solution {
    
          public static void main(String[] args) {
    
              Class clazz = MyObject.class;
              MyObject myObject = new MyObject("heihei", 10);
    
              Field[] fields = clazz.getDeclaredFields();
              System.out.println(fields.length + " fields");
      
              for (Field field : fields) {
    
                  try {
                      field.setAccessible(true);
                      System.out.println(field.get(clazz));
                  } catch (Exception e) {
                      try {
                          field.setAccessible(true);
                          System.out.println(field.get(myObject));
                      } catch (Exception e1) {
                          e1.printStackTrace();
                      }
                  }
    
                  System.out.println(field.toString());
              }
          }
      }
    

    (2) 获取全部public变量:getFields

    如果当前的Class对象代表一个类,那么会返回它的所有public域和它的所有基类、实现的所有超接口的public域;

    如果当前的Class对象代表一个接口,那么会返回它的所有public域和所有超接口的public域

    示例

      前半部分和上面的示例一样
    
      class Solution {
    
          public static void main(String[] args) {
    
              Class clazz = MyObject.class;
    
              Field[] fields = clazz.getFields();
              System.out.println(fields.length + " fields");
              MyObject myObject = new MyObject("heihei", 10);
    
              for (Field field : fields) {
    
                  try {
                      field.setAccessible(true);
                      System.out.println(field.get(clazz));
                  } catch (Exception e) {
    
                      try {
                          field.setAccessible(true);
                          System.out.println(field.get(myObject));
                      } catch (Exception e1) {
                          e1.printStackTrace();
                      }
                  }
    
                  System.out.println(field.toString());
              }
          }
      }
    

    输出

      4 fields
      3
      public static int MyObject.x
      heihei
      public java.lang.String MyObject.z
      6
      public static int BaseObject.a
      1000
      public int BaseObject.d
    

    (3) 同理,也可以用getField(String name)和getDeclaredField(String name)获取某个特定的域

  • 反射操作__成员方法__

    类的成员方法是java.lang.reflect.Method的对象

    (1) 和前面的类似,getDeclaredMethods()用来获取所有方法,但是不包括超类的方法;getMethods()用来获取所有当前类对象的public方法和超类型的所有public方法;getDeclaredMethod()和getMethod()通过指定方法名称和参数类型,获取某个特定的方法

    (2) method.invoke()可以执行这个方法

    (3) 示例

      class MyObject{
    
          public static int x = 3;
          private static String y = "haha";
    
          public String z;
          private int w;
    
          public MyObject(String z, int w) {
              this.z = z;
              this.w = w;
          }
    
          public int getW() {
              return this.w;
          }
    
          private void setW(int w) {
              this.w = w;
          }
      }
    
      class Solution {
    
          public static void main(String[] args) {
    
              Class clazz = MyObject.class;
              MyObject myObject = new MyObject("haha", 4);
              System.out.println(myObject.getW());
    
              try {
                  Method method = clazz.getDeclaredMethod("setW", int.class);
                  method.setAccessible(true);   //由于是private方法,所以要设置可访问权限
                  method.invoke(myObject, 10);
                  System.out.println(myObject.getW());
    
              } catch (NoSuchMethodException | IllegalAccessException
              | InvocationTargetException e) {
                  e.printStackTrace();
              }
          }
      }
    

    输出

      4
      10
    
  • 利用反射__可以解决无法访问private构造器、域、成员方法的问题__,无论是Construtor、Field还是Method类,都提供了setAccessible(boolean)方法,只要设为true,private也可以访问使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值