Почему импорт класса не требуется при вызове метода в экземпляре (Java)
Что-то меня смутило - пример:
Thing.java:
import java.util.Date;
class Thing {
static Date getDate() {return new Date();}
}
(тот же пакет) TestUsesThing.java:
// not importing Date here.
public class TestUsesThing {
public static void main(String[] args) {
System.out.println(Thing.getDate().getTime()); // okay
// Date date = new Date(); // naturally this wouldn't be okay
}
}
Почему нет необходимости импортировать Date, чтобы иметь возможность называть getTime() на одном из них?
Ответы
Ответ 1
Импорт в Java необходим только потому, что компилятор знает, что такое Date
, если вы введете
Date date = new Date();
Импорт не похож на #include
в C/С++; все типы на пути к классам доступны, но вы import
просто не должны писать полное имя. И в этом случае это не нужно.
Ответ 2
Хороший вопрос!!
Я думаю, что результат заключается в различии между тем, как java-компилятор обрабатывает выражения против операторов.
Date d = new Date(); // a statement
где as
new Thing().getDate().getTime()
- это выражение, которое встречается внутри вызова метода println. Когда вы вызываете getDate в новом Thing(), компилятор пытается обработать выражение, просмотрев информацию типа для класса Thing, где он получает объявление типа Date.
Но когда вы пытаетесь использовать Date отдельно в инструкции типа
Date d = new Thing().getDate();
вы назначаете результат типу в текущей области (класс TestUsesThing), компилятор пытается разрешить тип внутри этой области. В результате вы видите ошибку компилятора для неизвестного типа.
Ответ 3
Есть ли Thing и TestUsesThing в одном пакете? Если это так, вам не нужно импортировать Thing. Причина, по которой вам нужно импортировать Date, заключается в том, что она находится в другом пакете.
Ответ 4
Операторы import
используются для нескольких вещей.
- Проверка типа компилятора и предотвращение столкновения имен.
- Обеспечивает привязку байтового кода.
Всякий раз, когда мы говорим
System.out.println( new Thing().getDate().getTime() )
Компилятор анализирует это выражение слева направо и попадает в этот класс.
Разбор компилятора первого уровня.
- Перейти к классу предметов
-
Компиляция не имеет никакой связи или ошибки ClassVersion от Thing.class
- Check Thing.class имеет метод getDate.
- Если # 3 хорошо, то указатель компилятора все еще находится в Thing.class(который имеет инструкции импорта даты), и я мог бы вызвать метод Time.
-
Как потребитель TestUsesThing получает только длинную переменную.
System.out.println( new Thing().getDate() )
5.1 В этом случае мы неявно обращаемся к методу .toString()
Ответ 5
На самом деле это был идеальный пример, так как существуют два разных стандартных класса Java Date: java.util.Date и java.sql.Date.
Как узнать, какой из них использовать? Просто. Метод getDate() объявляется как часть определения класса Thing, а частью этого объявления является его возвращаемый тип:
public java.util.Date getDate() {
return this.date;
}
Конечно, если у вас есть импорт в определении класса Thing - и он не является двусмысленным, вы просто говорите:
public Date getDate() {
Если вы должны были декодировать двоичный файл класса Thing, вы увидите подпись метода метода getDate и включаете полное имя класса (включая пакет) возвращаемого типа.
import - это просто способ сообщить компилятору, какие пакеты вы хотите использовать при обращении к классам без явной квалификации. Список импорта будет проверяться всякий раз, когда будет видно неквалифицированное имя класса, и пакеты будут найдены. Если нет двусмысленности (например, импортирования java.util.date и java.sql.Date), этот класс будет использоваться. Если вы можете определить класс неявно или если имя класса полностью квалифицировано, вам не нужно импортировать.