Отражение Java: приведение Integer из поля класса - PullRequest
0 голосов
/ 02 октября 2019

Я недавно столкнулся со следующей ошибкой, которая действительно смущает меня. Я импортировал отражать. У меня есть класс (называемый работником) с полем, которое является частным int под названием numOfJobs. В конструкторе Worker для numOfJobs задано значение 0. Затем в классе тестера я создаю экземпляр типа worker:

    waterBenders[0] = new Worker();
    Field []fields = waterBenders[0].getClass().getDeclaredFields();
    Field privateFieldJobs = fields[0];
    privateFieldJobs.setAccessible(true);

    try{

          System.out.println(privateFieldJobs.get(waterBenders[0]));

          System.out.println(privateFieldJobs.get(waterBenders[0]).getClass());

          System.out.println((int)privateFieldJobs.get(waterBenders[0]));
    }

Это третья строка в поле try, содержащая ошибку,Первые две строки выведите:

    0    
    class java.lang.Integer

Это имеет смысл для меня. Однако если объект privateFieldJobs.get (waterBenders [0]) является объектом типа Integer со значением «0», то почему (int) privateFieldJobs.get (waterBenders [0]) выдает ошибку:

    Cannot cast from java.lang.Object to int

Если бы я должен был создать обычный объект типа Integer, то этот тип приведения обычно работает. Что такого особенного в этом примере? Я предполагаю, что это как-то связано с тем фактом, что этот объект Integer происходит из массива fields.

Мой рабочий класс по сути:

    public class Worker extends Unit{
      private int numOfJobs;

      public Worker(Tile position, double hp, String faction) {
        super(position, hp, 2, faction);   
        this.numOfJobs = 0;
      }

      public int getNumOfJobs(){
        return this.numOfJobs;
      }
    }

Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

2 голосов
/ 02 октября 2019

Обычно вы пытаетесь это сделать:

Integer i=1;
Object o=i;
int val=(int)o;

У него нет причин работать, поэтому он не работает.

Либо приведите его обратно к Integer (как вы видите, это не обязательно для println, так как в любом случае вызывается правильный toString(), но это необходимо для распаковки), или вы можете попробовать использовать getInt():

int val1=(Integer)privateFieldJobs.get(waterBenders[0]);
int val2=privateFieldJobs.getInt(waterBenders[0]);


Ну, я был неправ в отношении последнего: хотя оба они работают на int, но getInt() не работает на Integer:
import java.lang.reflect.*;

class Ideone {
    public Integer objInt=23;
    public int valInt=42;

    public static void main (String[] args) throws java.lang.Exception {
        Field objField=Ideone.class.getField("objInt");
        Field valField=Ideone.class.getField("valInt");

        Ideone test=new Ideone();

        System.out.print("objInt-get: ");
        System.out.println(objField.get(test));

        System.out.print("objInt-getInt: ");
        try{
            System.out.println(objField.getInt(test));
        } catch (Exception ex) {
            System.out.println(ex.getClass());
        }

        System.out.print("valInt-get: ");
        System.out.println(valField.get(test));

        System.out.print("valInt-getInt: ");
        System.out.println(valField.getInt(test));
    }
}

(классназывается Ideone, потому что его можно попробовать там: https://ideone.com/91xzmc)
Выход:

objInt-get: 23
objInt-getInt: class java.lang.IllegalArgumentException
valInt-get: 42
valInt-getInt: 42

Таким образом, можно использовать как get(), так и getInt() наint поле, но если поле Integer, только get работает (магия ex.getClass() сводится к сокращению сообщения, по умолчанию есть длинное объяснение, которое не помещается в строку).

Примечание: использование числовых классов, таких как Integer, означает создание объектов в куче (что может добавить к фрагментации кучи и может сделать дополнительную работу для сбора мусора). р). Если вам конкретно не нужно, чтобы число было null -пригодным или являлось объектом по какой-либо другой причине (это может понадобиться некоторым экзотическим сериализаторам), используйте int. Он быстрее, легче и короче, а также не требует нажатия Shift (для I).

2 голосов
/ 02 октября 2019

Это потому, что Field # get возвращает Object, и вы не можете привести любой тип Object к примитивному типу в java. Если вы хотите примитивное целочисленное значение от объекта Integer, вы можете сделать что-то вроде этого

Integer field = (Integer) privateFieldJobs.get(waterBenders[0]);
int value = field.intValue();
...