В вашем примере con.createStatement()
будет возвращать экземпляр некоторого класса, реализующего интерфейс Statement
.
con
предположительно является конкретным экземпляром класса, который реализует java.sql.Connection
, и эта конкретная реализация Connection
определяет, какой тип Statement
он должен возвращать.
Самый простой способ увидеть это — запустить свой код с помощью отладчика, и вы сможете увидеть фактический тип, которым является stmt
во время выполнения. Этот тип будет чем-то, что реализует Statement
.
Чтобы дать очень простой пример того, как это может работать для воображаемой базы данных с именем «SomeDatabase», у вас есть интерфейс Statement
, который вы показали выше:
public interface Statement extends Wrapper, AutoCloseable
и интерфейс Connection
:
public interface Connection extends Wrapper, AutoCloseable
Предположим, что con
является экземпляром конкретного класса с именем SomeDatabaseConnection
, который реализует метод createStatement
, потому что это требуется для интерфейса Connection
. Реализация createStatement
возвращает экземпляр конкретного класса, реализующего Statement
, характерного для SomeDatabase:
public class SomeDatabaseConnection implements Connection {
public Statement createStatement() {
return new SomeDatabaseStatement();
}
}
Теперь мы можем сказать:
Connection con = new SomeDatabaseConnection();
Statement stmt = con.createStatement();
Надеюсь, здесь вы видите, что фактически возвращаемый конкретный класс является экземпляром SomeDatabaseStatement
, который реализует Statement
.
Весь смысл всего этого в том, что детали могут быть скрыты от кода вашего приложения; не имеет значения, предоставлены ли ваши Connection
или Statement
Oracle, MySQL или SomeDatabase, функциональность, которую они предоставляют, гарантируется интерфейсами, для которых вы разрабатываете, поэтому вы можете легко переключаться с одной базы данных на другую, не меняя свою собственную код вообще.
Терминология
Хотя фактический конкретный класс stmt
является каким-то конкретным классом (SomeDatabaseStatement
в моем глупом примере), мы все же можем сказать, что это "оператор", поскольку он соответствует всем требованиям интерфейса Statement
.
Кроме того, поскольку интерфейс Statement
расширяет Wrapper
и AutoCloseable
, мы можем сказать, что stmt
«является оболочкой» и «является AutoCloseable», поскольку мы знаем, что он также должен соответствовать требованиям обоих этих интерфейсов.
Ваша линия:
Statement stmt = con.createStatement();
Может быть записано как:
MyDatabaseStatement stmt = con.createStatement();
но также было бы так же правильно написать, как:
Wrapper stmt = con.createStatement();
or
AutoCloseable stmt = con.createStatement();
Очевидный следующий вопрос: какой из них мы должны выбрать? Простой ответ на этот вопрос: тот, который дает вам всю необходимую функциональность, и не более того.
В этом конкретном примере в большинстве случаев это будет Statement
, потому что интерфейс Statement
предоставляет вам все полезные методы для взаимодействия с базой данных. Однако, если по какой-то причине вам нужно было вызвать только метод close()
, который определен в интерфейсе AutoCloseable
, то, вероятно, было бы лучше использовать AutoCloseable
вместо Statement
.
Чтобы узнать больше о том, почему это хорошо, прочитайте о принципе инверсии зависимостей.
20.05.2019
stmt
будет классом, реализующим интерфейсStatement
20.05.2019