在整个反射体系中,Java 的作者提供了一个类用来描述 Java 文件,这个类为 Class。
2 如何获取类的 Class 对象 2.1 类名.classClass 类型的对象代表某一个类的字节码文件。
Class userClass1 = User.class;2.2 Class.forName(“全路径类名”)
Class userClass2 = Class.forName("com.yonxao.study.jdk8api.reflect.User");
2.3 对象.getClass()
User user = new User(); Class userClass3 = user.getClass();
3 反射的核心思想userClass1 == userClass2 == userClass3
所谓的反射是将一个类中的各个成员映射成相对应的 Java 类型。
成员:
包 --> Package构造器 --> Constructor属性 --> Filed方法 --> Method 4 通过反射创建对象
创建对象时一定会调用构造方法。因此步骤如下:
- 需要通过反射先获取字节码(根基),然后通过字节码来获取指定的构造器,再通过构造器创建对象。
package com.yonxao.study.jdk8api.reflect.constructor;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
public class ConstructorTest {
@Test
public void test1() {
Class userClass = User.class;
Constructor>[] constructors = userClass.getConstructors();
for (Constructor> constructor : constructors) {
System.out.println(constructor);
}
// public com.yonxao.study.jdk8api.reflect.constructor.Man()
// public com.yonxao.study.jdk8api.reflect.constructor.Man(java.lang.String,int,float,boolean)
}
@Test
public void test2() {
Class userClass = User.class;
try {
Constructor constructor = userClass.getConstructor();
System.out.println(constructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// public com.yonxao.study.jdk8api.reflect.constructor.Man()
}
@Test
public void test3() {
Class userClass = User.class;
try {
Constructor constructor = userClass.getConstructor(String.class, int.class, float.class, boolean.class);
System.out.println(constructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// public com.yonxao.study.jdk8api.reflect.constructor.Man(java.lang.String,int,float,boolean)
}
@SuppressWarnings({"java:S112"})
@Test
public void test4() throws Exception {
Class userClass = User.class;
// 使用构造器创建对象
Constructor constructor = userClass.getConstructor(String.class, int.class, float.class, boolean.class);
User user = constructor.newInstance("王五", 22, 1.80f, false);
System.out.println(user);
// 使用字节码创建对象, 只能使用无参构造器创建
User u = userClass.newInstance();
System.out.println(u);
}
}
@SuppressWarnings("all")
class User {
public String username = "张三";
int age = 11;
protected float height = 1.75F;
private boolean sex = true;
public User() {
}
public User(String username, int age, float height, boolean sex) {
this.username = username;
this.age = age;
this.height = height;
this.sex = sex;
}
@Override
public String toString() {
return "User{" + "username='" + username + ''' + ", age=" + age + ", height=" + height + ", sex=" + sex + '}';
}
}
5 反射创建对象效率问题
@SuppressWarnings("all")
@Test
public void test5() throws Exception {
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
Class userClass = User.class;
// 使用构造器创建对象
Constructor constructor = userClass.getConstructor(String.class, int.class, float.class, boolean.class);
User user = (User) constructor.newInstance("王五", 22, 1.80f, false);
}
long endTime = System.currentTimeMillis();
System.out.println("通过反射创建对象, 时间: " + (endTime - startTime) + " ms");
// 通过反射创建对象, 时间: 123 ms
}
@SuppressWarnings("all")
@Test
public void test6() {
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
User user = new User("王五", 22, 1.80f, false);
}
long endTime = System.currentTimeMillis();
System.out.println("通过传统方式创建对象, 时间: " + (endTime - startTime) + " ms");
// 通过传统方式创建对象, 时间: 3 ms
}
次数越多差距越大,至少 10 倍起,所以对效率要求比较高的项目,都不会直接使用框架,比如说 mybatis 等,会直接使用 JDBC 来提升效率。
6 通过反射获取属性 6.1 通过反射获取属性package com.yonxao.study.jdk8api.reflect.filed;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class FiledTest {
@Test
public void test1() {
Class userClass = User.class;
// 获取所有共有属性字段
Field[] fields = userClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
/// public java.lang.String com.yonxao.study.jdk8api.reflect.filed.User.username
System.out.println("---");
// 获取所有声明的属性字段
Field[] declaredFields = userClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
/// public java.lang.String com.yonxao.study.jdk8api.reflect.filed.User.username
/// int com.yonxao.study.jdk8api.reflect.filed.User.age
/// protected float com.yonxao.study.jdk8api.reflect.filed.User.height
/// private boolean com.yonxao.study.jdk8api.reflect.filed.User.sex
}
@Test
public void test2() throws NoSuchFieldException {
Class userClass = User.class;
Field field = userClass.getDeclaredField("username");
Class> fieldType = field.getType();
System.out.println("属性的类型: " + fieldType);
/// 属性的类型: class java.lang.String
String fieldOfClassName = field.getDeclaringClass().getTypeName();
System.out.println("属性所属的类全路径: " + fieldOfClassName);
/// 属性所属的类全路径: com.yonxao.study.jdk8api.reflect.filed.User
String fieldName = field.getName();
System.out.println("属性的名称: " + fieldName);
/// 属性的名称: username
int modifiers = field.getModifiers();
System.out.printf("属性的修饰符的值: %s, 修饰符: %s%n", modifiers, ((modifiers == 0) ? "" : (Modifier.toString(modifiers))));
/// 属性的修饰符的值: 1, 修饰符: public
System.out.println(field.toString());
}
@SuppressWarnings("all")
@Test
public void test3() {
for (int i = 0; i <= 256; i++) {
String name = Modifier.toString(i);
if (!name.contains(" ")) {
System.out.printf("数字: %3d,名称: %s%n", i, name);
}
}
/// 数字: 0,名称: 默认的
/// 数字: 1,名称: public
/// 数字: 2,名称: private
/// 数字: 4,名称: protected
/// 数字: 8,名称: static
/// 数字: 16,名称: final
/// 数字: 32,名称: synchronized
/// 数字: 64,名称: volatile
/// 数字: 128,名称: transient
/// 数字: 256,名称: native
}
}
@SuppressWarnings("all")
class User {
public String username = "张三";
int age = 11;
protected float height = 1.75F;
private boolean sex = true;
public User() {
}
public User(String username, int age, float height, boolean sex) {
this.username = username;
this.age = age;
this.height = height;
this.sex = sex;
}
@Override
public String toString() {
return "User{" + "username='" + username + ''' + ", age=" + age + ", height=" + height + ", sex=" + sex + '}';
}
}
6.2 通过(暴力)反射来获取属性的值
@SuppressWarnings("all")
@Test
public void test4() throws Exception {
Class userClass = User.class;
Field[] declaredFields = userClass.getDeclaredFields();
User user = userClass.newInstance();
for (Field declaredField : declaredFields) {
// 被 private 修饰的属性, 其值无法通过反射直接获取到, 需要通过暴力反射来获取值
if (declaredField.getModifiers() == 2) {
// 所谓的暴力反射
declaredField.setAccessible(true);
}
Object o = declaredField.get(user);
System.out.printf("字段名: %s, 字段值: %s%n", declaredField.getName(), o.toString());
}
}
7 通过反射执行类的方法
package com.yonxao.study.jdk8api.reflect.method;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
public class MethodTest {
@Test
public void test1() {
Class birdClass = Bird.class;
Method[] methods = birdClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
/// public void com.yonxao.study.jdk8api.reflect.method.Bird.fly()
/// public void com.yonxao.study.jdk8api.reflect.method.Bird.fly(long)
/// public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
/// public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
/// public final void java.lang.Object.wait() throws java.lang.InterruptedException
/// public boolean java.lang.Object.equals(java.lang.Object)
/// public java.lang.String java.lang.Object.toString()
/// public native int java.lang.Object.hashCode()
/// public final native java.lang.Class java.lang.Object.getClass()
/// public final native void java.lang.Object.notify()
/// public final native void java.lang.Object.notifyAll()
}
@Test
public void test2() {
Class birdClass = Bird.class;
Method[] methods = birdClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
/// private void com.yonxao.study.jdk8api.reflect.method.Bird.fly(java.lang.String,long)
/// public void com.yonxao.study.jdk8api.reflect.method.Bird.fly()
/// public void com.yonxao.study.jdk8api.reflect.method.Bird.fly(long)
}
@SuppressWarnings("all")
@Test
public void test3() throws Exception {
Class birdClass = Bird.class;
Method fly = birdClass.getMethod("fly");
Method fly2 = birdClass.getMethod("fly", long.class);
Method fly3 = birdClass.getMethod("fly", String.class, long.class);
}
@SuppressWarnings("all")
@Test
public void test4() throws Exception {
Class birdClass = Bird.class;
Bird bird = birdClass.newInstance();
Method fly = birdClass.getMethod("fly");
Method fly2 = birdClass.getMethod("fly", long.class);
Method fly3 = birdClass.getDeclaredMethod("fly", String.class, long.class);
fly.invoke(bird);
fly2.invoke(bird, 9);
// 在其它类中是无法调用目标类的私有方法的, 但反射可以
fly3.setAccessible(true);
fly3.invoke(bird, "麻雀", 8);
}
}
class Bird {
public void fly() {
System.out.println("鸟会飞");
}
public void fly(long l) {
System.out.println("鸟会飞" + l + "分钟");
}
private void fly(String name, long l) {
System.out.println(name + "会飞" + l + "分钟");
}
}
8 反射练习
对象和 Map 互相转化
package com.yonxao.study.jdk8api.reflect.practice;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class ReflectTest {
@SuppressWarnings("all")
@Test
public void test1() throws Exception {
User user = new User();
Map map = bean2map(user);
System.out.println(map);
}
@Test
public void test2() throws Exception {
Map map = new HashMap<>(8);
map.put("username", "老王");
map.put("age", 44);
map.put("height", 1.88F);
map.put("sex", false);
User user = map2bean(map, User.class);
System.out.println(user);
}
@SuppressWarnings("java:S3011")
public static Map bean2map(Object obj) throws IllegalAccessException {
Map map = new HashMap<>(8);
Class> objClass = obj.getClass();
Field[] fields = objClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
map.put(field.getName(), field.get(obj));
}
return map;
}
@SuppressWarnings("all")
public static T map2bean(Map map, Class c) throws Exception {
Field[] declaredFields = c.getDeclaredFields();
T t = c.newInstance();
for (Field field : declaredFields) {
field.setAccessible(true);
field.set(t, map.get(field.getName()));
}
return t;
}
}
@SuppressWarnings("all")
class User {
public String username = "张三";
Integer age = 11;
protected Float height = 1.75F;
private Boolean sex = true;
@Override
public String toString() {
return "User{" + "username='" + username + ''' + ", age=" + age + ", height=" + height + ", sex=" + sex + '}';
}
}



