笔记输出来源:拉勾教育Java就业急训营
修改时间:2020年12月22日
作者:pp_x
邮箱:pp_x12138@163.com
java特性之多态
多态的概念
- 多态主要指同一事物表现出来的多种形态
多态的语法格式
- 父类类型 引用变量名 = new 子类类型();
- 如:
Shape sr = new Rect();
sr.show();
案例
- 编程实现
Shape
类的封装,特征有:横纵坐标,要求提供打印所有特征的方法 - 编程实现
Rect
类的封装并继承自Shape
类,特征有:长度和宽度 - 编程实现
ShapeRectTest
类,再main
方法中分别创建Shape
和Rect
类型对象并打印特征
多态的特点
- 当父类类型的引用指向子类类型的对象的时候,父类类型的引用可以直接调用父类独有的方法
- 当父类类型的引用指向子类类型的对象的时候,父类类型的引用不可以直接调用子类独有的方法
- 对于父子类都有的非静态方法来说,编译阶段调用的父类版本, 运行阶段调用子类重写的版本(
动态绑定
)。 - 对于父子类都有的静态方法,编译运行阶段都调用父类的静态方法。(因为静态类型与指定的对象没有关系,与类有关系)
引用数据类型之间的转换
- 引用数据类型之间的转换方式有两种:
自动类型转换
和强制类型转换
- 自动类型转换指小类型向大类型的转换,也就是子类转为父类,也叫向上转型
- 强制类型转换指大类型向小类型的转换,也就是父类转为子类,也叫向下转型
- 引用类型的转换必须发生在父子类之间。
- (重点)若强转的目标类型并不是该引用真正指向的数据类型时则编译通过,运行时发生类型转换异常
- 为了避免上述错误发生,应该在强转之前进行判断,格式如下
if(引用变量instanceof
数据类型)
判断引用变量指向的对象是否为后面的数据类型
- 为了避免上述错误发生,应该在强转之前进行判断,格式如下
shape类
public class Shape {
private int x;
private int y;
public Shape() {
}
public Shape(int x, int y) {
setX(x);
setY(y);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void show() {
System.out.println("横坐标:" + getX() + ",纵坐标:" + getY());
}
// 自定义静态方法
public static void test() {
System.out.println("Shape类中的静态方法!");
}
}
Rect类
public class Rect extends Shape {
private int len;
private int wid;
public Rect() {
}
public Rect(int x, int y, int len, int wid) {
super(x, y);
setLen(len);
setWid(wid);
}
public int getLen() {
return len;
}
public void setLen(int len) {
if(len > 0) {
this.len = len;
} else {
System.out.println("长度不合理哦!!!");
}
}
public int getWid() {
return wid;
}
public void setWid(int wid) {
if (wid > 0) {
this.wid = wid;
} else {
System.out.println("宽度不合理哦!!!");
}
}
@Override
public void show() {
super.show();
System.out.println("长度是:" + getLen() + ",宽度是:" + getWid());
}
// 自定义静态方法
//@Override Error: 历史原因、不是真正意义上的重写
public static void test() {
System.out.println("---Rect类中的静态方法!");
}
}
ShapeRectTest类
public class ShapeRectTest {
public static void main(String[] args) {
// 1.声明Shape类型的引用指向Shape类型的对象并打印特征
Shape s1 = new Shape(1, 2);
// 当Rect类中没有重写show方法时,下面调用Shape类中的show方法
// 当Rect类中重写show方法后,下面调用Shape类中的show方法
s1.show(); // 1 2
// 使用ctrl+d快捷键可以复制当前行
System.out.println("------------------------------------");
// 2.声明Rect类型的引用指向Rect类型的对象并打印特征
Rect r1 = new Rect(3, 4, 5, 6);
// 当Rect类中没有重写show方法时,下面调用Shape类中的show方法
// 当Rect类中重写show方法后,下面调用Rect类中的show方法
r1.show(); // 3 4 5 6
// 使用alt+shift+上下方向键 可以移动代码
System.out.println("------------------------------------");
// 3.声明Shape类型的引用指向Rect类型的对象并打印特征
// 相当于从Rect类型到Shape类型的转换 也就是子类到父类的转换 小到大的转换 自动类型转换
Shape sr = new Rect(7, 8, 9, 10);
// 当Rect类中没有重写show方法时,下面调用Shape类中的show方法
// 当Rect类中重写show方法后,下面的代码在编译阶段调用Shape类的方法,在运行阶段调用Rect类中的show方法
sr.show(); // 7 8 9 10
System.out.println("------------------------------------");
// 4.测试Shape类型的引用能否直接调用父类和子类独有的方法呢???
int ia = sr.getX();
System.out.println("获取到的横坐标是:" + ia); // 7
//sr.getLen(); error Shape类中找不到getLen方法,也就是还在Shape类中查找
// 调用静态方法
sr.test(); // 提示:不建议使用引用.的方式访问
Shape.test(); // 推荐使用类名.的方式访问
System.out.println("------------------------------------");
// 5.使用父类类型的引用调用子类独有方法的方式
// 相当于从Shape类型到Rect类型的转换,也就是父类到子类的转换 大到小的转换 强制类型转换
int ib = ((Rect) sr).getLen();
System.out.println("获取到的长度是:" + ib); // 9
// 希望将Shape类型转换为String类型 强制类型转换要求必须拥有父子类关系
//String str1 = (String)sr; Error
// 希望将Shape类型强制转换为Circle类型,下面没有报错
//Circle c1 = (Circle)sr; // 编译ok,但运行阶段发生 ClassCastException类型转换异常
// 在强制类型转换之前应该使用instanceof进行类型的判断
// 判断sr指向堆区内存中的对象是否为Circle类型,若是则返回true,否则返回false
if(sr instanceof Circle) {
System.out.println("可以放心地转换了!");
Circle c1 = (Circle)sr;
} else {
System.out.println("强转有风险,操作需谨慎!");
}
}
}
多态的实际意义
- 在于屏蔽了不同子类的差异性实现通用的编程带来的不同的效果
多态使用的例子
Shape
同上
Circle
package com.lagou.object4;
public class Circle extends Shape {
private int ir;
public Circle() {
}
public Circle(int x, int y, int ir) {
super(x, y);
setIr(ir);
}
public int getIr() {
return ir;
}
public void setIr(int ir) {
if (ir > 0) {
this.ir = ir;
} else {
System.out.println("半径不合理哦!!!");
}
}
@Override
public void show() {
super.show();
System.out.println("半径是:" + getIr());
}
}
ShapeTest
public class ShapeTest {
// 自定义成员方法实现将参数指定矩形对象特征打印出来的行为,也就是绘制图形的行为
// Rect r = new Rect(1, 2, 3, 4);
// public static void draw(Rect r) {
// r.show(); // 1 2 3 4
// }
// 自定义成员方法实现将参数指定圆形对象特征打印出来的行为
// public static void draw(Circle c) {
// c.show(); // 5 6 7
// }
// 自定义成员方法实现既能打印矩形对象又能打印圆形对象的特征,对象由参数传入 子类 is a 父类
// Shape s = new Rect(1, 2, 3, 4); 父类类型的引用指向子类类型的对象,形成了多态
// Shape s = new Circle(5, 6, 7); 多态
// 多态的使用场合一:通过参数传递形成了多态
public static void draw(Shape s) {
// 编译阶段调用父类的版本,运行阶段调用子类重写以后的版本
s.show();
}
public static void main(String[] args) {
// Rect r = new Rect(1, 2, 3, 4);
// r.show();
ShapeTest.draw(new Rect(1, 2, 3, 4));
ShapeTest.draw(new Circle(5, 6, 7));
}
}