4.面向对象的编程_抽象和多态
-
抽象
public class Practice { public static void main(String[] args) { Student.say(); } } public abstract class Student { /* abstract : 表示抽象的 , 可以用来修饰类和函数 抽象的本质, 是从一类事物中抽取特征, 归纳总结出统一的属性和方法. 抽象可能不实现具体功能, 更像是一种模板. 因此不可以创建对象或调用具体功能, 主要用来被子类继承, 然后子类再将方法实现, 完成具体的功能 abstract修饰的类称为 抽象类 格式 : 修饰符 abstract class 类名{} abstract修饰的函数称为 抽象函数 格式 : 修饰符 abstract 返回值类型 函数名(形式参数) ; 注意 : 1.抽象函数必须位于抽象类,但抽象类中不一定有抽象函数 2.即便抽象类中没有抽象函数,它依然不能创建对象 抽象类是有构造器的,用于子类创建对象时调用 3.子类继承抽象父类时,自然会继承父类中的抽象函数, 因此子类要么也声明为抽象类(GaoEr), 要么重写抽象函数(GaoYi),实现具体功能 模板法 : 当程序的一部分是确定的,另一部分是不确定, 确定部分在抽象父类写好, 不确定部分只做抽象声明, 具体功能交由子类来完成 模板法是多线程的原理. abstract 关键字不能与哪些关键字一起使用? 1.private 2.static 3.final static 不能跟 this super 一起使用 */ private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } public abstract void study() ; public static void say(){// static的属性或函数依然可以用类名直接调用 System.out.println("aaa"); } } public class GaoYi extends Student{ // 同一个体系,才可以继承 public GaoYi() { } public GaoYi(String name, int age) { super(name, age); } @Override public void study() { System.out.println("高一学生学习高一内容....."); } } public abstract class GaoEr extends Student{ }
-
接口
public class Practice { public static void main(String[] args) { /* interface 接口, 和class不同 接口是一种规范, 和继承类似, 也是抽象的. 没有具体功能, 需要靠class来实现接口 类与类之间 : 单继承,支持多层继承 接口与类之间 : 多实现(类可以implements多个接口), 也支持多层实现 类来实现接口,类实现接口后,具备继承特征 : 类是子类 , 接口是父类 接口与接口之间 : 多继承关系,支持多层继承 同一个体系继承. 不同体系之间,有类似的行为, 使用接口 继承: 动物->鸟类->鹰 接口: 鹰<-飞行->飞机 */ IA.m4(); IAImpl ia = new IAImpl(); ia.m3(); } } public interface IA { /* 接口是没有构造器的. JDK8.0/1.8 之前接口只有两个成员 1.常量 : public static final 数据类型 常量名 = 初始值 ; 2.抽象函数 : public abstract 返回值类型 函数名(形式参数) ; 注意: 这两种成员修饰符是固定的, 接口中的缺省即是默认这两种, 不再是default JDK8.0/1.8 之后接口多了default声明(默认级别函数), 是非抽象函数 之前都是abstract函数, 接口一旦有方法变动, 其子类(实现类)均需要实现. 现在可以用default, 有变动时, 子类可以根据需求,选择是直接继承还是重写. */ public static final double PI = 3.14; public abstract boolean m1(); int m2(int num);// public abstract default void m3(){// 非抽象函数, 不再强迫子类(实现类)实现. System.out.println("default IA 函数 m3"); } static void m4(){// 接口的静态成员依然可以用接口名直接访问 System.out.println("静态函数 m4"); } } public class IAImpl extends Object implements IA{// 先声明继承,再声明接口. 可以声明多个接口 // m1,m2函数必须重写实现, m3不需要 //@Override public boolean m1() { return false; } //@Override public int m2(int num) { return 0; } }
-
多态
public class Practice { public static void main(String[] args) { /* 多态 : 同一个事物的多种形态 前提 : 1.类继承 2.函数重写 3.向上转型 */ Animal animal = new Animal(); animal.eat(); Cat cat2 = new Cat(); cat2.eat(); // 向上转型 : 父类变量 来接收 子类对象的引用. 基本数据类型的自动类型转换 // 向上转型后会失去子类特有功能. 通过父类变量可以访问, 访问的实际结果也是子类, 但不可以直接访问子类特有函数 Animal animal2 = new Cat(); animal2.eat(); // animal2.catchMouse();// error // 向下转型 : 将父类变量转换为子类类型 基本数据类型的强制类型转换 Cat cat3 = (Cat) animal2; cat3.catchMouse(); // instanceof : 判断前面的对象是否是后面这个类的类型 // 可以通过这个语句来判断, 有问题直接处理, 避免运行异常 // 格式 : 对象名 instanceof 类型 System.out.println(animal instanceof Cat); System.out.println(animal2 instanceof Cat); System.out.println("---------------------------------------------"); Cat cat = new Cat(); function(cat); // 多态只和函数有关, 和成员变量无关, 即便父类变量实际指向子类, 访问成员变量时依然是父类的成员变量 // 看起来地址实际指向子类, 应该访问子类的成员变量. 但这涉及java隐藏域的内容, 不必深究. 当做特性,记住结论即可 System.out.println("---------------------------------------------"); System.out.println(animal2.num);// 110 System.out.println(cat2.num);// 120 } public static void function(Animal animal){// Animal animal = cat ; if (animal instanceof Animal) { animal.eat(); } if (animal instanceof Cat) { ((Cat) animal).catchMouse(); } } } public class Animal { int num = 110; public void eat() { System.out.println("动物吃..."); } public void sleep() { System.out.println("动物睡觉"); } } public class Cat extends Animal { int num = 120; @Override public void eat() { System.out.println("猫吃鱼....."); } public void catchMouse() { System.out.println("猫抓老鼠!!!!"); } }