多态
多态通过分离做什么和怎么做,从另一个角度将接口和实现分离开来
多态的作用是消除类型之间的耦合关系
多态方法调用允许一种类型表现出与其他相似类型之间的区别,只要他们都是从同一个基类导出的
Java组合与继承
组合
在新类中嵌入某个对象,让其实现所需要的功能,但是新类的用户看到的只是为新类所定义的接口
组合其实上是has-a的关系
比如一个车子,有发动机new Engine,有轮子new Wheel,有车窗new Door
继承
继承是is-a的关系
比如汽车和交通工具,不能说汽车拥有交通工具,而只能说汽车是交通工具,因此是继承关系
什么时候用组合,什么时候用继承呢
一个最清晰的判断方法就是问一问自己是否需要从新类向基类进行向上转型
如果需要向上转型,那么继承是必要的,如果不需要,应该好好考虑一下到底需不需要继承
继承的一条通用的准则是:用继承表达行为之间的差异,并用字段表达状态上面的变化
很多情况下面,更好的选择方式是组合
动态绑定
Java除了static方法和final方法,其他所有的方法都是后期绑定的。
后期绑定也叫动态绑定或者运行时绑定
通过动态绑定实现多态这个事实之后,就可以编写只与基类打交道的程序代码了。
向上转型
Shape s = new Circle()
通过继承,Circle就是一种Shaple(is-a)关系
当调用s.draw的时候,其实上调用了Circle里面的draw方法。
覆盖私有方法
public class PrivateOverride {
public void f() {
System.out.println("f in father");
}
}
public class MyOver extends PrivateOverride{
@Override
public void f() {
System.out.println("f in child");
}
public static void main(String[] args) {
PrivateOverride test = new MyOver();
test.f();
}
}
仍然会调用子类的方法。
当把PrivateOverride类里面的f()改为private之后,就不是 @Override了。
因为private被自动认为是final方法,并且对导出类是屏蔽的,不可以被重载。
protected可以。
多态——向上转型“缺陷”
看下面这个代码
class Super {
public int field = 0;
public int getField() {
return field;
}
}
class Sub extends Super {
public int field = 1;
@Override
public int getField() {
return field;
}
public int getSuperField() {
return super.field;
}
}
public class FieldAccess {
public static void main(String[] args) {
Super test1 = new Sub();
System.out.println("field:" + test1.field);
System.out.println("get field:" + test1.getField());
//test1没有SuperField方法
Sub test2 = new Sub();
System.out.println("");
System.out.println("field:" + test2.field);
System.out.println("get field:" + test2.getField());
System.out.println("super field:" + test2.getSuperField());
}
}
输出结果:
如果是Super test1 = new Sub();,那么test1是不能够有getSuperField方法的,因为受到向上转型的限制。
调用test1.field的时候,返回是0,说明返回的是基类的field
而test1.getField重载了之前的方法,所以调用test1.getField的时候,返回1,是子类的field
解决办法:
通常会将所有的域这只为private
基类中的域和导出类中的域一般不可能会赋予相同的名字,这样的做法很容易令人混淆
private方法、static方法、final方法都不具有多态性
构造器和多态
class Meal {
Meal() {
System.out.println("Meal()");
}
}
class Bread {
Bread() {
System.out.println("Bread()");
}
}
class Lunch extends Meal {
Lunch() {
System.out.println("Lunch()");
}
}
class ProtableLunch extends Lunch {
ProtableLunch() {
System.out.println("ProtableLunch()");
}
}
public class Sandwich extends ProtableLunch{
Bread bread = new Bread();
Sandwich() {
System.out.println("Sandwich()");
}
public static void main(String[] args) {
Sandwich sandwich = new Sandwich();
}
}
从输出可以看到:
首先调用基类构造器,这个步骤会反复递归下去
按照声明的孙旭调用成员的初始化方法
调用导出类构造器主体
构造器的调用顺序是很重要的。当进行继承时,我们已经知道基类的一切,并且可以访问基类中任何声明为public和protected的成员。
标签:Java,System,多态,field,println,new,public,out
来源: https://blog.csdn.net/weixin_36372879/article/details/101224558