2013-02-19 2 views
4

В чем разница между временем компиляции и временем выполнения любого объекта в Java? Я читаю книгу Effective Java, и Джошуа Блох упоминает о типах времени компиляции и типах времени выполнения экземпляров массива в пункте 26 много раз, главным образом для описания того, что подавление предупреждений о броске может быть безопасным иногда.В чем разница между типом времени компиляции и типом времени выполнения для любого объекта в Java?

// Appropriate suppression of unchecked warning 
public E pop() { 
if (size == 0) 
    throw new EmptyStackException(); 
    // push requires elements to be of type E, so cast is correct 
    @SuppressWarnings("unchecked") E result = (E) elements[--size]; 
    elements[size] = null; // Eliminate obsolete reference 
    return result; 
} 

Здесь автор говорит об этих различных типах types в контексте массивов. Но через этот вопрос я хотел бы понять разницу между compile time types vs run time types для любого типа объекта.

+1

На самом деле существует три типа проверки типов: время компиляции, время проверки и время выполнения. Runtime является наименее распространенным типом и в основном происходит только там, где есть явная операция литья. –

+0

@HotLicks Интерфейсы также проверяются во время выполнения, а не на время проверки. Но поскольку компилятор также их проверяет, вам не нужно беспокоиться об этом, кроме случаев отражения или не Java-кода. – Antimony

+0

@Antimony - Ну, интерфейсы, конечно, рассматриваются как классы для проверки типов. Существует динамический поиск при вызове метода интерфейса, но сбой поиска будет по существу «внутренней ошибкой», если я правильно помню. –

ответ

10

Java - это статически типизированный язык, поэтому компилятор попытается определить типы всего и убедиться, что все безопасно. К сожалению, статический тип вывода по своей сути ограничен. Компилятор должен быть консервативным, а также не может видеть информацию о времени выполнения. Поэтому он не сможет доказать, что определенный код является типичным, даже если это действительно так.

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

Например, рассмотрим следующий код (который не будет компилировать)

public class typetest{ 
    public static void main(String[] args){ 
     Object x = args; 
     String[] y = x; 

     System.out.println(y[0]) 
    } 
} 

Переменная x всегда будет иметь тип String[], но компилятор не в состоянии понять это. Поэтому вам нужно явно придать приложению y.

+0

Интересно, что в этом случае верификатор JVM, вероятно, выяснит это, хотя компилятор этого не сделает. Верификатор JVM вводит тип от всех назначений к локальной переменной, и, учитывая только тот, тип хорошо известен. –

+0

Да, это только проблема во время компиляции. Конечно, если вы сохранили его в поле типа Object, а затем извлекли его, то верификатор также не смог бы это выяснить. – Antimony

+0

Во время компиляции Java считает, что ссылка 'x' указывает на объект типа' Object', если ссылка 'x' имеет тип' Object'. Он не учитывает неявный upcast от 'String' до' Object' 'args', что означает, что' x' фактически указывает на объект типа 'String []'. Во время выполнения Java реализует ссылку 'x', фактически указывающую на объект типа' String [] '. Таким образом, Java выдаст ошибки, если вы не нажмете 'x', чтобы сообщить компилятору, что на самом деле указано' x' во время компиляции. – NoName

0

Я думаю о «компиляции типа времени» как ЛЮБОГО типа, который может отображаться во время компиляции. Это будет включать объявленный класс, любые суперклассы и любые реализованные интерфейсы.

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

Как только объект присваивается переменной, компилятор будет обрабатывать его, как если бы он относится к типу переменной. Таким образом, другое использование «времени компиляции» может быть типом переменной, и вы можете обойти это во время компиляции путем кастинга на другой тип, если знаете, что приведение будет законным во время выполнения.

Если я говорю только о одном типе, я думаю о «runtime-type» переменной как фактическом подклассе уровня нижней (верхней?) Переменной; самый низкий подкласс, к которому он может быть применен. Но я также регулярно думаю о любом объекте как о создании какого-либо из его юридических типов.

Надеюсь, что это поможет.

+0

Переменная типа класса содержит * reference *; он просто имеет один тип - минимально-ограниченный тип вещи, который он примет, который определяется во время компиляции. Слоты массива ведут себя как переменные, но их тип определяется во время выполнения.Если 'myAnimals' является' Animal [] ', который содержит ссылку на' Cat [1] ', а' Cat [0] является экземпляром 'SiameseCat', тогда тип' Cat' будет временем выполнения -связанные с элементами массива, независимо от объектов, к которым массив содержит ссылки. – supercat

1

Java статически типизирован. Это означает, что каждое выражение (включая переменные) в языке имеет тип, который известен во время компиляции в соответствии с правилами языка. Это называется статическим типом (то, что вы называете «тип времени компиляции»). Типы на Java - это примитивные типы и ссылочные типы.

Кроме того, каждый объект во время выполнения в Java имеет «класс» (здесь «класс» включает в себя фиктивный массив «классы»), который известен во время выполнения.Класс объекта - это класс, с которым был создан объект.

Часть путаницы возникает из-за того, что каждый класс (и интерфейс и тип массива) в Java имеет соответствующий ссылочный тип с именем класса (или интерфейса или типа массива). Значение ссылочного типа является ссылкой, которая может быть либо null, либо указывать на объект. Языка Java разработан таким образом, что ссылка на ссылочного типаX, если не null всегда будет указывать на объект, чей класс является класса X или подкласс из него (или для интерфейсов, чей класс реализует интерфейс X).

Обратите внимание, что класс времени выполнения применяет объекты , но объекты не являются значениями на Java. С другой стороны, типы относятся к переменным и выражениям, которые являются понятиями времени компиляции. Переменная или выражение никогда не могут иметь значение объекта, потому что нет типов объектов; он может иметь значение ссылки, указывающее на объект.

Смежные вопросы