Java反射(Reflection)

一、反射介绍

Java反射机制可以在运行时检查类、接口、方法和变量等信息,还可以在运行时实例化新对象、调用方法以及获取和设置变量值。

有些情况下,我们要使用的类在运行时才会确定,这时我们不能在编译期使用,因此只能通过反射的形式来使用在运行时才存在的类,这是反射用得比较多的场景。

编译时,我们对于类的内部信息不可知,必须得到运行时才能获取类的具体信息。比如ORM框架,在运行时才能够获取类中的各个属性,然后通过反射的形式获取其属性名和值,存入数据库。

反射机制提供的功能:

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的方法
  • 通过反射甚至可以调用到private方法
  • 在运行时修改构造函数、变量和方法的访问权限

解耦:

假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?答案是不能通过编译。但是利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。

在对类的调用和实例化的时候,通过在配置文件中配置相应的类名,在程序中读取类名,然后通过反射技术在程序中加载和实例化。如常见的数据库驱动程序类,为了达到不依赖特定数据库驱动类,将用到的数据库驱动类名放到配置文件中(例如xml文件、properties文件和文本文件),然后在程序中加载驱动,来实现对数据库的解耦,也就是说只要修改配置文件,就可以方便地更改数据库类型。

 

二、反射API

java.lang.Class

java.lang.reflect包中的Field、Constructor、Method、Array类

 

Class:

类是程序的一部分,每个类都有一个Class对象。每当编写并且编译了一个新类,就会产生一个Class对象。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的,因此不能显示地声明一个Class对象。

Class的方法:

  • getName():获得类的完整名字(包含包名信息)
  • getSimpleName():只获取类名(不包含包名)
  • getPackage():获取包信息
  • getFields():获得类的public类型的属性
  • getDeclaredFields():获得类的所有属性
  • getMethods():获得类的public类型的方法
  • getDeclaredMethods():获得类的所有方法
  • getMethod(String name, Class[]{parameterTypes}):获得类的特定方法,name参数指定方法名字,parameterTypes参数指定方法的参数类型
  • getConstructors():获得类的public类型的构造方法
  • getConstructor(Class[]{parameterTypes}):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型
  • getSuperclass():返回父类的Class对象
  • getInterfaces():获取接口信息(一个类可以实现多个接口),注意:getInterfaces()只返回指定类实现的接口,不会返父类实现的接口。
  • newInstance():先通过反射获取到构造器,再通过构造器调用newInstance()方法创建这个类的一个对象(若获取的是带参构造函数,则newInstance方法创建对象需要传递参数)

 

三、获取Class对象的方式

1、类名.class

2、Class.forName()

3、对象名.getClass()

4、通过 ClassLoader对象的 loadClass方法

ClassLoader.getSystemClassLoader().loadClass("com.my.test.Hello")

public class ClassModel {
    static {
        System.out.println("static block");
    }
    {
        System.out.println("dynamic block");
    }
}

public class ClassTest {
      public static void main(String[] args) {
          // 方式一 
          System.out.println("方式一 "); 
          Class<?> c = ClassModel.class;
          System.out.println("方式二");
          // 方式二
          try {
            Class<?> c2 = Class.forName("com.yp.reflect.demo1.ClassModel");
           } catch (ClassNotFoundException e) {
               e.printStackTrace();
           }
          // 方式三
          System.out.println("方式三"); 
          (new ClassModel()).getClass();
    }
}

  

 

四、使用反射

从对象中获取类名:

package com.longluo.java.interview.reflection;
  
public class ReflectionHelloWorld {
  
  public static void main(String[] args) {
    Foo f = new Foo();
    System.out.println(f.getClass().getName());
  }
}
  
class Foo {
  public void print() {
    System.out.println("abc");
  }
}

输出:com.longluo.java.interview.reflection.Foo

 

调用未知对象的方法:不知道一个对象的类型,但是通过反射,我们可以使用这个对象并且调用它的方法(需要知道方法名)

package com.longluo.java.interview.reflection;

import java.lang.reflect.Method;
  
public class ReflectionHelloWorld {

  public static void main(String[] args) {
    Foo f = new Foo();
    Method method;
    try {
      method = f.getClass().getMethod("print", null);
      method.invoke(f);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
  
class Foo {
  public void print() {
    System.out.println("abc");
  }
}

  

从Class实例创建对象

package com.longluo.java.interview.reflection;
  
import java.lang.reflect.Method;
  
public class ReflectionHelloWorld {
  
  public static void main(String[] args) {

    Class c = null;
    try {
      c = Class.forName("com.longluo.java.interview.reflection.Foo");
    } catch (Exception e) {
      e.printStackTrace();
    }
  
    Foo f = null;
    try {
      f = (Foo) c.newInstance();
    } catch (Exception e) {
      e.printStackTrace();
    }
    f.print();
  }
  
}
  
class Foo {
  public void print() {
    System.out.println("abc");
  }
}

  

获取构造器并创建实例

package com.longluo.java.interview.reflection;
import java.lang.reflect.Constructor;
public class ReflectionHelloWorld4 {
  public static void main(String[] args) {
    Class c = null;
    try {
      c = Class.forName("com.longluo.java.interview.reflection.Foo4");
    } catch (Exception e) {
      e.printStackTrace();
    }
    Foo4 f1 = null;
    Foo4 f2 = null;
    Constructor cons[] = c.getConstructors();
    try {
      f1 = (Foo4) cons[0].newInstance();
      f2 = (Foo4) cons[1].newInstance("abc");
    } catch (Exception e) {
      e.printStackTrace();
    }
    f1.print();
    f2.print();
  }
}

class Foo4 {
  String s;
  public Foo4() {
  }
  public Foo4(String s) {
    this.s = s;
  }
  public void print() {
    System.out.println(s);
  }
}

输出:

null
abc

  

通过反射修改数组大小

package com.longluo.java.interview.reflection;
import java.lang.reflect.Array;
public class ReflectionHelloWorld5 {
  public static void main(String[] args) {
    int[] intArray = { 1, 2, 3, 4, 5 };
    int[] newIntArray = (int[]) changeArraySize(intArray, 10);
    print(newIntArray);
  }
  public static Object changeArraySize(Object obj, int len) {
    Class arr = obj.getClass().getComponentType();
    Object newArray = Array.newInstance(arr, len);
    int co = Array.getLength(obj);
    System.arraycopy(obj, 0, newArray, 0, co);
    return newArray;
  }
  public static void print(Object obj) {
    Class c = obj.getClass();
    if (!c.isArray()) {
      return;
    }
    System.out.println("\nArray length:" + Array.getLength(obj));
    for (int i = 0; i < Array.getLength(obj); i++) {
      System.out.print(Array.get(obj, i) + " ");
    }
  }
}

  

 

posted @ 2021-03-30 10:10  455994206  阅读(250)  评论(0)    收藏  举报