Java 反射獲取父類的字段字: NoSuchFieldException

在開發(fā)中,經(jīng)常要存在需要將數(shù)據(jù)收集過來然后在內(nèi)存中進(jìn)行過濾,排序,分頁的情況。寫了一個過濾,排序,分頁的工具,結(jié)果發(fā)現(xiàn)有一些問題,下面來說下這個問題。

一、問題說明

先看下面一段代碼。排序時,自定義了一個比較器,通常情況下沒有問題。
但是,要是String paramType = o1.getClass().getDeclaredField(paramName).getGenericType().toString();語句中o1為一個繼承類,paramName為一個父類的成員變量,就會報異常:java.lang.NoSuchFieldException:XXX

Collections.sort(originList, new ParamComparator<T>(orderBy, order));



public int compare1(T o1, T o2) {
    if (paramName == null || paramName.isEmpty() || o1 == o2) {
        return 0;
    }

    String upperParamType = paramName.substring(0, 1).toUpperCase() + paramName.substring(1);
    try {
        String paramType = o1.getClass().getDeclaredField(paramName).getGenericType().toString();
        Method m = o1.getClass().getMethod("get" + upperParamType);
        int result;
        if (paramType.equals("class java.lang.String")) {
            String valueParam1 = (String) m.invoke(o1);
            String valueParam2 = (String) m.invoke(o2);
            if ((result = value(valueParam1, valueParam2)) != 0) {
                return result;
            } else {
                return isAscend ? valueParam1.compareTo(valueParam2) : valueParam2.compareTo(valueParam1);
            }
        } else if (paramType.equals("class java.util.Date")) {
            Date valueParam1 = (Date) m.invoke(o1);
            Date valueParam2 = (Date) m.invoke(o2);

            if ((result = value(valueParam1, valueParam2)) != 0) {
                return result;
            } else {
                return isAscend ? valueParam1.compareTo(valueParam2) : valueParam2.compareTo(valueParam1);
            }
        } else {
            return 0;
        }
    } catch (Exception ex) {
        log.warn("ParamComparator.compare Exception!");
        log.warn("paramName : '" + paramName + "', isAscend : " + isAscend + ", o1 : " + o1 + ", o2 : " + o2);
        ex.printStackTrace();
        return 0;
    }
}

二、問題定位:

JAVA 反射獲取不到父類中聲明的字段,但可以獲取到父類中聲明的方法。這樣可以獲取到父類中該字段的值。

三、問題解決

下面說一種解決方案,就是通過getSuperclass方法獲取父類再調(diào)用getDeclaredField方法

public int compare(T o1, T o2) {
    if (paramName == null || paramName.isEmpty() || o1 == o2) {
        return 0;
    }

    String upperParamType = paramName.substring(0, 1).toUpperCase() + paramName.substring(1);
    try {
        // String paramType = o1.getClass().getDeclaredField(paramName).getGenericType().toString();
        String paramType = getFiled(paramName, o1.getClass()).getGenericType().toString();
        Method m = o1.getClass().getMethod("get" + upperParamType);
        int result;
        if (paramType.equals("class java.lang.String")) {
            String valueParam1 = (String) m.invoke(o1);
            String valueParam2 = (String) m.invoke(o2);
            if ((result = value(valueParam1, valueParam2)) != 0) {
                return result;
            } else {
                return isAscend ? valueParam1.compareTo(valueParam2) : valueParam2.compareTo(valueParam1);
            }
        } else if (paramType.equals("class java.util.Date")) {
            Date valueParam1 = (Date) m.invoke(o1);
            Date valueParam2 = (Date) m.invoke(o2);

            if ((result = value(valueParam1, valueParam2)) != 0) {
                return result;
            } else {
                return isAscend ? valueParam1.compareTo(valueParam2) : valueParam2.compareTo(valueParam1);
            }
        } else {
            return 0;
        }
    } catch (Exception ex) {
        log.warn("ParamComparator.compare Exception!");
        log.warn("paramName : '" + paramName + "', isAscend : " + isAscend + ", o1 : " + o1 + ", o2 : " + o2);
        ex.printStackTrace();
        return 0;
    }
}


public static Field getFiled(String tar, Class clazz) {
    String error = null;
    Field field = null;
    while (clazz != null) {
        try {
            field = clazz.getDeclaredField(tar);
            error = null;
            break;
        } catch (Exception e) {
            clazz = clazz.getSuperclass();
            error = e.getMessage();
        }
    }
    if (error != null || field == null) {
        throw new RuntimeException("無法獲取源字段:" + tar);
    }
    return field;
}

四、知識點:

  1. getField vs getDeclaredField
    getField用于返回一個指定名稱的屬性,但是這個屬性必須是公有的這個屬性可以在父類中定義。如果是私有屬性或者是保護(hù)屬性,那么都會拋出異常提示找不到這個屬性; getDeclaredField獲得在這個類型的聲明中定義的指定名稱的屬性,這個屬性必須是在這個類型的聲明中定義,但可以使私有和保護(hù)的。

五、參考

【1】java反射獲取父類和子類字段值、賦值
【2】JAVA 反射獲取不到父類中聲明的字段,但可以獲取到父類中聲明的方法

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容