Yansıma genel alan değeri alın


132

Yansıma yoluyla alan değeri almaya çalışıyorum. Sorun şu ki, alanların türünü bilmiyorum ve değeri alırken buna karar vermem gerekiyor.

Bu kod, bu istisna ile sonuçlanır:

Java.lang.String alanı com .... fieldName java.lang.String olarak ayarlanamıyor

Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);

Class<?> targetType = field.getType();
Object objectValue = targetType.newInstance();

Object value = field.get(objectValue);

Yayınlamayı denedim, ancak derleme hataları alıyorum:

field.get((targetType)objectValue)

veya

targetType objectValue = targetType.newInstance();

Bunu nasıl yapabilirim?


4
API'ye bakıldığında, field.get()olması gereken argüman objectdeğil objectValue.
akaIDIOT

Yanıtlar:


144

Daha önce cevaplandığı gibi, şunları kullanmalısınız:

Object value = field.get(objectInstance);

Bazen tercih edilen başka bir yol da alıcıyı dinamik olarak çağırmaktır. örnek kod:

public static Object runGetter(Field field, BaseValidationObject o)
{
    // MZ: Find the correct method
    for (Method method : o.getMethods())
    {
        if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3)))
        {
            if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
            {
                // MZ: Method found, run it
                try
                {
                    return method.invoke(o);
                }
                catch (IllegalAccessException e)
                {
                    Logger.fatal("Could not determine method: " + method.getName());
                }
                catch (InvocationTargetException e)
                {
                    Logger.fatal("Could not determine method: " + method.getName());
                }

            }
        }
    }


    return null;
}

Ayrıca, sınıfınız başka bir sınıftan miras aldığında, Alanı yinelemeli olarak belirlemeniz gerektiğini unutmayın. örneğin, belirli bir sınıfın tüm Alanlarını getirmek için;

    for (Class<?> c = someClass; c != null; c = c.getSuperclass())
    {
        Field[] fields = c.getDeclaredFields();
        for (Field classField : fields)
        {
            result.add(classField);
        }
    }

1
kendi başınıza süper sınıfları yinelemeniz gerektiği tam olarak doğru değil gibi görünüyor. C.getFields () veya c.getField (), her uygulama arabirimindeki alanı otomatik olarak ve tüm üst sınıflarda özyinelemeli olarak arayacaktır. Yani getDeclaredX'ten getX'e geçmek yeterlidir.
Przemysław Ładyński

3
Aslında, getFields () rutini, tüm süper sınıflar ve arayüzler için alanları getirmenize izin verir, ancak yalnızca genel olanlar. Genellikle alanlar özel / korumalı yapılır ve alıcılar / ayarlayıcılar aracılığıyla açığa çıkarılır.
Marius

@Marius, paketin ne olduğunu öğrenebilir BaseValidationObjectmiyim?
randytan

@Randytan, benim özel kod depomda yer alıyor, bunu Object ile değiştirebilirsiniz. Aynısı statik Logger çağrıları için de geçerlidir, bunları kendi kaydedicinizle (örnek) değiştirin.
Marius

@Marius object sınıfın yöntemi yok getMethods(). Herhangi bir tavsiye?
randytan

127

Sen geçmelidir nesne için olsun yöntemini alanında böylece,

  Field field = object.getClass().getDeclaredField(fieldName);    
  field.setAccessible(true);
  Object value = field.get(object);

6
field.get (object) 'de nesnenin neden kullanılması gerektiğini biliyor musunuz - alanın kendisi o nesneden geliyor, neden ona tekrar ihtiyacı var!?
serup

19
@serup Hayır, Field nesnesi, gerçek örneğinizle bağlantısı olmayan Class nesnesinden gelir. ( object.getClass()size bu Sınıf nesnesini döndürür)
Dmitry Spikhalskiy

1
objectpasajda tanımlanmamıştır, bu nedenle okuyucular onu nasıl kullanacaklarını anlayamazlar.
Ghilteras

