Java: Почему нужно вводить cast для instanceof () в equals ()? Это для справки или меньше кода? - PullRequest
1 голос
/ 14 января 2020

Java newb ie здесь, у меня есть базовый c вопрос, на который наполовину отвечают предыдущие ответы в других темах или документах, но я все еще не до конца понимаю механизм и хочу быть уверенным Я рассматриваю основные принципы (код внизу, вопросы посередине).

По сути, я переопределяю метод equals (), чтобы проверить, имеют ли два объекта MyDate одинаковую дату. Я делаю экземпляр проверки, является ли объект o объектом MyDate, затем вы вводите объект temp специально для объекта MyDate o, а затем сравниваете даты. Почему вы вводите переменную temp в класс MyDate o, если он уже принадлежит классу MyDate?

  1. Используете ли вы переменную temp в качестве более простой ссылки на объект, который вы хотите запустить сравнение equals ()? Поскольку вы используете equals () для сравнения MyDate.equals(MyOtherDate), в коде, если я не назначу переменную для хранения ссылки, вы получите различные ошибки (temp не может быть разрешена как переменная, несоответствие типов, et c в основном компилятор не уверен, где искать, если вы не напишите больше кода).

2a. Некоторые из других потоков говорили что-то о том, что, хотя instanceof проверяет, является ли экземпляр классом, он проверяет класс base , но не проверяет подкласс. Вы выполняете приведение типов, потому что вы специально указываете компилятору проверять указанный объект c (приведение типа из общего объекта к указанному c объекту). ПРИМЕЧАНИЕ. Это может быть вопрос типа c с указанием версии и разновидности, я видел разные ответы на похожие вопросы.

2b. Приведение изменяет ссылку, а не сам объект. Таким образом, если объекты принадлежат к одному и тому же классу, но к разным подклассам, произойдет сбой во время выполнения, а не во время компиляции. И не получу ли я ClassCastException?

public boolean equals(Object o) {
            if (o instanceof MyDate) {
                MyDate temp = (MyDate) o;
                if ((temp.day == day) && (temp.month == month) && (temp.year == year)) {
                    return true;
                }
            } 
            return false;
        }

Ответы [ 2 ]

2 голосов
/ 14 января 2020

Java имеет две взаимосвязанные, но отдельные концепции: тип выражения и тип времени выполнения значения .

Эти понятия в некоторой степени совместимы; если выражение имеет тип MyDate, то при оценке этого выражения вы либо получаете ссылку на объект, тип времени выполнения которого равен либо MyDate, либо подкласс MyDate, либо вы получаете нулевую ссылку, либо вы получить исключение или бесконечность l oop или еще много чего. Но понятия разные, и даже когда ваши типы времени выполнения хороши, иногда вам нужно предоставить компилятору некоторую дополнительную информацию о типах.

> Почему вы вводите переменную temp в класс MyDate или когда он уже имеет класс MyDate?

Переменная o имеет тип Object, а не когда-либо типа MyDate. Он содержит ссылку на объект, чей тип времени выполнения равен MyDate (или подкласс MyDate), но это не влияет на тип o. Таким образом, вы пишете (MyDate)o, чтобы создать выражение с тем же значением (и, следовательно, с тем же типом времени выполнения) и желаемым типом.

Если бы компилятор был умнее, он мог бы, возможно, трактовать o как имеющий тип MyDate внутри вашего if заявления, так что вам не понадобится приведение; но текущая Java спецификация языка не позволяет этого. (И если это произойдет, это может иметь некоторые странные последствия, когда дело касается отправки метода stati c.)

1 голос
/ 14 января 2020

Компилятор Java не понимает класс типа вашего объекта "o" как MyDate. Это происходит потому, что вы получили параметр типа Object, поэтому он будет считан как объект. Чтобы получить доступ к методам и свойствам параметра известного типа MyDate, необходимо сообщить компилятору, что это объект типа MyDate. Именно так компилятор поймет, что вы делаете. Теперь давайте взглянем на другое представление.

Каждый тип в Java расширяет тип Object, что означает, что каждый раз, когда вы пишете класс, вы неявно расширяете Object public / protected свойства и поведение. Вот почему вы «переопределяете» метод equals, относящийся к типу Object. Хорошо, когда вы делаете сравнение между двумя объектами, вы должны сначала проверить, принадлежат ли они оба к одному и тому же типу, как вы сделали в своем примере с: if (o instanceof MyDate) { ... }, чтобы убедиться, что o имеет тип MyDate. Но в этот момент, поскольку вы не приводили «o» к типу «MyDate», вы не сможете получить доступ к указанным c свойствам или методам MyDate. Так что подумайте немного, если у меня есть класс A, который расширяет мой класс B, я смогу получить доступ к B publi c методам и свойствам внутри A, но я не могу сделать то же самое для B потому что Б не может видеть, что происходит на дереве. Ты следишь?

Надеюсь, я смогу ответить на твои сомнения.

...