Начальный массив объектов Путаница

У меня возникли проблемы с пониманием того, что на самом деле происходит, когда я объявляю массив в следующем коде.

class Type1 {

}

class Type2 extends Type1 {
    public void method2() {

    }
}

class Test {
    public static void main(String[] args) {

        Type1[] x = new Type2[2];
        x[0] = new Type1(); // runtime error
        x[1] = new Type2();
        x[1].method2(); // syntax error

    }
}

Я думал, поскольку правая часть объявления массива является new Type2[2] что массив будет состоять из ссылочных переменных типа Type2. Если это так, первая ошибка имеет смысл, потому что у меня нет подтипа, относящегося к супертипу.

Однако почему вторая ошибка возникает после двух строк? Разве method2() известен по типу 2, поэтому метод известен ссылочной переменной? Кажется, это потому, что Type1 не знает method2, значит, это означает, что массив состоит из ссылочных переменных типа Type1? Если это так, то почему возникает первая ошибка, поскольку она больше не является подтипом, относящимся к супертипу?

Кроме того, почему первая ошибка является ошибкой во время выполнения, а другая - синтаксической ошибкой?

Пожалуйста, обратите внимание, что я только на своем втором курсе программирования, поэтому моя терминология может быть немного отключена.

Изменение: вопрос здесь не отвечает на мой вопрос, потому что он не отвечает, почему элемент массива типа x не может вызвать method2() хотя элемент x Type 2. Мой вопрос отличается из-за этого и потому, что в моем вопросе также спрашивается, почему первая ошибка возникает при возникновении второй ошибки (почему элемент x не может ссылаться и объект типа Type1 и в то же время не может вызвать method2()), Первоначально я думал, что если произошла одна ошибка, другая не может произойти. Я хотел сравнить между двумя ошибками и более подробное объяснение, чем просто правила полиморфизма.

Ответ 1

Это одна из тех странных вещей, которые позволяет Java, назначая массив производного класса переменной массива базового класса.

В вашем коде x во время компиляции имеет тип Type1[]. Это то, что думает компилятор. Во время выполнения x имеет тип Type2[], но компилятор этого не знает.

Первая ошибка возникает во время выполнения, поскольку, как вы сказали, вы не можете назначать Type1 переменной типа Type2.

Но вторая ошибка возникает во время компиляции, потому что компилятор все еще считает, что x имеет тип Type1, и нет метода под названием method2 в Type1, хотя x фактически содержит Type2[] во время выполнения.

Чтобы вызвать method2, вам нужно сообщить компилятору, что x[1] имеет тип Type2 путем кастинга:

((Type2)x[1]).method2();

Урок дня? Не делайте этого:

Superclass[] array = new Subclass[2];

Вы попадете в беду.

Ответ 2

Ссылка на супертип может относиться к подтипу. Я думаю, вы понимаете это, поскольку первая ошибка является последовательной для вас.

Вторая ошибка связана с тем, что во время компиляции x по-прежнему является Type1[]. Это означает, что во время выполнения ссылка может содержать любой подтип, включая тип, который не имеет метода method2. Вот почему вы можете использовать только методы, определенные в Type1.

Например, вы можете проверить, действительно ли тип является Type2 во время выполнения, используя isInstanceOf, а затем отбрасывает его в Type2 и затем использует method2. Однако, как правило, есть лучшие решения.

Ответ 3

чтобы поставить его в непрофессионалы для нижеприведенного кода,

Type1[] x = new Type2[2];

давайте просто возьмем Type1 x = new Type2; а не массивы, просто классы.

Что вы делаете на этом этапе?

Здесь x является ссылочной переменной. Мы создаем объект "Type2", и x имеет ссылку Object Type2 [позволяет просто сказать, x - это удаленный элемент управления, указывающий на объект Type2). Не забывайте, что x имеет тип "Type1", что означает, что на пульте дистанционного управления нет кнопки "method2()". [Помните, метод2 относится к классу Type2 не Type1].

Компилятор вызывает метод для объекта, только когда он видит его внутри класса. компилятор не заботится о том, какой объект вы создаете [здесь: новый Type2], все, что он заботит, это то, на кого вы делаете вызов (здесь: x [1], который имеет тип Type1). Таким образом, он выдает ошибку времени компиляции. Он не беспокоится о том, что происходит во время выполнения или на каком объекте он указывает, все, что ему нужно, - это если у ссылочного типа есть метод вызова или нет. [В нашей терминологии, имеет ли пульт ДУ эта кнопка]? ,

почему первая ошибка является ошибкой во время выполнения, а другая - синтаксической ошибкой?

Я надеюсь, что приведенное выше объяснение (когда вы рассматриваете типы Array по вашему вопросу) отвечает на вашу вторую половину вопроса.

И, что касается первой части, вы в значительной степени ответили на нее. Как бы то ни было, дело в том, что массивы допускают такие вещи и взрываются в Runtime, тогда как Arraylist делает это во время компиляции. [Это часть Generics].

Как вы сказали, вы новичок в этом, вот моя ссылка для вас.

Ссылка:

Первая глава Java