遗传性和多态性
遗传性
遗传性允许 Java 复用&扩展 现有代码。
!注意,这里StyledString只是一个理论上的例子,因为String类是最终类,实践中无法被延展和添加特性。
延伸基础的String类,就是要充分利用现有的方法,同时增加一些我们自己的特性。
例1,String类原本只能做单纯的文本,扩展:增加文本样式,如粗体、斜体、下划线等。
class StyledString extends String //extends是扩展关键字
{
void setUnderlined(boolean underline){//参数为True/False,给出是否要划线的状态参数设置
……
}
void setItalics(boolean italic){
……
}
}
这里只添加了两个新的method,String原有的方法都能继续沿用。
例2,继承后,添加新的特性(这里是方法)
class Robot{
void talk(String phrase){
...
}}
class TranslationRobot extends Robot{
void translate(String phrase){
this.talk(phrase.replaceAll("a",substitute));//在这里复用talk, 在传入参数处中间添加了新方法 - replaceall
}}
使用延伸的新方法
public static void main(String args[])
{
StyledString message = new StyleString("Hello");//初始化新的字符串
message.setUnderlined(true);
message.setItalics(true);//设置为要求进行下划线、斜体的操作
System.out.println(message);
}
覆写 (Overriding)
重载:基于父类旧方法 + 添加新特性到子类,产生“新“方法,就是重载。
class Robot{
...
void charge(float amount){
System.out.println(name+" charges.");
powerLevel += amount;
}}
class TranslationRobot extends Robot{//extends可自动收到父类所有特性,包括属性和方法,无需重新重复写
...
@Override //覆写时要像这样注释一个@Override,以防止破坏方法签名
void charge(float amount){
System.out.println(name+" charges double.");
powerLevel = powerLevel + 2*amount;//复用+修改,替代父类方法
}}
覆写Overriding——函数原型完全相同!改变的是:父类的方法函数体。方法只有细微差别(原来是充电,这里是双倍充电)。
如上面Robot例子中,函数原型一致——都是void charge(float amount), return为空,输入都是浮点型。
其overriding表现于函数体不同:println()里的内容,以及powerLevel的变化有细微差别!
区别:重载Overloading——仅函数名相同,函数原型不同:参数不同、return类型不同等。函数签名signature因为输入参数的数量、类型等不同而不同。与多态性有关。例:
public class Sum {
public int sum(int x, int y)
{
return (x + y);
}
public int sum(int x, int y, int z)
{
return (x + y + z);
}
public double sum(double x, double y)
{
return (x + y);
}
public static void main(String args[])
{
Sum s = new Sum();
System.out.println(s.sum(10, 20));
System.out.println(s.sum(10, 20, 30));
System.out.println(s.sum(10.5, 20.5));
}
}
无论覆写还是重载,方法名都一样。因此实际调用的方法,取决于实际执行的对象。
例如,定义对象:普通机器人Robot C, 翻译机器人TranslationRobot D。
那么C.charge ( 2f ) 和 D.charge ( 2f ) 采用的方法就是不同的。
方法链
复用父类的方法,并在结尾处添加一些额外的特性。例如:
public Sting toString()
{
String text = super.toString();//沿用父类方法,一路递归顺沿至最上层父类
if(isUnderlined) text = "\033[4m"+"\033[0m";
if(isItalics) text = "\033[3m"+"\033[0m"; //两个if()的函数体为额外添加的方法特性
return text;
}
多态性
输入的String种类可能不确定,可能是最普通的String,也可能是上面延伸得到的styledString。
要写适用于两种String的方法,需要更通用笼统的方法:
public void spellCheck(String text) ...
这种方法既适用于String数据类型的对象 (普通String),也适用于String型的子类 (即延伸得到的 styledString)。
父类和子类有同名的方法,父类的可以无细节,只有一个抽象的函数名;
创建父类的一个范例变量,可用于存其衍生的下面任意子类型变量。
利用父类范例的多态性,父子类的同名方法(但细节上有些许差别),可以省去重复代码。
动态调度
public class Mammal {
...
public void makeNoise() {
System.out.println("Generic mammal sound");
}}
public class Dog extends Mammal{
public void makeNoise() {
System.out.println("woof woof");
}}
public class Lion extends Mammal{
public void makeNoise() {
System.out.println("grrrrrrr! roar");
}}
public class Dolphin extends Mammal{
public void makeNoise() {
System.out.println("squeek click");
}}
//下面是通过多态性使用动态调度方法
public class MammalPlanet {
public static void main(String [] args) {
Mammal [] mammalArrayObject = new Mammal[3];
mammalArrayObject[0] = new Lion();
mammalArrayObject[1] = new Dog();
mammalArrayObject[2] = new Dolphin();
for(Mammal mCurr : mammalArrayObject){
mCurr.stateAttributes();
mCurr.makeNoise();
}
}
}