多态:
多态的语法格式:
父类类型 引用变量名 = new 子类类型();
多态:父类引用 指向 子类对象
父类引用,在编译阶段,调用父类的方法,在运行阶段调用子类的方法
父类引用,可以调用父类独有方法,不能直接调用子类独有的方法
对于父子都有的静态方法,编译和运行阶段都调用父类的静态方法
自动类型转换 : 子类转父类
父类的引用强转子类类型 可能引发 ClassCastException 类型转换异常
// 在强制类型转换之前应该使用instanceof进行类型的判断 // 判断sr指向堆区内存中的对象是否为Circle类型,若是则返回true,否则返回false if(sr instanceof Circle) { System.out.println("可以放心地转换了!"); Circle c1 = (Circle)sr; } else { System.out.println("强转有风险,操作需谨慎!"); }
多态的使用场合之一:通过参数传递形成多态
多态的实际意义在于屏蔽了不同子类的差异性
package com.lagou.task09; 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)); } }
抽象类:
不能具体实例化,用abstract 修饰。不能创建对象
格式:
访问权限 abstract 返回值类型 方法名(形参列表);
public abstract void cry();
注意事项:
一般抽象类用 Abstract 开头
抽象类中也可以没有抽象方法
真正的抽象类,有abstract 关键字修饰,并且有抽象方法
抽象类的意义在于被继承
抽象子类必须重写抽象方法或者自己变成抽象类。
多态的使用场合二:直接在方法体中使用抽象类的引用指向子类类型的对象
private 和abstract 不能共同修饰方法 // 子类不能继承父类的私有方法
final abstract 不同共同修饰方法 // final 修饰的方法不能被重写
static abstract 不能共同修饰方法 // static 类名可以直接调用抽象方法
final abstract 不能共同修饰类 // final 修饰的类不能被继承
接口:
成员变量只能是常量 public static final 修饰 (可以省略)
里面只能有抽象方法 public abstract (新特性除外)
接口的实际意义: 弥补java不支持多继承
使用implement 关键字表达实现的关系,支持多实现
接口例子:
package com.lagou.task09; public interface Metal { // 自定义抽象方法描述发光的行为 public abstract void shine(); }
package com.lagou.task09; public interface Money { // 自定义抽象方法描述购物的行为 public abstract void buy(); }
package com.lagou.task09; // 使用implements关键字表达实现的关系,支持多实现 public class Gold implements Metal, Money { @Override public void shine() { System.out.println("发出了金黄色的光芒..."); } @Override public void buy() { System.out.println("买了好多好吃的..."); } public static void main(String[] args) { // 1.声明接口类型的引用指向实现类的对象,形成了多态 Metal mt = new Gold(); mt.shine(); Money mn = new Gold(); mn.buy(); } }
接口只能继承接口 ,使用extends关键字
接口继承接口支持多继承
类实现接口 ,使用implement关键字
例子:
package com.lagou.task09; public interface Runner { // 自定义抽象方法描述奔跑的行为 public abstract void run(); }
package com.lagou.task09; // 接口只能继承接口,不能继承类 public interface Hunter extends Runner { // 自定义成员方法描述捕猎的行为 public abstract void hunt(); // 将两个默认方法中重复的代码可以提取出来打包成一个方法在下面的两个方法中分别调用即可 private void show() { System.out.println("在以后的开发中尽量减少重复的代码,也就是减少代码的冗余!"); } // 增加一个抽象方法 //public abstract void show1(); // 增加非抽象方法 public default void show1() { show(); //System.out.println("在以后的开发中尽量减少重复的代码,也就是减少代码的冗余!"); System.out.println("show1方法中:这里仅仅是接口中的默认功能,实现类可以自由选择是否重写!"); } // 增加非抽象方法 public default void show2() { show(); //System.out.println("在以后的开发中尽量减少重复的代码,也就是减少代码的冗余!"); System.out.println("show2方法中:这里仅仅是接口中的默认功能,实现类可以自由选择是否重写!"); } // 增加静态方法 隶属于类层级,也就是接口层级 public static void test() { System.out.println("这里是静态方法,可以直接通过接口名.的方式调用,省略对象的创建"); } }
package com.lagou.task09; public class Man implements Hunter { @Override public void hunt() { System.out.println("正在追赶一直小白兔..."); } @Override public void run() { System.out.println("正在被一直大熊追赶,玩命奔跑中..."); } @Override public void show1() { System.out.println("为了给你几分薄面,我决定重写一下!"); } public static void main(String[] args) { // 1.声明接口类型的引用指向实现类的对象,形成了多态 Runner runner = new Man(); runner.run(); Hunter hunter = new Man(); hunter.hunt(); System.out.println("-----------------------------------------"); // 2.可以使用接口名称.的方式调用接口中的静态方法 Hunter.test(); } }
接口中的默认方法: public default 子类可以自由选择是否实现
java9 开始,私有方法 可以提高代码复用
如果多个静态方法中有重复代码,也可以实现私有静态方法提高代码复用。
补充内容:
静态语句块,可以初始化静态成员
声明和显式赋值是分离的,
静态成员在静态代码块提前调用,需要加类名限定
类初始化方法: <clinit>(),在类加载的时候执行一次
显式赋值,构造块,构造器会在class文件整合成<init>
继承:子类拥有父类的所有特征和方法.
初始化器不能继承,静态代码块(类初始化器),构造块,构造器(对象初始化器)
构造块可以在多个构造器前执行共同的初始化代码.
文章来自拉勾教育 大数据开发