Нет, java.lang.Object#finalize
является самым близким, можно добраться.
Однако то, когда (и если) это называют, не гарантируется.
См.: java.lang.Runtime#runFinalizersOnExit(boolean)
Все три совершенно законны, поскольку нет реальной разницы во времени выполнения между Stack
и Stack
, но все три будут в результате в предупреждениях компилятора.
Stack<Integer> s = new Stack()
Это приведет к предупреждению о "непроверенном преобразовании", поскольку в целом преобразовывать необработанный тип в параметризованный тип небезопасно. Однако в этом случае это совершенно безопасно: нажатие целых
значений не вызовет никаких ошибок; ввод значений, отличных от Integer
, вызовет ошибку типа.
Stack s = new Stack<Integer>()
Это допустимое преобразование параметризованного типа в необработанный. Вы сможете протолкнуть значение любого типа. Однако любая такая операция приведет к предупреждению «непроверенный вызов»
Stack s = new Stack()
. Опять же, это допустимо, без неявного преобразования. Вы сможете протолкнуть значение любого типа. Однако любая такая операция приведет к предупреждению о «непроверенном вызове».
Вы также можете получить предупреждение «необработанного типа» каждый раз, когда обращаетесь к типу Stack
.
Все они небезопасны, потому что дженерики Java, в силу стирания типа , являются всего лишь синтаксическим сахаром. Например, это полностью допустимый код Java:
Stack<Integer> s = new Stack<Integer>();
Stack<Double> s2 = (Stack<Double>)s;
s2.push(3.3d);
Смысл дженериков Java заключается в том, что вам не нужно явно указывать на приведение объектов. Вот и все. Они не делают ничего, кроме этого (кроме генерации предупреждений компилятора и IDE).
Они по-прежнему полезны и могут сделать ваш код более читаемым и менее подверженным ошибкам, но, в конечном итоге, на уровне байтового кода важно понимать, что они ' он ничего не делает.