This commit is contained in:
Looly 2022-03-08 20:52:43 +08:00
parent 62fd367fc4
commit 9229eea85f
5 changed files with 134 additions and 72 deletions

View File

@ -14,6 +14,7 @@
### 🐞Bug修复 ### 🐞Bug修复
* 【core 】 修复ObjectUtil.hasNull传入null返回true的问题pr#555@Gitee * 【core 】 修复ObjectUtil.hasNull传入null返回true的问题pr#555@Gitee
* 【core 】 修复NumberConverter对数字转换的问题issue#I4WPF4@Gitee * 【core 】 修复NumberConverter对数字转换的问题issue#I4WPF4@Gitee
* 【core 】 修复ReflectUtil.getMethods获取接口方法问题issue#I4WUWR@Gitee
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.7.22 (2022-03-01) # 5.7.22 (2022-03-01)

View File

@ -20,35 +20,60 @@ public class ModifierUtil {
* @since 4.0.5 * @since 4.0.5
*/ */
public enum ModifierType { public enum ModifierType {
/** public修饰符所有类都能访问 */ /**
* public修饰符所有类都能访问
*/
PUBLIC(Modifier.PUBLIC), PUBLIC(Modifier.PUBLIC),
/** private修饰符只能被自己访问和修改 */ /**
* private修饰符只能被自己访问和修改
*/
PRIVATE(Modifier.PRIVATE), PRIVATE(Modifier.PRIVATE),
/** protected修饰符自身、子类及同一个包中类可以访问 */ /**
* protected修饰符自身子类及同一个包中类可以访问
*/
PROTECTED(Modifier.PROTECTED), PROTECTED(Modifier.PROTECTED),
/** static修饰符静态修饰符指定变量被所有对象共享即所有实例都可以使用该变量。变量属于这个类 */ /**
* static修饰符静态修饰符指定变量被所有对象共享即所有实例都可以使用该变量变量属于这个类
*/
STATIC(Modifier.STATIC), STATIC(Modifier.STATIC),
/** final修饰符最终修饰符指定此变量的值不能变使用在方法上表示不能被重载 */ /**
* final修饰符最终修饰符指定此变量的值不能变使用在方法上表示不能被重载
*/
FINAL(Modifier.FINAL), FINAL(Modifier.FINAL),
/** synchronized同步修饰符在多个线程中该修饰符用于在运行前对他所属的方法加锁以防止其他线程的访问运行结束后解锁。 */ /**
* synchronized同步修饰符在多个线程中该修饰符用于在运行前对他所属的方法加锁以防止其他线程的访问运行结束后解锁
*/
SYNCHRONIZED(Modifier.SYNCHRONIZED), SYNCHRONIZED(Modifier.SYNCHRONIZED),
/** (易失修饰符)指定该变量可以同时被几个线程控制和修改 */ /**
* 易失修饰符指定该变量可以同时被几个线程控制和修改
*/
VOLATILE(Modifier.VOLATILE), VOLATILE(Modifier.VOLATILE),
/** (过度修饰符)指定该变量是系统保留,暂无特别作用的临时性变量,序列化时忽略 */ /**
* 过度修饰符指定该变量是系统保留暂无特别作用的临时性变量序列化时忽略
*/
TRANSIENT(Modifier.TRANSIENT), TRANSIENT(Modifier.TRANSIENT),
/** native本地修饰符。指定此方法的方法体是用其他语言在程序外部编写的。 */ /**
* native本地修饰符指定此方法的方法体是用其他语言在程序外部编写的
*/
NATIVE(Modifier.NATIVE), NATIVE(Modifier.NATIVE),
/** abstract将一个类声明为抽象类没有实现的方法需要子类提供方法实现。 */ /**
* abstract将一个类声明为抽象类没有实现的方法需要子类提供方法实现
*/
ABSTRACT(Modifier.ABSTRACT), ABSTRACT(Modifier.ABSTRACT),
/** strictfp一旦使用了关键字strictfp来声明某个类、接口或者方法时那么在这个关键字所声明的范围内所有浮点运算都是精确的符合IEEE-754规范的。 */ /**
* strictfp一旦使用了关键字strictfp来声明某个类接口或者方法时那么在这个关键字所声明的范围内所有浮点运算都是精确的符合IEEE-754规范的
*/
STRICT(Modifier.STRICT); STRICT(Modifier.STRICT);
/** 修饰符枚举对应的int修饰符值 */ /**
* 修饰符枚举对应的int修饰符值
*/
private final int value; private final int value;
/** /**
* 构造 * 构造
*
* @param modifier 修饰符int表示{@link Modifier} * @param modifier 修饰符int表示{@link Modifier}
*/ */
ModifierType(int modifier) { ModifierType(int modifier) {
@ -57,6 +82,7 @@ public class ModifierUtil {
/** /**
* 获取修饰符枚举对应的int修饰符值值见{@link Modifier} * 获取修饰符枚举对应的int修饰符值值见{@link Modifier}
*
* @return 修饰符枚举对应的int修饰符值 * @return 修饰符枚举对应的int修饰符值
*/ */
public int getValue() { public int getValue() {
@ -226,9 +252,21 @@ public class ModifierUtil {
return clazz.isSynthetic(); return clazz.isSynthetic();
} }
/**
* 是否抽象方法
*
* @param method 方法
* @return 是否抽象方法
* @since 5.7.23
*/
public static boolean isAbstract(Method method) {
return hasModifier(method, ModifierType.ABSTRACT);
}
//-------------------------------------------------------------------------------------------------------- Private method start //-------------------------------------------------------------------------------------------------------- Private method start
/** /**
* 多个修饰符做操作表示同时存在多个修饰符 * 多个修饰符做操作表示同时存在多个修饰符
*
* @param modifierTypes 修饰符列表元素不能为空 * @param modifierTypes 修饰符列表元素不能为空
* @return 之后的修饰符 * @return 之后的修饰符
*/ */

View File

@ -652,30 +652,36 @@ public class ReflectUtil {
} }
/** /**
* 获得一个类中所有方法列表直接反射获取无缓存 * 获得一个类中所有方法列表直接反射获取无缓存<br>
* 接口获取方法和默认方法
* *
* @param beanClass * @param beanClass 或接口
* @param withSuperClassMethods 是否包括父类的方法列表 * @param withSupers 是否包括父类或接口的方法列表
* @return 方法列表 * @return 方法列表
* @throws SecurityException 安全检查异常 * @throws SecurityException 安全检查异常
*/ */
public static Method[] getMethodsDirectly(Class<?> beanClass, boolean withSuperClassMethods) throws SecurityException { public static Method[] getMethodsDirectly(Class<?> beanClass, boolean withSupers) throws SecurityException {
Assert.notNull(beanClass); Assert.notNull(beanClass);
if(beanClass.isInterface()){
// 对于接口直接调用Class.getMethods方法获取所有方法因为接口都是public方法
return withSupers ? beanClass.getMethods() : beanClass.getDeclaredMethods();
}
Method[] allMethods = null; Method[] allMethods = null;
Class<?> searchType = beanClass; Class<?> searchType = beanClass;
Method[] declaredMethods; Method[] declaredMethods;
while (searchType != null) { while (searchType != null && searchType != Object.class) {
declaredMethods = searchType.getDeclaredMethods(); declaredMethods = searchType.getDeclaredMethods();
if (null == allMethods) { if (null == allMethods) {
allMethods = declaredMethods; allMethods = declaredMethods;
} else { } else {
allMethods = ArrayUtil.append(allMethods, declaredMethods); allMethods = ArrayUtil.append(allMethods, declaredMethods);
} }
searchType = withSuperClassMethods ? searchType.getSuperclass() : null; searchType = (withSupers && false == searchType.isInterface()) ? searchType.getSuperclass() : null;
} }
return allMethods; return ArrayUtil.append(allMethods);
} }
/** /**

View File

@ -1,13 +1,15 @@
package cn.hutool.core.lang.test.bean; package cn.hutool.core.lang.test.bean;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects;
/** /**
* *
* @author 质量过关 * @author 质量过关
* *
*/ */
@Data
public class ExamInfoDict implements Serializable { public class ExamInfoDict implements Serializable {
private static final long serialVersionUID = 3640936499125004525L; private static final long serialVersionUID = 3640936499125004525L;
@ -18,49 +20,7 @@ public class ExamInfoDict implements Serializable {
// 试题是否作答 // 试题是否作答
private Integer answerIs; private Integer answerIs;
public Integer getId() {
return id;
}
public Integer getId(Integer defaultValue) { public Integer getId(Integer defaultValue) {
return this.id == null ? defaultValue : this.id; return this.id == null ? defaultValue : this.id;
} }
public void setId(Integer id) {
this.id = id;
}
public Integer getExamType() {
return examType;
}
public void setExamType(Integer examType) {
this.examType = examType;
}
public Integer getAnswerIs() {
return answerIs;
}
public void setAnswerIs(Integer answerIs) {
this.answerIs = answerIs;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ExamInfoDict that = (ExamInfoDict) o;
return Objects.equals(id, that.id) && Objects.equals(examType, that.examType) && Objects.equals(answerIs, that.answerIs);
}
@Override
public int hashCode() {
return Objects.hash(id, examType, answerIs);
}
@Override
public String toString() {
return "ExamInfoDict{" + "id=" + id + ", examType=" + examType + ", answerIs=" + answerIs + '}';
}
} }

View File

@ -116,7 +116,7 @@ public class ReflectUtilTest {
@Ignore @Ignore
public void getMethodBenchTest(){ public void getMethodBenchTest(){
// 预热 // 预热
getMethod(TestBenchClass.class, false, "getH"); getMethodWithReturnTypeCheck(TestBenchClass.class, false, "getH");
final TimeInterval timer = DateUtil.timer(); final TimeInterval timer = DateUtil.timer();
timer.start(); timer.start();
@ -127,7 +127,7 @@ public class ReflectUtilTest {
timer.restart(); timer.restart();
for (int i = 0; i < 100000000; i++) { for (int i = 0; i < 100000000; i++) {
getMethod(TestBenchClass.class, false, "getH"); getMethodWithReturnTypeCheck(TestBenchClass.class, false, "getH");
} }
Console.log(timer.interval()); Console.log(timer.interval());
} }
@ -150,7 +150,7 @@ public class ReflectUtilTest {
private String n; private String n;
} }
public static Method getMethod(Class<?> clazz, boolean ignoreCase, String methodName, Class<?>... paramTypes) throws SecurityException { public static Method getMethodWithReturnTypeCheck(Class<?> clazz, boolean ignoreCase, String methodName, Class<?>... paramTypes) throws SecurityException {
if (null == clazz || StrUtil.isBlank(methodName)) { if (null == clazz || StrUtil.isBlank(methodName)) {
return null; return null;
} }
@ -169,4 +169,61 @@ public class ReflectUtilTest {
} }
return res; return res;
} }
@Test
public void getMethodsFromClassExtends(){
// 继承情况下需解决方法去重问题
final Method[] methods = ReflectUtil.getMethods(C2.class);
Assert.assertEquals(2, methods.length);
}
@Test
public void getMethodsFromInterfaceTest(){
// 对于接口直接调用Class.getMethods方法获取所有方法因为接口都是public方法
// 因此此处得到包括TestInterface1TestInterface2TestInterface3中一共4个方法
final Method[] methods = ReflectUtil.getMethods(TestInterface3.class);
Assert.assertEquals(4, methods.length);
// 接口里调用getMethods和getPublicMethods效果相同
final Method[] publicMethods = ReflectUtil.getPublicMethods(TestInterface3.class);
Assert.assertArrayEquals(methods, publicMethods);
}
interface TestInterface1{
void getA();
void getB();
default void getC(){
}
}
interface TestInterface2 extends TestInterface1{
@Override
void getB();
}
interface TestInterface3 extends TestInterface2{
void get3();
}
class C1 implements TestInterface2{
@Override
public void getA() {
}
@Override
public void getB() {
}
}
class C2 extends C1{
@Override
public void getA() {
}
}
} }