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) + " ");
}
}
}
浙公网安备 33010602011771号