Java yansımasında getFields ve getDeclaredFields arasındaki fark nedir


195

Java yansıması kullanırken getFieldsyöntem ve yöntem arasındaki fark hakkında biraz kafam karıştı getDeclaredFields.

getDeclaredFieldsSınıfın tüm alanlarına erişmenizi sağlayan ve getFieldsyalnızca ortak alanları döndüren okudum . Eğer durum buysa, neden her zaman kullanmıyorsunuz getDeclaredFields?

Birisi lütfen bunu ayrıntılı olarak açıklayabilir ve iki yöntem arasındaki farkı ve ne zaman / neden birini diğerinin üzerinde kullanmak isteyeceğinizi açıklayabilir mi?


3
getFieldüst sınıftan devralınan bir alanı alabilir, ancak getDeclaredFieldalamaz. getDeclaredFieldkendisini işlevi çağırdığınız sınıfla sınırlandırır.
user2336315

@ user2336315 doğru, ancak getFieldözel üyelere erişemiyor
Madbreaks

Yanıtlar:


258

getFields ()

Tüm publicalanlar tüm sınıf hiyerarşisinde yukarı çıkar.

getDeclaredFields ()

Erişilebilirliklerine bakılmaksızın, yalnızca geçerli sınıf için olan tüm alanlar, geçerli sınıfın miras alabileceği temel sınıflar için geçerli değildir.

Tüm alanları hiyerarşiye çıkarmak için aşağıdaki işlevi yazdım:

public static Iterable<Field> getFieldsUpTo(@Nonnull Class<?> startClass, 
                                   @Nullable Class<?> exclusiveParent) {

   List<Field> currentClassFields = Lists.newArrayList(startClass.getDeclaredFields());
   Class<?> parentClass = startClass.getSuperclass();

   if (parentClass != null && 
          (exclusiveParent == null || !(parentClass.equals(exclusiveParent)))) {
     List<Field> parentClassFields = 
         (List<Field>) getFieldsUpTo(parentClass, exclusiveParent);
     currentClassFields.addAll(parentClassFields);
   }

   return currentClassFields;
}

exclusiveParentSınıf gelen alanların alınmasını önlemek için sağlanmıştır Object. nullEğer Objectalanları istiyorsan olabilir .

Lists.newArrayListAçıklığa kavuşturmak için Guava'dan geliyor.

Güncelleme

Bilginize, yukarıdaki kod benim de GitHub'dan yayınlanmaktadır LibEx projenin ReflectionUtils .


8
Harika bir cevap, ancak üst sınıflardaki özel alanların mevcut sınıf örnekleri Field#getve benzer yöntemler tarafından kullanılamayacağı belirtilmelidir. Başka bir deyişle, bu yaklaşım değildir tipik derleme yapmaz aynı şekilde, üst sınıfında özel arayüzüne cari sınıf erişime izin.
FThompson

4
@Vulcan Kod kapsamı değiştirmek için yansıma kullanmak üzere yazılmadıkça setAccessibleve yerinde Güvenlik Yöneticisi yoksa doğru
John B

Hafif nit, "(erişilebilirlik ne olursa olsun)" değil "(kapsam ne olursa olsun)" olmalıdır. Tüm alanlar aynı kapsama sahiptir, yani sınıfın gövdesi .
yshavit

@yshavit Teşekkürler. Güncellenmiş.
John B

1
Olmaz. Yana privatealanlar yalnızca erişilebilir aracılığıyla getDeclaredFieldshangi sınıf özeldir. Her alan (aynı tür ve adla bile) farklı Fieldörneklerdir.
John B

7

Daha önce de belirtildiği gibi, Class.getDeclaredField(String)sadece Classonu aradığınız alanlara bakar .

Bir aramak istiyorsanız Fieldde Classhiyerarşi, bu basit işlevi kullanabilirsiniz:

/**
 * Returns the first {@link Field} in the hierarchy for the specified name
 */
public static Field getField(Class<?> clazz, String name) {
    Field field = null;
    while (clazz != null && field == null) {
        try {
            field = clazz.getDeclaredField(name);
        } catch (Exception e) {
        }
        clazz = clazz.getSuperclass();
    }
    return field;
}

Bu, privateörneğin bir üst sınıftan bir alan bulmak için kullanışlıdır . Ayrıca, değerini değiştirmek isterseniz, değeri şu şekilde kullanabilirsiniz:

/**
 * Sets {@code value} to the first {@link Field} in the {@code object} hierarchy, for the specified name
 */
public static void setField(Object object, String fieldName, Object value) throws Exception {
    Field field = getField(object.getClass(), fieldName);
    field.setAccessible(true);
    field.set(object, value);
}

hiç bulunmazsa hala hata atmak için küçük bir değişikliktry try { field = clazz.getDeclaredField(name); } catch (NoSuchFieldException e) { clazz = clazz.getSuperclass(); if(clazz==null){ throw e; } }
Sven Dhaens

5

public Field[] getFields() throws SecurityException

Tüm erişilebilir ortak alanları yansıtan Alan nesnelerini içeren bir dizi döndürürBu Class nesnesi tarafından temsil edilen sınıfın veya arabirimin . Döndürülen dizideki öğeler sıralanmaz ve belirli bir sırada değildir. Sınıf veya arabirimin erişilebilir ortak alanları yoksa veya bir dizi sınıfını, ilkel türü veya boşluğu temsil ediyorsa, bu yöntem 0 uzunluğunda bir dizi döndürür.

Özellikle, bu Class nesnesi bir sınıfı temsil ediyorsa, bu yöntem döndürür bu sınıfın ve tüm üst sınıflarının ortak alanlarını . Bu Class nesnesi bir arabirimi temsil ediyorsa, bu yöntem bu arabirimin ve tüm üst düzeylerinin alanlarını döndürür.

Dizi sınıfı için örtük uzunluk alanı bu yöntemle yansıtılmaz. Kullanıcı kodu, dizileri işlemek için Array sınıfı yöntemlerini kullanmalıdır.


public Field[] getDeclaredFields() throws SecurityException

Bu Class nesnesi tarafından temsil edilen sınıf veya arabirim tarafından bildirilen tüm alanları yansıtan bir Field nesneleri dizisi döndürür . Bu , genel, korumalı, varsayılan (paket) erişimi ve özel alanları içerir, ancak devralınan alanları hariç tutar . Döndürülen dizideki öğeler sıralanmaz ve belirli bir sırada değildir. Sınıf veya arabirim alan bildirmezse veya bu Sınıf nesnesi ilkel bir türü, bir dizi sınıfını veya void'i temsil ediyorsa, bu yöntem 0 uzunluktaki bir diziyi döndürür.


Ve tüm üst sınıflardan tüm alanlara ihtiyacım olursa? Bazı kodlar gereklidir, örneğin https://stackoverflow.com/a/35103361/755804 adresinden :

public static List<Field> getAllModelFields(Class aClass) {
    List<Field> fields = new ArrayList<>();
    do {
        Collections.addAll(fields, aClass.getDeclaredFields());
        aClass = aClass.getSuperclass();
    } while (aClass != null);
    return fields;
}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.