1.JAVA反射机制的概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
java中使用Class类进行反射,关于Class类官网API给出的解释是:
Instances of the class Class represent classes and interfaces in a running Java application.
翻译为中文是:Class类的实例代表一个运行java应用程序的类和接口
对于这句话的理解就是:在面向对象的世界里,万事万物皆对象
类也是对象,任何一个类都是java.lang.Class类的实例对象,因此Class也称为类类型。
2.实例对象的三种表达方式
public class ReflectTest {
public static final void main(String args[]) {
//1.第一种表达方式,已知类名,
//每个类都有一个隐含的静态成员变量class
Class c1 = Hello.class;
//2.第二种表达方式,已知该类的对象,通过getClass方法
Hello hello = new Hello();
Class c2 = hello.getClass();
//3.第三种表达方式,已知完整包名
Class c3 = null;
try {
c3 = Class.forName("com.dao_li.myapplication.Hello");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//c1, c2,c3表示了Hello类的类类型(class type)
//类也是对象,是Class类的实例对象,
//一个类只可能是Class类的一个实例对象
out.println(c1);
out.println(c2);
out.println(c3);
out.println(c1 == c2 && c1 == c3);
}
}
//类是Class类的对象
class Hello{
}
运行结果:
class com.dao_li.myapplication.Hello
class com.dao_li.myapplication.Hello
class com.dao_li.myapplication.Hello
true
Process finished with exit code 0
这里再加入两点说明
1、java静态加载和动态加载的说明:
new创建对象的方式称作为静态加载,而使用Class.forName(“your package”)称作为动态加载
它们俩本质的区别在于静态加载的类在编译时刻就需要加载所有可能使用到的类(必须存在),而动态加载的类在编译时期可以不存在,但是在运行时会检查。
2、void、自定义类、基本的数据类型及其封装类都存在类类型
import static java.lang.System.out;
public class ClassDemo {
public static void main(String[] args){
Class c1 = int.class;
Class c2 = Integer.class;
Class c3 = String.class;
Class c4 = void.class;
out.println(c1);
out.println(c2);
out.println(c3);
out.println(c4);
}
}
3、获取类的构造方法,成员变量,成员方法
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import static java.lang.System.out;
/**
* 创建时间: 2017/7/24 11:33
* 功能描述:打印类的基本信息,包括构造方法,成员变量,成员方法
*/
public class ClassUtil {
//打印类的构造方法
public static void printConsMsg(Object obj) {
out.println("----------------------------------------------");
Class c = obj.getClass();
out.println("类名:" + c.getName());
Constructor[] constructors = c.getConstructors(); //获取所有public的构造方法
// Constructor[] constructors = c.getDeclaredConstructors(); //获取所有的构造方法
for (int i = 0; i < constructors.length; i++) {
out.print("构造方法" + (i + 1) + ": " + c.getSimpleName() + "(");
Constructor constructor = constructors[i];
Class[] paramTypes = constructor.getParameterTypes(); //获取构造函数的参数列表
for (int j = 0; j < paramTypes.length; j++) {
Class c1 = paramTypes[j];
out.print(c1.getName());
if (j != paramTypes.length - 1) {
out.print(",");
}
}
out.println(")");
}
out.println();
}
//打印类的成员变量
public static void printFieldMsg(Object obj) {
out.println("----------------------------------------------");
Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型
out.println("类名:" + c.getName());
// 打印该类的所有public成员变量
Field[] fields = c.getFields(); //获取该类中声明的所有的public成员变量,
// Field[] fields = c.getDeclaredFields(); //获取该类中声明的所有的成员变量,
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
Class c1 = field.getType(); //获取成员变量的类类型
out.println("成员变量" + (i + 1) + ": " + c1.getName() + " " + field.getName());
}
out.println();
}
//打印类的成员函数
public static void printMethodMsg(Object obj) {
out.println("----------------------------------------------");
Class c = obj.getClass();
out.println("类名:" + c.getName());
// 打印该类的所有public成员方法
Method[] methods = c.getMethods(); //获取所有的public成员方法,包括从父类继承而来
// Method[] methods = c.getDeclaredMethods(); //获取所有的成员方法
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
Class returnType = method.getReturnType(); //获取method的返回值的类类型
out.print("成员方法" + (i + 1) + ": " + returnType.getName() + " ");
out.print(method.getName()); //获取method的名称
out.print("(");
Class[] paramTypes = method.getParameterTypes(); //获取method参数类型,得到的参数列表的类型的类类型
for (int j = 0; j < paramTypes.length; j++) {
Class c1 = paramTypes[j];
out.print(c1.getName());
if (j != paramTypes.length - 1) {
out.print(",");
}
}
out.println(")");
}
out.println();
}
}
调用示例:
ClassUtil.printFieldMsg(new String());
ClassUtil.printConsMsg(new String());
ClassUtil.printMethodMsg(new String());
4、调用方法的两种方式
自定义一个类
public class TestClass {
public int add(int a, int b) {
return a + b;
}
public String add(String a, String b) {
return a + b;
}
}
调用方式1:
使用类的实例直接调用重载方法:
import static java.lang.System.out;
public class ClassDemo {
public static void main(String[] args) {
TestClass testClass = new TestClass();
int i = testClass.add(12, 18);
out.println(i);
String s = testClass.add("Hello", "Reflect");
out.println(s);
}
}
调用方式2:
通过反射机制调用类的方法
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static java.lang.System.out;
public class ClassDemo {
public static void main(String[] args) {
TestClass testClass = new TestClass(); //new一个类的对象
Class c = testClass.getClass(); //获取类的类类型
try {
//获取方法名为add,参数为int,int的方法实例
Method method = c.getMethod("add", int.class, int.class);
int i = (int) method.invoke(testClass, 1772, 15);
out.println(i);
Method method1 = c.getMethod("add", new Class[]{String.class, String.class});
String s = (String) method1.invoke(testClass, "Hello", "Reflect");
out.println(s);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
反射中getMethods 与 getDeclaredMethods 的区别:
public Method[] getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。
public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。当调用private方法时,需要在Method对象加上method.setAccessible(true)设置访问权限,不然会报IllegalAccessException异常。