多态
实际意义:
屏蔽不同子类的差异性 实现通用的编程 带来不同的结果
public class ShapeTest {
//打印矩形
// public static void draw(Rect r){
// System.out.println(r.toString());
// }
// //打印圆形
// public static void draw(Circle r){
// System.out.println(r.toString());
// }
public static void draw(Shape u){
System.out.println(u.toString());
}
public static void main(String[] args) {
ShapeTest.draw(new Rect(17,18,19,20));
ShapeTest.draw(new Circle(21,22,23));
}
}
同一种事物的多种形态
父类类型的引用指向子类类型的对象
父类类型 引用变量名 = new 子类类型();
向上转型:可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
比如:父类Parent,子类Child
父类的引用指向子类对象:Parent p=new Child();
说明:向上转型时,子类对象当成父类对象,只能调用父类的功能,如果子类重写了父类中声明过的方法,方法体执行的就是子类重过后的功能。但是此时对象是把自己看做是父类类型的,所以其他资源使用的还是父类型的。
比如:花木兰替父从军,大家都把花木兰看做她爸,但是实际从军的是花木兰,而且,花木兰只能做她爸能做的事,在军营里是不可以化妆的。
eg:
Shape sr = new Recy();
sr.show;
当父类类型的引用指向子类类型的对象时,父类类型的引用可以直接调用父类独有的方法。
当父类类型的引用指向子类类型的对象时,父类类型的引用不可以直接调用子类独有的方法。
对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段调用子类重写的版本(动态绑定)
对于父子类都有的静态方法来说,编译和运行阶段都调用父类版本。(静态方法的调用 只取决于这个变量所隶属于的类型,跟指向的对象没有关系,跟是否创建对象无关)(/*多态中,调用的静态方法是父类的,因为多态对象把自己看作是父类类型 * 直接使用父类中的静态资源*/)
public class ShapeRectTest {
public static void main(String[] args) {
//声明Shape类型的引用指向shape类型的对象并打印特征
Shape shape = new Shape(1,2);
String s = shape.toString();
System.out.println(s);
Rect rect = new Rect(3, 4, 5, 6);
String s1 = rect.toString();
System.out.println(s1);
/*--------------------------------------------------------------------------*/
//当父类的方法不满足子类的需求 需要重写
//声明rect类型的引用指向rect类型的对象并打印特征
//声明shape类型的引用指向rect类型的对象并打印
//向上转型? 应用之类的需要了解 效果不清楚
//披着父类的子类
Shape sr= new Rect(7,8,9,10);
String s2 = sr.toString();
System.out.println(s2);
//在编译阶段调用父类的方法 在运行阶段调用子类rect的tostring方法
//shape父类的引用能不能直接调用父类和子类独有的方法
int x = sr.getX();
System.out.println(x);
//披着父类的子类 可以直接调用父类的方法
//sr.getl(); 不能调用子类的方法
//共同的方法 编译调父类 运行调子类
sr.test();//隶属于类层级
shape.test();
//编译阶段和运行阶段都是调用的父类
int l = ((Rect) sr).getL();//强转
System.out.println("披着父类的子类获取到的长度"+l);
//希望将shape父类型转换为rect子类型
//String str1 = (String)sr;
//Inconvertible types; cannot cast 'night.Shape' to 'java.lang.String'
Shape qiangzhuan = (Shape) rect;
String s3 = qiangzhuan.toString();
System.out.println("强转之后的属性:"+s3);
System.out.println(s1);
}
}
父类:
public class Shape {
private int x;
private int y;
public static void test(){
System.out.println("父类中的静态方法");
}
public Shape(int x, int y) {
this.x = x;
this.y = y;
}
public Shape() {
}
@Override
public String toString() {
return "Shape{" +
"x=" + x +
", y=" + y +
'}';
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
System.out.println("父类中的独有方法");
return x;
}
public int getY() {
return y;
}
}
子类:
public class Rect extends Shape{
private int w;
private int l;
public static void test(){
System.out.println("子类中的静态方法");
}
参考一下这位博主的 理解更透彻
特别是其说法 编译看左边 运行看右边
多态
- 成员变量: 使用的是父类的(编译)
- 成员方法: 由于存在重写现象,所以使用的是子类的(运行)
- 静态成员: 随着类的加载而加载,谁调用就返回谁的(什么叫做谁调用)
引用数据类型之间的转换
1.引用数据类型之间的转换方式有两种:自动类型转换和强制类型转换,
2.自动类型转换主要指小类型向大类型的转换,也就是子类转为父类,也
叫做向上转型。
3.强制类型转换主要指大类型向小类型的转换,也就是父类转为子类,也
叫做向下转型或显式类型转换。
4..引用数据类型之间的转换必须发生在父子类之间,否则编译报错。
instanceof
做强转之前做一个判断 防止向上转型这种只是编译过了
if(sr instanceof Circle){
System.out.println("可以放心转换");
}
else{
System.out.println("强转有风险 操作需谨慎");
}
抽象方法
abstract
方法没法直接写 需要在具体子类里重写 先声明
public abstract void cry();
抽象类
1.不能具体实例化 不能创建对象
2.abstract和private 不能共同修饰同一个方法 因为私有方法不能被继承
3.final和abstract不能共同修饰同一个方法
4.static同上 static理解为共享
public abstract class AbstractTest {
private int cnt;
public AbstractTest() {
}
public AbstractTest(int cnt) {
this.cnt = cnt;
}
public void setCnt(int cnt) {
this.cnt = cnt;
}
public int getCnt() {
return cnt;
}
public abstract void show();
public static void main(String[] args) {
//AbstractTest abstractTest = new AbstractTest();
}
}
抽象类默认要有抽象方法
规定抽象类不能声明对象 就是为了防止通过抽象类对象调用抽象方法
抽象类的实际意义
继承抽象类必须要重写其抽象方法
或者自己也还是抽象类
多态的使用场景一是形参通用
多态的使用场景二:
public class SubAbstractTest extends AbstractTest {
public static void main(String[] args) {
//AbstractTest abstractTest = new AbstractTest();
SubAbstractTest sat = new SubAbstractTest();
SubAbstractTest at = new SubAbstractTest();
//
}
@Override
public void show() {
System.out.println("被迫重写");
}
}
在以后的开发中推荐使用多态的格式,此时父类类型引用直接调用的所有方法一定是父类中拥有的方法,若以后更换子类时,只需要将new关赞字后面的子类类型修改而其它地方无需改变就可以立即生效,从而提高了代码的可维护性和可扩展型。
抽象类:
public abstract class Account {
private double money;
//子类通过super调用
public void setMoney(double money) {
this.money = money;
}
public double getMoney() {
return money;
}
public Account(double money) {
this.money = money;
}
public Account() {
}
public abstract double getLixi();
}
public class FixedAccoount extends Account{
public FixedAccoount(int i) {
super(i);//调用父类的有参构造
}
public FixedAccoount() {
super();
}
@Override
public double getLixi() {
return getMoney() * 0.03*1;
}
public static void main(String[] args) {
// Account fixedAccoount = new FixedAccoount(1000);
FixedAccoount fixedAccoount = new FixedAccoount();
fixedAccoount.setMoney(1000);
double lixi = fixedAccoount.getLixi();
System.out.println(lixi);
}
}