目录
前言:
今天想来总结一下反射是什么?以及如何使用?
概念:
在Java里面一个类有两种状态,它们分别是编译和运行状态,通常我们需要获取这个类的信息都是在编译阶段获得的,也就是直接点出来或者new出来,可是如果需要在类运行的阶段获得Java的类的信息的话,就需要用到Java的反射。
用处:
Java的反射用的最多的地方就是在框架里面,举个栗子,正常情况下我们要获取一个类的属性方法,我们可以直接new一个对象出来,然后再去获取它的属性和方法,然而这种情况下我们需要知道具体是哪一个类。现在有一种情况,我们做一个操作日志功能,保存用户添加和编辑的数据操作内容,要实现这个功能我们可以使用Aop,然后到具体的对象里面的操作内容我们就可以用到反射了。
Java 反射,就是在运行状态中。
- 获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等
- 获取任意对象的属性,并且能改变对象的属性
- 调用任意对象的方法
- 判断任意一个对象所属的类
- 实例化任意一个类的对象
如何使用?
(1)获取类所在的包名
package com.example.demo.test;
/**
* @Author tanghh
* @Date 2020/2/5 9:34
*/
public class TestClass {
public static void main(String[] args) throws ClassNotFoundException {
//1:获取当前类所在的包的名称:
// testGetPackageName();
}
/**
* 1.测试获取 Class 对象,获取 类所在的包名
* @throws ClassNotFoundException
*/
public static void testGetPackageName() throws ClassNotFoundException {
Class class1 = new TestClass().getClass();
System.out.println("第一种方式获取类所在的包的名称为:"+ class1.getName());
Class class2 = TestClass.class;
System.out.println("第二种方式获取类所在的包的名称为:"+class2.getName());
Class class3 = Class.forName("com.example.demo.test.TestClass");
System.out.println("第三种方式获取类所在的包的名称为:"+class3.getName());
//一个 jvm 中一种 Class 只会被实例化一次,对上面的 Class 实例进行判断发现都是相等的
System.out.println(class1 == class2);
System.out.println(class1 == class3);
}
}
测试效果
(2) 获取类的属性和方法等信息
package com.example.demo.test;
/**
* @Author tanghh
* @Date 2020/2/5 9:34
*/
public class TestClass {
private int i = 0;
public int j = 1;
private void t() {
System.out.println("调用 TestClass 对象的 t() 方法");
}
public static void main(String[] args) throws ClassNotFoundException {
//2.测试当前类对象的方法
testClassMethod();
}
/**
* 1.测试获取 Class 对象,获取 类所在的包名
* @throws ClassNotFoundException
*/
public static void testGetPackageName() throws ClassNotFoundException {
Class class1 = new TestClass().getClass();
System.out.println("第一种方式获取类所在的包的名称为:"+ class1.getName());
Class class2 = TestClass.class;
System.out.println("第二种方式获取类所在的包的名称为:"+class2.getName());
Class class3 = Class.forName("com.example.demo.test.TestClass");
System.out.println("第三种方式获取类所在的包的名称为:"+class3.getName());
//一个 jvm 中一种 Class 只会被实例化一次,对上面的 Class 实例进行判断发现都是相等的
System.out.println(class1 == class2);
System.out.println(class1 == class3);
}
/**
* 测试 Class 对象的方法
*/
public static void testClassMethod() {
Class<TestClass> clazz = TestClass.class;
System.out.println("1.获取类全名(包含路径)----> " + clazz.getName());
System.out.println("2.获取类简称 --> " + clazz.getSimpleName());
System.out.println("3.获取父类 --> " + clazz.getSuperclass());
System.out.println("4.判断是否为接口 --> " + clazz.isInterface());
System.out.println("5.获取 public 字段,包含父类 public 字段 --> " + join(clazz.getFields(), "\r\n"));
System.out.println("6.获取所有字段 --> " + join(clazz.getDeclaredFields(), "\r\n"));
System.out.println("7.获取 public 方法,包含父类 public 方法 --> " + join(clazz.getMethods(), "\r\n"));
System.out.println("8.获取所有字段 --> " + join(clazz.getDeclaredMethods(), "\r\n"));
System.out.println("9.获取构造方法 --> " + join(clazz.getConstructors(), "\r\n"));
try {
clazz.newInstance().t();//实例化 TestClass 对象,调用对象中的 t() 方法
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* 拼接数组成字符串
* @param objs
* @param s
* @return
*/
private static String join(Object[] objs, String s) {
StringBuilder r = new StringBuilder();
for (Object obj : objs) {
r.append(obj).append(s);
}
return r.toString();
}
}
测试结果