From 43fd06fc624ec0279b69b397f21075b7011eab61 Mon Sep 17 00:00:00 2001 From: achao Date: Tue, 7 Jun 2022 23:13:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9EReflectUtil.getDescriptor?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=8D=95=E4=B8=AAclass=E7=9A=84=E6=8F=8F?= =?UTF-8?q?=E8=BF=B0=E7=AC=A6=E9=87=8D=E8=BD=BD=EF=BC=8C=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=E5=92=8C=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/reflect/ReflectUtil.java | 102 +++++++++--------- .../hutool/core/reflect/ReflectUtilTest.java | 19 +++- 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java b/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java index 06985a355..d1f19fdbd 100644 --- a/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/reflect/ReflectUtil.java @@ -33,7 +33,8 @@ public class ReflectUtil { * * @param executable 可执行的反射对象 * @return 描述符 - * @apiNote 参考:jvm定义的Field Descriptors(字段描述) + * @link jvm定义的Field Descriptors(字段描述) + * @link 关于类型描述符的博客 *

例:

* Object.class.getMethod("hashCode") + * + * @author VampireAchao */ public static String getDescriptor(Executable executable) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append('('); Class[] parameters = executable.getParameterTypes(); for (Class parameter : parameters) { - appendDescriptor(parameter, stringBuilder); + stringBuilder.append(getDescriptor(parameter)); } if (executable instanceof Method) { Method method = (Method) executable; - stringBuilder.append(')'); - appendDescriptor(method.getReturnType(), stringBuilder); - return stringBuilder.toString(); + return stringBuilder.append(')').append(getDescriptor(method.getReturnType())).toString(); } else if (executable instanceof Constructor) { return stringBuilder.append(")V").toString(); } @@ -62,65 +62,63 @@ public class ReflectUtil { } /** - * 拼接描述符 + * 获取类型描述符,这是编译成class文件后的二进制名称 * - * @param clazz 类 - * @param stringBuilder 描述符 + * @param clazz 类 * @link jvm定义的Field Descriptors(字段描述) + * @link 关于类型描述符的博客 + *

例:

+ * + * @author VampireAchao */ - private static void appendDescriptor(Class clazz, StringBuilder stringBuilder) { + public static String getDescriptor(Class clazz) { + StringBuilder stringBuilder = new StringBuilder(); Class currentClass; for (currentClass = clazz; currentClass.isArray(); currentClass = currentClass.getComponentType()) { + // 如果当前是数组描述符 stringBuilder.append('['); } if (currentClass.isPrimitive()) { - stringBuilder.append(getDescriptorChar(currentClass)); + // 只有下面九种基础数据类型以及数组,才有独立的描述符 + final char descriptor; + // see sun.invoke.util.Wrapper + // These must be in the order defined for widening primitive conversions in JLS 5.1.2 + if (currentClass == boolean.class) { + descriptor = 'Z'; + } else if (currentClass == byte.class) { + descriptor = 'B'; + } else if (currentClass == short.class) { + descriptor = 'S'; + } else if (currentClass == char.class) { + descriptor = 'C'; + } else if (currentClass == int.class) { + descriptor = 'I'; + } else if (currentClass == long.class) { + descriptor = 'J'; + } else if (currentClass == float.class) { + descriptor = 'F'; + } else if (currentClass == double.class) { + descriptor = 'D'; + } else if (currentClass == void.class) { + // VOID must be the last type, since it is "assignable" from any other type: + descriptor = 'V'; + } else { + throw new AssertionError(); + } + stringBuilder.append(descriptor); } else { + // 否则一律是 "L"+类名.replace('.', '/')+";"格式的对象类型 stringBuilder.append('L').append(currentClass.getName().replace('.', '/')).append(';'); } - - } - - /** - * 获取单个描述符 - * - * @param currentClass 当前类 - * @return 描述符 - */ - private static char getDescriptorChar(Class currentClass) { - if ( currentClass == boolean.class) { - return 'Z'; - } - if ( currentClass == byte.class) { - return 'B'; - } - if (currentClass == short.class) { - return 'S'; - } - if (currentClass == char.class) { - return 'C'; - } - if (currentClass == int.class) { - return 'I'; - } - if (currentClass == long.class) { - return 'J'; - } - if (currentClass == float.class) { - return 'F'; - } - if (currentClass == double.class) { - return 'D'; - } - if (currentClass == Object.class) { - return 'L'; - } - if (currentClass == void.class) { - return 'V'; - } - throw new AssertionError(); + return stringBuilder.toString(); } } diff --git a/hutool-core/src/test/java/cn/hutool/core/reflect/ReflectUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/reflect/ReflectUtilTest.java index a89659531..60d2bdbb8 100644 --- a/hutool-core/src/test/java/cn/hutool/core/reflect/ReflectUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/reflect/ReflectUtilTest.java @@ -1,11 +1,13 @@ package cn.hutool.core.reflect; import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.ArrayUtil; import lombok.Data; import lombok.SneakyThrows; import org.junit.Test; +import java.util.Arrays; +import java.util.Collection; + /** * 反射工具类单元测试 * @@ -113,10 +115,21 @@ public class ReflectUtilTest { @Test @SneakyThrows public void testGetDescriptor() { + // methods Assert.equals("()I", ReflectUtil.getDescriptor(Object.class.getMethod("hashCode"))); Assert.equals("()Ljava/lang/String;", ReflectUtil.getDescriptor(Object.class.getMethod("toString"))); Assert.equals("(Ljava/lang/Object;)Z", ReflectUtil.getDescriptor(Object.class.getMethod("equals", Object.class))); - Assert.equals("(Ljava/lang/Class;Ljava/lang/StringBuilder;)V", ReflectUtil.getDescriptor(ReflectUtil.class.getDeclaredMethod("appendDescriptor", Class.class, StringBuilder.class))); - Assert.equals("([Ljava/lang/Object;)Z", ReflectUtil.getDescriptor(ArrayUtil.class.getMethod("isEmpty", Object[].class))); + Assert.equals("(II)I", ReflectUtil.getDescriptor(Integer.class.getDeclaredMethod("compare", int.class, int.class))); + Assert.equals("([Ljava/lang/Object;)Ljava/util/List;", ReflectUtil.getDescriptor(Arrays.class.getMethod("asList", Object[].class))); + Assert.equals("()V", ReflectUtil.getDescriptor(Object.class.getConstructor())); + // clazz + Assert.equals("Z", ReflectUtil.getDescriptor(boolean.class)); + Assert.equals("Ljava/lang/Boolean;", ReflectUtil.getDescriptor(Boolean.class)); + Assert.equals("[[[D", ReflectUtil.getDescriptor(double[][][].class)); + Assert.equals("I", ReflectUtil.getDescriptor(int.class)); + Assert.equals("Ljava/lang/Integer;", ReflectUtil.getDescriptor(Integer.class)); + Assert.equals("V", ReflectUtil.getDescriptor(void.class)); + Assert.equals("Ljava/lang/Void;", ReflectUtil.getDescriptor(Void.class)); + Assert.equals("Ljava/lang/Object;", ReflectUtil.getDescriptor(Object.class)); } }