一、多态:
1.定义:
父类的引用指向子类的对象。
2.举例解读:
package com.qcby;
public class A {
public String name;
public int age;
public void run(){
System.out.println("A跑的很快");
}
public void eat(String name){
System.out.println(name+ "吃的很多");
}
}
--------------------------------------------
package com.qcby;
public class B extends A{
public String sex;
public double height;
public void fly(){
System.out.println("B飞得很高");
}
public void run(){
System.out.println("B跑的很快");
}
}
-----------------------------------------
package com.qcby;
public class Test {
public static void main(String[] args) {
A ab = new B();
ab.name = "张三";
ab.age = 18;
ab.run();
ab.eat("张三");
}
}
-------------------------------------------
//运行结果:
//B跑的很快
//张三吃的很多
父类:A 子类:B
此时,过程:
-
编译阶段:
Test
类被编译成Test.class
。A
类被编译成A.class
。B
类被编译成B.class
,需要A.class
的支持。
-
类加载阶段:
A.class
和B.class
被加载到方法区。
-
运行阶段:
- 创建
B
类型的对象,并将其赋值给A
类型的变量ab
。 - 调用
ab.run()
,由于ab
实际上引用的是B
类对象,因此调用B
中的run
方法。 - 调用
ab.eat("张三")
,由于eat
方法在A
类中定义且未在B
类中重写,因此调用A
类中的eat
方法。
- 创建
内存图:标红是调用到的。
3.多态的形式:
1. 方法重载:
2. 方法重写:
3. 接口实现和抽象类
多态也可以通过接口和抽象类来实现。一个接口或抽象类定义了一组方法,但没有实现它们。具体的实现由实现接口或继承抽象类的子类提供。
例:
interface Shape {
void draw();
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Circle");
}
}
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Rectangle");
}
}
abstract class Shape {
abstract void draw();
}
class Circle extends Shape {
@Override
void draw() {
System.out.println("Drawing a Circle");
}
}
class Rectangle extends Shape {
@Override
void draw() {
System.out.println("Drawing a Rectangle");
}
}
在这两个示例中,Shape
接口和 Shape
抽象类定义了 draw
方法,具体的实现由 Circle
和 Rectangle
提供。通过多态,代码可以处理不同类型的 Shape
对象,而无需关心具体的实现细节。
二、向上转型:
1.基本概念:
子类的对象可以被父类所接受,将一个子类对象引用赋值给其父类变量的过程。这是一种自动进行的类型转换,因为子类对象可以被看作是父类对象的一个实例。向上转型是一种常见的操作,特别是在使用多态时。
例:
package com.qcby;
public class A {
public String name;
public int age;
public void run(){
System.out.println("A跑的很快");
}
public void eat(String name){
System.out.println(name+ "吃的很多");
}
}
----------------------------------------------------
package com.qcby;
public class B extends A{
public String sex;
public double height;
public void fly(){
System.out.println("B飞得很高");
}
public void run(){
System.out.println("B跑的很快");
}
}
-----------------------------------------------------
package com.qcby;
public class C {
public static void headler(A a) {
System.out.println("C的输出。。。。。。。");
}
}
--------------------------------------------------------
package com.qcby;
public class Test {
public static void main(String[] args) {
B b = new B();
C.headler(b);
}
}
-------------------------------------------------------
//运行结果:
//C的输出。。。。。。。
由此可知,B的对象被A类所接受。
2.特点:
1.自动转型:Java 在向上转型时会自动进行转换,程序员不需要显式地进行类型转换。
2.访问权限:向上转型后,变量的类型是父类类型,因此只能访问父类中定义的方法和属性。子类特有的方法和属性在向上转型后无法访问。
3.多态:向上转型使得 Java 的多态机制得以实现。即通过父类类型的引用,可以调用子类中重写的方法。这个特性在实现多态和设计灵活的系统时非常有用。
4.安全性:向上转型是安全的。向上转型不会导致 ClassCastException 异常,但访问子类特有的方法会产生编译错误。
三、练习:
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
public class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
public class C extends B{
}
public class D extends B{
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}
输出结果:
-
A and A
解析:a1
调用的是A
类中的方法,其中有show(D)
和show(A)
两个重载方法。由于b
被向上转型到A
,a1.show(b)
调用的是A
类中的show(A)
方法,输出A and A
。这在a1
是A
类型,且b
的类型向上转型的情况下是准确的。 -
A and A
解析:和第一个选项相似,a1
调用的是A
类的方法,C继承于B,b
向上转型到A
,因此调用show(A)
方法,输出A and A
。这个选项与第一个选项的解释相同。 -
A and D
解析:a1
调用的是A
类的方法,其中有show(D)
和show(A)
两个重载方法。如果b
实际上是D
类型,那么在A
类中调用show(D)
方法会输出A and D
。 -
B and A
解析:a2
是B
类型,但由于方法重写,它调用的是B
类中的show(A)
方法。这个选项需要B
类重写A
类中的show(A)
方法并且输出B and A
。 -
B and A
解析:类似于第四个选项,a2
是B
类型,调用的是B
类中的show(A)
方法。这里需要a2
向上转型到A
,调用B
类的show(A)
方法,输出B and A
。 -
A and D
解析:与第三个选项相似,这个结果表明a2
调用的是A
类中的show(D)
方法,输出A and D
。需要b
实际上是D
类型或其子类。 -
B and B
解析:b
是B
类型,B
类中的方法可以被调用,可能包括show(D)
和show(A)
方法,这里输出B and B
。这表明B
类中的方法重写了A
类中的方法。 -
B and B
解析:和第七个选项类似,这个结果表明b
是B
类型,由于继承和方法重写,输出B and B
。 -
A and D
解析:b
是B
类型,调用了A
类中的show(D)
方法,输出A and D
。这表明b
实际上是D
类型或其子类,且重载方法选择为show(D)
。