Oop 面向对象编程练习
我正在复习考试,参加了这次复习练习。我有答案,但我这辈子都不能把脑袋绕在这上面。有人能解释一下发生了什么事吗Oop 面向对象编程练习,oop,object,interface,static,Oop,Object,Interface,Static,我正在复习考试,参加了这次复习练习。我有答案,但我这辈子都不能把脑袋绕在这上面。有人能解释一下发生了什么事吗 interface I1 { public void f(); } class A implements I1 { public void f() { //implementation } public static void g(){ //implementation } } class B extends A { public void f() { //imple
interface I1 {
public void f();
}
class A implements I1 {
public void f() {
//implementation
}
public static void g(){
//implementation
}
}
class B extends A {
public void f() {
//implementation
}
public static void g(){
//implementation
}
}
假设
I1 I1=新的B()
I1 i2=新的A()
a1=新的A()
A a2=新的B()
A b1=(A)新的B()
在不编写任何代码的情况下,用文字解释以下各项的效果:
下面的方法调用。只需说“这将调用f”
方法在“etc”中实现
b1.f()
b1.g()
i1.f()
a1.g()
i2.f()
a2.g() g
方法分析
请注意,f
是一个实例方法,而g
是一个静态方法。静态方法与类关联
因此,因为您将b1
,a1
和a2
声明为A
,调用b1.g()
,a1.g()
和a2.g()
都将调用A.g()
下面是关于Java静态方法的另一个好问题:
f
方法分析
Java实例方法默认为virtual
方法,可以被子类覆盖。因此f()
实际执行的操作取决于实例是什么(也就是说,取决于new
关键字后面的类型)
b1
是B
的一个实例,因此b1.f()
将调用B
上定义的f
方法,即B.f()
i1
也是B
的一个实例,因此i1.f()
也将调用B
上定义的f
方法,即B.f()
i2
是A
的一个实例,因此i2.f()
将调用A
上定义的f
方法,即A.f()
那么a2.f()
呢?如上所述,a2
是B
的一个实例(您使用new
关键字创建它),因此a2.f()
将调用B.f()
更多关于方法重写的信息
你可能想知道他们为什么这样工作?为什么a2.f()
在Java中不被设计为调用A.f()
?原因如下:
假设您有一个模块,该模块将根据记录列表执行复杂的计算。这些记录可以从数据库中检索,也可以从第三方RESTAPI提供的web api中检索。如何使您的模块尽可能可扩展
这是您的模块代码:
public class MyModule {
public void doComplexWork() {
// Where to get the records?
List<Record> records = ???;
// Do complex computation here
}
}
现在让我们稍微更改一下模块代码:
public class MyModule {
private IRecordRetriever _recordRetriever;
// Inject IRecordRetriever from contructor
public MyModule(IRecordRetriever retriever) {
_recordRetriever = retriever;
}
public void doComplexWork() {
// Where to get the records?
// From the IRecordRetriever
List<Record> records = _recordRetriever.retrieveRecords();
// Do complex computation here
}
}
公共类MyModule{
专用IRecordRetriever\u recordRetriever;
//从构造函数注入IRecordRetriever
公共MyModule(IRecordRetriever检索器){
_recordRetriever=检索器;
}
公共无效文档复合工作(){
//在哪里可以找到记录?
//从IRecordRetriever
列表记录=\u recordRetriever.retrieveRecords();
//在这里做复杂的计算
}
}
现在我们的MyModule
可以扩展了。因为无论在哪里检索记录,都不需要更改MyModule
中的代码。若现在您从数据库检索记录,但后来您决定更改为从RESTAPI检索记录,MyModule
中的任何内容都不需要更改!您只需更改传递给MyModule
构造函数的运行时IRecordRetriever
实例
为什么我们可以实现这种可扩展性?这是因为方法重写。我们将私有字段\u recordRetriever
声明为IRecordRetriever
,因此实际行为取决于实际运行时实例(由new
关键字创建)。因此,要更改记录检索行为,我们只需要更改传递给MyModule
构造函数的运行时IRecordRetriever
实例。如果方法重写不可用,即:
IRecordRetriever retriever=新数据库RecordRetriever();
retriever.retrieveRecords()
如果对retriever.retrieveRecords()
的调用不是调用DatabaseRecordRetriever
上定义的retrieveRecords()
方法,而是调用ireRecordRetriever
上定义的retrieveRecords()
方法,则我们无法实现可扩展性。(当然,IRecordRetriever
是一个接口,因此您不能调用IRecordRetriever.retrieveRecords()
,但这也适用于虚拟方法)
我上面提到的也适用于其他面向对象编程语言
我通过构造函数将IRecordRetriever
传递给MyModule
的方式被调用。您可以阅读更多关于面向对象编程、方法重写和GoF设计模式的资料。要了解这一点,您只需在每个实现中放入一条打印语句,比如“方法f在a中实现”,您可以使用它来了解发生了什么。
public class DatabaseRecordRetriever implements IRecordRetriever {
@Override
public List<Record> retrieveRecords() {
// Connect database and fetch database records here
}
}
public class RestApiRecordRetriever implements IRecordRetriever {
@Override
public List<Record> retrieveRecords() {
// Access the rest api to fetch records here
}
}
public class MyModule {
private IRecordRetriever _recordRetriever;
// Inject IRecordRetriever from contructor
public MyModule(IRecordRetriever retriever) {
_recordRetriever = retriever;
}
public void doComplexWork() {
// Where to get the records?
// From the IRecordRetriever
List<Record> records = _recordRetriever.retrieveRecords();
// Do complex computation here
}
}