У меня есть класс Element<T>, содержащий T и int:

class Element<T>{
    T obj;
    int i;
    // ...
}

Когда T не хранится, я хотел бы использовать obj как указатель на элемент или индекс:

obj = someElement;
obj = indexOf(someElement); 

Конечно, я не могу этого сделать, потому что в Java нет объединений или вариантов (как в вариантах C ++) и есть строгая система типов.

Обратите внимание, что я хотел бы иметь доступ к элементу через obj, но у меня нет желания изменять его через obj, если это поможет.

Вопросов:

  1. Есть ли способ добиться этого, не создавая свой собственный вариантный класс или не устанавливая его?
  2. Если да, то какой способ сделать это наиболее эффективно с точки зрения памяти, поскольку мне нужно будет создать много элементов?
2
Captain Hatteras 14 Окт 2021 в 22:26

2 ответа

Лучший ответ

Маленькая проблема концептуальна. Объект в java - это просто некоторая память в куче и ее «адрес», который хранится в вашем поле объекта.

class MyUnion {
    Object any;
}

MyUnion u = new MyUnion();
u.any = "hello";
u.any = Integer.valueOf(13);

Вышеупомянутая конструкция представляет собой объединение «адресов», а не данных.

Ближайшим к объединению является байтовый массив, заключенный в ByteBuffer.

ByteBuffer u = ByteBuffer.allocate(8);
u.putDouble(0, 3.14);
long x = u.getLong(0);

Для реального объекта их нужно "сериализовать" в некоторой форме:

String obj = "Ĉeĥoslovakio";
byte[] b = obj.getBytes(StandardCharsets.UTF_8);
u.putInt(b.length);
u.put(b);

Для сложных двоичных данных можно использовать ASN или любой другой систематический метод.

Так что это концептуально. У вас нет объектов, размещенных в стеке (некоторые JVM делают это скрытно), и: объекты являются косвенными .

1
Joop Eggen 14 Окт 2021 в 19:46

Один из способов приблизиться к этому - использовать интерфейс или суперкласс с наследованием.

Например, если бы у нас был следующий интерфейс Java:

 interface Element<T> {
     T getValue();
 }

Тогда любой класс, реализующий интерфейс Element, должен будет предоставить метод, возвращающий значение элемента.

Мы могли бы реализовать класс, который хранит объект типа T и возвращает его:

 class ElementObject<T> implements Element<T> {

     private T object;

     T getValue() {
         return object;
     }
  }

Или мы могли бы реализовать класс, который хранит индекс и использует его (вместе с некоторым большим списком объектов):

 class ElementIndex<T> implements Element<T> {

     private int index;

     T getValue() {
         return bigListOfObjects.get(index);
     }
  }

Теперь вы можете создать список или массив или Element, и некоторые из них могут быть ElementObject, а некоторые могут быть ElementIndex, но они оба будут предоставлять доступ к элементу по желанию, без каких-либо потраченных впустую полей ни в одном из них.

1
Andrew Merrill 14 Окт 2021 в 20:06