@Ghilteras bu durumda, henüz düşünme kullanmamalı ve önce bazı temel becerileri edinmeli 🤷🏻‍♂️. Yansıma, bir değişkenin birlikte objectçalıştığımız hedef nesnemiz / örneğimiz anlamına geldiğini açıklamayacak kadar gelişmiş bir konudur . Okurların aslında objectbu cevabın ne olduğu konusunda tamamen iyi olduğunu düşünüyorum .
Dmitry Spikhalskiy

@RajanPrasad Pek değil. Soruda 'nesne' adı olan tek bir nesne var. Diğer nesnelerin başka isimleri vardır. Cevap kesin ve sorulara ve soruları olabildiğince açık hale getirmek için soruda kullanılan isimler için uygun hale getirildi. Sizin için işe yaramazsa - nasıl daha net hale getirebileceğime dair hiçbir fikrim yok ve başka yanıtları denemelisiniz ya da henüz derinlemesine düşünmekten kaçınmalısınız.
Dmitry Spikhalskiy

19

Sınıf üyelerini ve değerleri görmek için (basit ve hızlı hata ayıklama) tercih sınıfımın toString () uygulamasındaki yansımaları kullanıyorum.

Kullandığım basitleştirilmiş kod:

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();

    Class<?> thisClass = null;
    try {
        thisClass = Class.forName(this.getClass().getName());

        Field[] aClassFields = thisClass.getDeclaredFields();
        sb.append(this.getClass().getSimpleName() + " [ ");
        for(Field f : aClassFields){
            String fName = f.getName();
            sb.append("(" + f.getType() + ") " + fName + " = " + f.get(this) + ", ");
        }
        sb.append("]");
    } catch (Exception e) {
        e.printStackTrace();
    }

    return sb.toString();
}

Umarım birine yardımcı olur, çünkü ben de araştırdım.


12

Neyi başarmaya çalıştığınız benim için gerçekten açık olmasa da, kodunuzda bariz bir hata tespit ettim: Field.get()alanı argüman olarak içeren nesneyi, o alanın bir (olası) değerini değil. Yani yapmalısın field.get(object).

Alan değerini arıyor göründüğünüz için, bunu şu şekilde elde edebilirsiniz:

Object objectValue = field.get(object);

Alan türünü somutlaştırmaya ve bazı boş / varsayılan değerler oluşturmaya gerek yoktur; ya da belki kaçırdığım bir şey var.


2
objecttanımlanmamışsa okuyucular cevabın nasıl uygulanacağını anlayamaz.
Ghilteras

10
 Integer typeValue = 0;
 try {
     Class<Types> types = Types.class;
     java.lang.reflect.Field field = types.getDeclaredField("Type");
     field.setAccessible(true);
     Object value = field.get(types);
     typeValue = (Integer) value;
 } catch (Exception e) {
     e.printStackTrace();
 }

4

Yanlış argümanla anlaşmak istiyorsun.

Olmalı:

Object value = field.get(object);

2
objecttanımlı değil, okuyucular
yanıttaki

2

Çözümümü Kotlin'de yayınlıyorum, ancak java nesneleriyle de çalışabilir. Herhangi bir nesnenin bu işlevi kullanabilmesi için bir işlev uzantısı oluşturuyorum.

fun Any.iterateOverComponents() {

val fields = this.javaClass.declaredFields

fields.forEachIndexed { i, field ->

    fields[i].isAccessible = true
    // get value of the fields
    val value = fields[i].get(this)

    // print result
    Log.w("Msg", "Value of Field "
            + fields[i].name
            + " is " + value)
}}

Bu web sayfasına bir göz atın: https://www.geeksforgeeks.org/field-get-method-in-java-with-examples/


1
    ` 
//Here is the example I used for get the field name also the field value
//Hope This will help to someone
TestModel model = new TestModel ("MyDate", "MyTime", "OUT");
//Get All the fields of the class
 Field[] fields = model.getClass().getDeclaredFields();
//If the field is private make the field to accessible true
fields[0].setAccessible(true);
//Get the field name
  System.out.println(fields[0].getName());
//Get the field value
System.out.println(fields[0].get(model));
`
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.