mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix bug
This commit is contained in:
parent
62fd367fc4
commit
9229eea85f
@ -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)
|
||||||
|
@ -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 “与”之后的修饰符
|
||||||
*/
|
*/
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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 + '}';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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方法
|
||||||
|
// 因此此处得到包括TestInterface1、TestInterface2、TestInterface3中一共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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user