面向对象特征——多态
多态有两种描述方式,一种是方法的多态性、一种是对象的多态性。多态是发生在编译期间的。
一、方法的多态性:
① 方法的重载:同一个方法名称,会根据传入参数的类型及个数不同执行不同的方法体;
② 方法的覆写: 同一个方法,会根据子类的不同,实现不同的功能。也就是继承了父类的多个子类对父类方法的重写,导致了方法的多态性。
二、对象的多态性(指的是发生在继承关系之中,子类和父类之间转换问题)
父类对象——子类实例:
① 向上转型(自动完成):父类 父类对象 = 子类实例 <new 实现>
子类对象——父类实例:
② 向下转型(强制完成):子类 子类对象 = (子类)父类实例 <new 实现>
下面看一个实例,让我们加深对多态的理解!!
class A {
public void m(A a) {
System.out.println("AA");
}
public void m(D d) {
System.out.println("AD");
}
}
class B extends A {
@Override
public void m(A a) {
System.out.println("BA");
}
public void m(B b) {
System.out.println("BD");
}
public static void main(String[] args) {
A a = new B();
B b = new B();
C c = new C();
D d = new D();
a.m(a);
a.m(b);
a.m(c);
a.m(d);
}
}
class C extends B{}
class D extends B{}
答:打印结果如下。
BA
BA
BA
AD
题目解析:
这道题很好的体现了方法的多态性和对象的多态性。父类对象指向子类实例,体现对象的多态性,而方法的参数不同,体现了方法的多态性。
第一个 BA:因为 A 的 m() 方法,被子类 B 重写了,所以输出是:BA;
第二个 BA:因为 B 是 A 的子类,当调用父类 m() 方法时,发现 m() 方法被 B 类重写了,所以会调用 B 中的 m() 方法,输出就是:BA;
第三个 BA:因为 C 是 B 的子类,会直接调用 B 的 m() 方法,所以输出就是:BA;
第四个 AD:因为 D 是 A 的子类,所以会调用 A 的 m() 方法,所以输出就是:AD。
我们看到,我们并不需要重新改动代码,只需要实现继承关系,就可以很方便的调用各个类的不同方法。
上面我们提到子类可以重写父类的方法,那子类可以重写父类的成员变量吗?
class A {
public int x = 0;
public static int y = 0;
public void m() {
System.out.print("A");
}
}
class B extends A {
public int x = 1;
public static int y = 2;
public void m() {
System.out.print("B");
}
public static void main(String[] args) {
A myClass = new B();
System.out.print(myClass.x);
System.out.print(myClass.y);
myClass.m();
}
}
上面的例子的输出值是什么呢?一个指向子类实例的父类应用,访问到的x和y到底是什么呢?输出的值为00B,这是因为子类不可以重写父类的成员变量。我们访问到的父类的变量没有发生改变。在子类中定义的变量只是子类的变量,父类不能访问,只能用子类的引用去访问。这是为什么呢?
因为在一个类中,子类中的成员变量如果和父类中的成员变量同名,那么即使他们类型不一样,只要名字一样。父类中的成员变量都会被隐藏。在子类中,父类的成员变量不能被简单的用引用来访问。而是,必须从父类的引用获得父类被隐藏的成员变量,一般来说,我们不推荐隐藏成员变量,因为这样会使代码变得难以阅读。
记录一下子类父类的加载
class ExecTest {
public static void main(String[] args) {
Son son = new Son();
}
}
class Parent{
{
System.out.print("1");
}
static{
System.out.print("2");
}
public Parent(){
System.out.print("3");
}
}
class Son extends Parent{
{
System.out.print("4");
}
static{
System.out.print("5");
}
public Son(){
System.out.print("6");
}
}
打印的结果如下:
251346
加载顺序如下:
- 执行父类的静态成员;2
- 执行子类的静态成员;5
- 父类的实例成员和实例初始化;1
- 执行父类构造方法;3
- 子类的实例成员和实例初始化;4
- 子类构造方法。6
来源:CSDN
作者:子衿@
链接:https://blog.csdn.net/huiyanfreeflying/article/details/103915038