java三大特性:继承、封装、多态.
今天学习一下多态, 多态的三要素:
继承、重写(overWrite区别于overLoad)、父类引用指向子类对象.
多态的基础是继承, 先来复习一下继承.
继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
继承的特性:
子类拥有父类非private的属性,方法。
final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写。
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
子类可以用自己的方式重写父类的方法。
Java的继承是单继承,但是可以多重继承
继承的关键字extends, java中所有的类都继承Object类,Object类拥有的方法HashCode(); wait(); notify(); equals(); getClass(); toString(); clone(); finalize()
构造方法:
通过多态的方式实例无参对象,首先要调用父类的无参构造方法,再调用子类的无参构造方法
@Data
public class Shape {
public Shape() {
System.out.println("这里什么形状");
}
}
@Data
public class Triangle extends Shape {
public Triangle() {
System.out.println("这是三角形");
}
}
public static void main(String[] args) {
Shape shape1 = new Triangle();
}
//结果是先调用父类无参构造再调用子类无参构造
D:\java\jdk1.8\bin\java.exe ...
这里什么形状
这是三角形
Process finished with exit code 0
通过多态的方式实例有参对象,首先要调用父类的无参构造方法,再调用子类的有参构造方法
@Data
public class Shape {
public String length = "什么形状的长";
public String width = "什么形状的宽";
public Shape() {
System.out.println("这里什么形状");
}
}
@Data
public class Triangle extends Shape {
public String length = "三角形的长";
public String width = "三角形的高";
public Triangle() {
System.out.println("这是三角形");
}
public Triangle(String length, String width) {
this.length = length;
this.width = width;
System.out.println("这是一个长是" + length + ", 宽是" + width + "的三角形");
}
}
public static void main(String[] args) {
//通过有参构造实例对象
Shape shape = new Triangle("这应该是什么形状的长","这应该是什么形状的宽");
}
//结果先调用父类无参构造,再调用子类的有参构造
D:\java\jdk1.8\bin\java.exe ...
这里什么形状
这是一个长是这应该是什么形状的长, 宽是这应该是什么形状的宽的三角形
Process finished with exit code 0
子类是不继承父类的构造方法的,它只是调用。
如果父类只有有参构造,没有手动加无参构造, 则子类的有参构造必须显式地通过 super 关键字调用父类的有参构造。
@Data
public class Shape {
public String length = "什么形状的长";
public String width = "什么形状的宽";
public Shape(String length, String width) {
this.length = length;
this.width = width;
System.out.println("这是一个长是" + length + ", 宽是" + width + "的不明形状");
}
}
@Data
public class Triangle extends Shape {
public String length = "三角形的长";
public String width = "三角形的高";
public Triangle(String length, String width) {
super(length, width); //这里要手动去调父类的构造方法
this.length = length;
this.width = width;
System.out.println("这是一个长是" + length + ", 宽是" + width + "的三角形");
}
}
public static void main(String[] args) {
Shape shape = new Triangle("这应该是什么形状的长","这应该是什么形状的宽");
}
//结果先调用父类有参构造,再调用子类有参构造
D:\java\jdk1.8\bin\java.exe ...
这是一个长是这应该是什么形状的长, 宽是这应该是什么形状的宽的不明形状
这是一个长是这应该是什么形状的长, 宽是这应该是什么形状的宽的三角形
Process finished with exit code 0
如果父类有无参构造,则在子类不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。
注意的点:
通过多态实例对象时, 编译时成员变量和方法要看父类,如果父类没有的话不会通过jvm的编译.
1. 将父类的成员变量注释掉, 将父类的静态和非静态方法也都注释掉, 我们通过多态的实例去调用这些变量或者方法, 结果: 不能通过编译.
代码如下:
@Data
public class Shape {
// public String length = "什么形状的长";
// public String width = "什么形状的宽";
// public static String angle = "有几个角";
public Shape() {
System.out.println("这里什么形状");
}
// public static void calculatedArea(String length, String width){
// System.out.println("面积 = " + length + "×" + width);
// }
// public void special(){
// System.out.println("点");
// }
}
@Data
public class Triangle extends Shape {
public String length = "三角形的长";
public String width = "三角形的高";
public static String angle = "三个角";
public Triangle() {
System.out.println("这是三角形");
}
public static void calculatedArea(String length, String width) {
System.out.println("面积 = 1/2 × " + length + "×" + width);
}
public void special(){
System.out.println("三角形");
}
}
2. 我们再把父类注释的都打开, 然后发现可以通过编译, 输出结果如下:
@Data
public class Shape {
public String length = "什么形状的长";
public String width = "什么形状的宽";
public static String angle = "有几个角";
public Shape() {
System.out.println("这里什么形状");
}
public static void calculatedArea(String length, String width){
System.out.println("面积 = " + length + "×" + width);
}
public void special(){
System.out.println("点");
}
}
@Data
public class Triangle extends Shape {
public String length = "三角形的长";
public String width = "三角形的高";
public static String angle = "三个角";
public Triangle() {
System.out.println("这是三角形");
}
public static void calculatedArea(String length, String width) {
System.out.println("面积 = 1/2 × " + length + "×" + width);
}
public void special(){
System.out.println("三角形");
}
}
public static void main(String[] args) {
Shape shape = new Triangle();
String angle = shape.angle;
System.out.println("角: " + angle);
System.out.println("长: " + shape.length);
System.out.println("宽: " + shape.width);
shape.calculatedArea("100", "200");
shape.special();
}
D:\java\jdk1.8\bin\java.exe ...
这里什么形状
这是三角形
角: 有几个角
长: 什么形状的长
宽: 什么形状的宽
面积 = 100×200
三角形
Process finished with exit code 0
输出结果可以看出: 成员变量都是父类的结果, 静态方法是父类的结果, 非静态方法是子类的结果.
因此, 多态实例对象时, 在编译时成员变量和方法都看父类, 父类没有则编译报错, 父类有则可以通过编译; 运行的时候, 成员变量和静态方法是父类的结果, 非静态方法则是子类的结果.
所以, 子类中的独有方法(没有通过重写父类的方法), 那么就不能通过多态实例的对象来调用该方法. 多态一定要有重写
多态中我们还涉及到, 类型转换: 向上转型(隐式、自动转型), 向下转型(显式、强制转型) . 向下转型有风险,有可能数据溢出, 丢失精度. 使用时需要注意.
多态的好处是可扩展性高, 灵活性
策略模式:它定义了算法,分别封装起来,让他们之间可以替换,此模式让算法的变化,不会影响到算法的客户。
java中 treeset 和 treemap 的排序功能是采用的策略模式的思想 我们只需要自己定义排序字段、规则就可以
策略模式的优点
策略模式的缺点
设计原则
设计原则是把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口,然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。
策略模式属于对象行为型模式,主要针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响其他代码情况下发生变化。策略模式适用于当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。
策略模式中有三个对象
(1) 环境对象:该类中实现了对抽象策略中定义的接口或者抽象类的引用。
(2) 抽象策略对象:它可由接口或抽象类来实现。
(3) 具体策略对象:它封装了实现同不功能的不同算法。
利用策略模式构建程序,可以根据用户配置情况,选择不同有算法来实现应用程序的功能。具体的选择由环境对象来完成。采用这种方式可以避免由于使用条件语句而带来的代码混乱,提高应用程序的灵活性与条理性。