Тип объекта в Java и ссылки на массивы

public class RefMix {
  public static void main(String[] args) {
    Object[] a = {null, "foo"};
    Object[] b = {"bar", b};
    a[0] = b;

    System.out.println(a[0][0]);
  }
}

Я понимаю, что массивы являются объектами в Java и, следовательно, являются подклассом типа Object. Мое дальнейшее понимание заключается в том, что 2-мерный массив реализуется как массив ссылок на массивы. Поэтому я не понимаю, почему мой a [0] [0] не создает bar в приведенном выше коде. Вместо этого он не компилируется:

RefMix.java:7: array required, but java.lang.Object found

Ответы

Ответ 1

Я понимаю, что массивы являются объектами в Java и, следовательно, являются подклассом типа Object. Мое дальнейшее понимание заключается в том, что 2-мерный массив реализуется как массив ссылок на массивы.

Это все правильно и объясняет, почему вы можете выполнить назначение

a[0] = b;

без каких-либо жалоб от компилятора.

Поэтому я не понимаю, почему мой a [0] [0] не создает бар в приведенном выше коде.

Хорошо, давайте взглянем на типы в этом выражении:

  • a - это Object[] - массив из Object s
  • a[0] - это Object
  • a[0][0] - Теперь вы пытаетесь использовать индекс массива на Object. Компилятор не знает, что Object на самом деле является массивом, поэтому он жалуется.

Ответ 2

Тип среды выполнения экземпляра объекта отличается от статически выводимого типа. Компилятор попытается оценить, какой тип каждой переменной может быть в программе, чтобы рано поймать определенные типы ошибок. В этом случае a[0] всегда будет массивом, но компилятор этого не знает. Поскольку вы получаете объект из массива объектов, все компиляторы знают, что a[0] является объектом. Поэтому он вызывает ошибку.

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

System.out.println(((Object[])a[0])[0]);

Ответ 3

Вы правы, массивы всегда Objects в Java, но Objects не всегда являются массивами, поэтому вы получаете ошибку компиляции, потому что a является Object[] (одномерным). Вы не можете получить доступ к

a[0][0];

потому что a не является двумерным массивом (по крайней мере, он не объявлен как таковой). Однако в этом случае вы уверены, что a[0] представляет собой массив Objects. Поэтому вы можете сделать это:

Object[] c = (Object[]) a[0];
System.out.println(c[0]);
// or directly:
System.out.println(((Object[])a[0])[0]);

Этот передает возвращаемый тип a[0] (который является Object) в Object[], и вы можете получить доступ к "второму слою" массива.

Ответ 4

Поскольку массив в Java является объектом, поэтому первое и второе назначение будут хранить ваш массив как 1-й элемент вашего массива объектов.

Object[] a = {null, "foo"};
Object[] b = {"bar", b};

Теперь вы изменили свой 1-й элемент массива объектов a, чтобы содержать значение b вместо массива. Но так как это массив объекта. Все, что выходит из него, будет объектом.

Так как a [0] - объект. Таким образом, вы явно не можете получить доступ к чему-то вроде этого: -

System.out.println(a[0][0]);

Вы можете попытаться привести ваш объект к объекту в массив [0]: -

System.out.println(((Object[])a[0])[0]);

Ответ 5

делать:

System.out.println(((Object[])a[0])[0]);

Это будет "бросать" объект в массив объектов во время выполнения.

Ответ 6

Поскольку в последнее время я много кодирую С++, я обнаружил, что Java гораздо более строг в проверке типов, чем С++. Java видит все, кроме примитивных типов, как Object, но Java делает еще один шаг к тому, чтобы различать типы Array и non-Array. Во время присваивания типа "a [0] = b;", Java сначала проверяет, является ли это типом массива или нет, после чего проходит обычную процедуру проверки полиморфного типа. Если вы хотите, чтобы ваш код работал, вы должны сделать...

Object[][] a = {{null}, {"foo"}};
Object[] b = {"bar", new java.util.Date()};
a[0] = b;

Вы можете увидеть, как java уделяет особое внимание массивам, просматривая подпись Java Class, которая передается классу Class.forName() в качестве параметра. Например, тип данных..

com.foo.Bar[][] barsIn2D;

может быть загружена подписи ниже...

// [ => Array
// [[ => Array of Array type
// L<object>; => Object, not Array
Class.forName("[[Lcom/foo/Bar;");

Как видите, подпись начинается с '[' или 'L'. Это говорит нам, имеет ли его массив или нет приоритет над "Lcom/foo/Bar;".

Ответ 7

Все, что вы делаете, эквивалентно этому

Object a = {"bar", "foo"};
System.out.println(a[0]);

который тоже не компилируется.