Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(八)之Polymorphism
Polymorphism is the third essential feature of an object-oriented programming language,after data abastraction and inheritance.
It provides another dimension of separation of interface from implementation, to decouple what from how. Polymorphism allows improved code organization and readability as well as the creation of extensible programs that can be "grown" not only during the original creation of the project, but also when new features are desired.
Polymorphism deals with decoupling in terms of types.
Polymorphism also called dynamic binding or late binding or run-time binding
Upcasting revisited
Forgetting the object type
The compiler can't know that this Instrument reference points to a Wind in the case and not a Brass or Stringed.
Method-call binding
Connecting a method call to a method body is called binding. When binding is performed before the program is run ( by the compiler and linker, if there is one), it's called early binding. C compilers have only early binding.
The solution is called late binding, which means that the binding occurs at run time, based on the type of object. Late binding is also called dynamic binding or runtime binding.
That is, the compiler still doesn't know the object type, but the method-call mechanism finds out and calls the correct method body. ( you can imagine that som sort of type information must be installed in the objects.
All method binding in Java uses late binding unless the method is static or final ( private methods are implicitly final). This means that ordinarily you don't need to make any decisions about whether late binding will occur--it happens automatically
only use finla as a design decision, and not as an attempt to improve performance.
Producing the right behavior
Extensibility
Polymorphism is an important technique for the programmer to "separate the things that change from the thins that stay the same."
Pitfall: "overriding" private methods
public class PrivateOverride {
private void f() {print("private f()");}
public static void main (String[] args) {
PrivateOverride po = new Derived();
po.f();
}
}
class Derived extends PrivateOverride {
public void f() { print("public f()");}
}
输出: private f()
Derived's f() in this case is a brand new method; it's not even overloaded,since the base-class version of f() isn't visible in Derived.
Pitfall: fields and static methods
only ordinary method calss can be polymorphic
For example, if you acces a field directly, that access will be resolved at compile time.
When a Sub object is upcast to a Super reference, any field accesses are resolved by compiler, and are thus not polymorphic. In this example, different storage is allocated for Super.field and Sub.field. Thus, Sub actually contains two fieldss called field: its own and the one that it gets from Super. Howerver, the Super version in not the default that is produced when refer to field in Sub; in order to get the Super field you must explicitly say super.field.
Although this seems like it could be a confusing issue, in practive it virtually never comes up. For one thing, you'll generally make all fields private and so you won't access them directly, but only as side effects of calling methods. In addition, you probably won/t give the same name to a base-class field and a derived-class field, because its confusing.
Constructors and polymorphism
Constructors are not polymorphic (they're actually static methods, but the static declaration is implicit).
Order of constructor calls
Inheritance and cleanup
If you do have cleanup issues, you must be diligent and create a dispose() method for you new class. And with inheritance, you must override dispose() in the derived class if you have any special cleanup that must happen as part of garbage collection. When you override dispose() in an inherited class, it's important to remember to call the base-class version of dispose(), since otherwise the base-class cleanup will no happen.
If one of the member objects is shared with one or more other objects, the problem becomes more complex and you cannot simply assume that you can call dispose(). In this case, reference counting may be necessary to keep track of the number of objects that are still accessing a shared object.
private int refcount = 0;
public void addRef() { refcount++;}
protectd void dispose(){
if ( -- refcount == 0){
// 具体的dispose
}
When you attach a shared object to your class, you must remember to call addRef(), but the dispose() method will keep track of the reference count and decide when to actually perform the cleanup. This technique requires extra diligence to use, but if you are sharing objects that require cleanup you don't have much choice.
Behavior of polymorphic methods inside constructors
class Glyph {
void draw() { print("Glyph.draw()"); }
Glyph() {
print("Glyph() before draw()");
draw();
print("Glyph() after draw()");
}
}
class RoundGlyph extends Glyph {
private int radius = 1;
RoundGlyph(int r) {
radius = r;
print("RoundGlyph.RoundGlyph(), radius = " + radius);
}
void draw() {
print("RoundGlyph.draw(), radius = " + radius);
}
}
public class PolyConstructors {
public static void main(String[] args) {
new RoundGlyph(5);
}
} /* Output:
Glyph() before draw()
RoundGlyph.draw(), radius = 0
Glyph() after draw()
RoundGlyph.RoundGlyph(), radius = 5
A good guideline for constructors is, "Do as little as possible to set the object into a good state, and if you can possibly avoid it, don't call any other methods in this class." The only safe methods to call inside a constructor are those that are final in the base class. ( This also applies to private methods, which are automatically final.)
Convariant return types
Java SE5 adds convariant return types, which means that an overridden method in a derived class can return a type derived from the type returned by the base-class method
Designing with inheritance
If you choose inheritance first when you're using an existing class to make a new class, things can become needlessly complicated.
A better approach is to choose composition first, especially when it's not obvious which one you should use.
A general guideline is " Use inheritance to express difference in behavior, and fields (composition) to express variations in state."
Substitution vs. extension
It would seem that the cleanest way to create an inheritance hierarchy is to take the "pure" approach. That is , only methods that have been established in the base class are overridden in the derived class.
All you need to do is upcast from the derived class and never look back to see what exact type of object you're dealing with. Everything is handled through polymorphism.
This too is a trap. Extending the interface is the perfect solution to a particular problem. This can be termed an "is-like-a" relationship.
Downcasting and runtime type information
At run time this cast is checked to ensure that it is in fact the type you think it is. If it isn't, you get a ClassCastException.
The act of checking types at run time is called runtime type identification (RTTI).
Summary
Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(八)之Polymorphism的更多相关文章
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(八)之Reusing Classes
The trick is to use the classes without soiling the existing code. 1. composition--simply create obj ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(七)之Access Control
Access control ( or implementation hiding) is about "not getting it right the first time." ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(六)之Initialization & Cleanup
Two of these safety issues are initialization and cleanup. initialization -> bug cleanup -> ru ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十三)之Strings
Immutable Strings Objects of the String class are immutable. If you examine the JDK documentation fo ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(二)之Introduction to Objects
The genesis of the computer revolution was a machine. The genesis of out programming languages thus ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十四)之Type Information
Runtime type information (RTTI) allow you to discover and use type information while a program is ru ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十二)之Error Handling with Exceptions
The ideal time to catch an error is at compile time, before you even try to run the program. However ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十一)之Holding Your Objects
To solve the general programming problem, you need to create any number of objects, anytime, anywher ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十)之Inner Classes
The inner class is a valuable feature because it allows you to group classes that logically belong t ...
随机推荐
- 基于openshift+华为对象存储的CSI开发
目录 需求来源 环境准备 代码修改 镜像下载 镜像生成 修改部署文件 部署CSI插件 CSI原理 核心原理 生命周期: 组件介绍 FAQ 参考: 需求来源 项目上目前使用的是openshift 3.1 ...
- PhpStorm+XAMPP+Xdebug 集成开发和断点调试环境配置
0x01 Xdebug安装 参考:https://xdebug.org/docs/install cd xdebug-/ phpize sudo ./configure --enable-xdebug ...
- 【C++】Strassen算法代码
本文仅代码,无理论解释 实话实说,我觉得这个算法在C系列的语言下,简直垃圾到爆炸--毕竟是一群完全不懂程序数学家对着纸弄出来的,看起来好像非常的有用,实际上耗时是非常爆炸的. 但是<算法导论&g ...
- 洛谷P1003 铺地毯 模拟
这一题就是一个很普通的模拟,每次输入的时候存储四个角的值 把四个角的横纵坐标存储在一排.然后在倒序遍历一遍,查找的时候就看所要查找的坐标在不在这个范围内,如果找到了就标记一下再输出,如果没有找到就输出 ...
- CF 997A
You’ve got a string a1,a2,…,an, consisting of zeros and ones.Let’s call a sequence of consecutive el ...
- 吴恩达最新TensorFlow专项课程开放注册,你离TF Boy只差这一步
不需要 ML/DL 基础,不需要深奥数学背景,初学者和软件开发者也能快速掌握 TensorFlow.掌握人工智能应用的开发秘诀. 以前,吴恩达的机器学习课程和深度学习课程会介绍很多概念与知识,虽然也会 ...
- 解决GPU显存未释放问题
前言 今早我想用多块GPU测试模型,于是就用了PyTorch里的torch.nn.parallel.DistributedDataParallel来支持用多块GPU的同时使用(下面简称其为Dist). ...
- 用css3实现摩天轮旋转的动画效果
用css3实现摩天轮旋转的动画效果 1.CSS3 @keyframes 规则如需在 CSS3 中创建动画,您需要学习 @keyframes 规则.@keyframes 规则用于创建动画.在 @keyf ...
- Ubuntu16.04下LAMP环境的安装与配置
Ubuntu16.04下LAMP环境的安装与配置 最近做个实验需要用到Ubuntu环境的靶场,所以这里介绍下Ubuntu环境下LAMP的安装与配置,话不多说,我们gkd! 1.Apache2的安装 首 ...
- 2783: 【基础】小 X 玩游戏(game)
2783: [基础]小 X 玩游戏(game) 时间限制: 1 Sec 内存限制: 64 MB 提交: 752 解决: 294 [提交] [状态] [讨论版] [命题人:ghost79] 题目描述 听 ...