1:多态(掌握)
(1)多态概念:一种事物的多种形态
(2)体现:父类的引用指向其子类的实例对象;接口的引用指向其实现类的实例对象
(3)特点:
成员方法:编译看左边,运行看右边
运行:子类重写的方法运行
编译:父类的引用类型必须有该方法
成员变量:编译看左边,运行看左边
运行:访问的为父类的属性
编译:父类的引用类型必须有该属性
总结:只有在方法调用的时候,才会判断子类是否重写,重写调用子类方法。其他情况均看父类类型
记忆方法:方法运行看右边,其他看左边
例子:
/* 多态: 一种事物的多种形态 前提: 具有继承关系 特点: 方法:编译看左边,运行看右边 运行:子类重写的方法运行 编译:父类的引用类型必须有该方法 变量:编译看左边,运行看左边 运行:访问的为父类的属性 编译:父类的引用类型必须有该属性 只有在方法调用的时候,才会判断子类是否重写,重写调用子类方法。其他情况均看父类类型 一句话总结:方法运行看右边,其他看左边 */ class Demo5 { public static void main(String[] args) { Animal animal = new Animal(); //动物是一种动物 Animal animal2 = new Cat(); //猫是一种动物,多态:猫的实例对象,父类动物的引用 //Cat cat2 = new Animal(); //动物是猫,不可以 Cat cat = new Cat(); //猫是猫 Animal a = new Cat(); //成员方法: a.eat(); //喵吃了 System.out.println(a.name); //巴马 System.out.println(a.age); //80 } } class Animal { String name = "巴马"; int age = 80; public void eat(){ System.out.println("吃了"); } } class Cat extends Animal { String name = "加菲"; int age = 40; public void eat(){ System.out.println("喵吃了"); } }
多太内存图:
(4)前提:
A:有继承或者实现关系。
B:有方法重写。 (重要)
/** * 多态的前提条件之一:必须要有方法的覆盖(即重写) */ public class Test { public static void main(String[] args) { Animal animal = new Dog(); animal.eat(); // animal.sleep(); //报错,找不到符号,接口中没有sleep()抽象方法 } } //接口 interface Animal { public abstract void eat(); } class Dog implements Animal { //继承的方法的重写 public void eat() { System.out.println("狗吃"); } //自己的方法 public void sleep() { System.out.println("夹着尾巴睡"); } }
C:有父类引用指向子类对象, 或者接口的应用指向实现类的对象
(3)好处和弊端:
A:好处
扩展性和维护性(是由继承和实现保证)。
/* 有两个类猪,狗继承动物,均有吃的动作。 创建多个猪与狗,调用他们吃的功能。 再来一个猫,创建多个猫的对象,调用猫的吃的功能 */ class Demo8_4 { public static void main(String[] args) { Pig pig = new Pig(); Pig pig2 = new Pig(); Pig pig3 = new Pig(); Dog dog = new Dog(); Dog dog2 = new Dog(); Dog dog3 = new Dog(); /* Animal pig = new Pig(); Animal pig2 = new Pig(); Animal pig3 = new Pig(); Animal dog = new Dog(); Animal dog2 = new Dog(); Animal dog3 = new Dog(); */ //不需要调用不同的方法,只需要调用同一个animalEat的方法即可 /* MyAnimalTool.pigEat(pig); MyAnimalTool.pigEat(pig2); MyAnimalTool.pigEat(pig3); MyAnimalTool.dogEat(dog); MyAnimalTool.dogEat(dog2); MyAnimalTool.dogEat(dog3); */ MyAnimalTool.animalEat(pig); MyAnimalTool.animalEat(pig2); MyAnimalTool.animalEat(pig3); MyAnimalTool.animalEat(dog); MyAnimalTool.animalEat(dog2); MyAnimalTool.animalEat(dog3); Cat cat = new Cat(); Cat cat2 = new Cat(); Cat cat3 = new Cat(); /* Animal cat = new Cat(); Animal cat2 = new Cat(); Animal cat3 = new Cat(); */ /* MyAnimalTool.catEat(cat); MyAnimalTool.catEat(cat2); MyAnimalTool.catEat(cat3); */ MyAnimalTool.animalEat(cat); MyAnimalTool.animalEat(cat2); MyAnimalTool.animalEat(cat3); } /* public static void pigEat(Pig p) { p.eat(); } public static void dogEat(Dog d) { d.eat(); } public static void catEat(Cat c) { c.eat(); } */ } //定义动物类作为父类 class Animal { public void eat(){ System.out.println("吃"); } } //定义猪与狗作为子类 class Pig extends Animal { public void eat(){ System.out.println("拱着吃"); } } class Dog extends Animal { public void eat(){ System.out.println("摇着尾巴吃"); } } class MyAnimalTool { //多个动物均是Animal的子类,所以只需要定义一个方法接受Animal类型即可。从而加入新的动物时,该类代码不需要改动! /* public static void pigEat(Pig p) { p.eat(); } public static void dogEat(Dog d) { d.eat(); } public static void catEat(Cat c) { c.eat(); } */ public static void animalEat(Animal a) { a.eat(); } } //添加猫类 class Cat extends Animal { public void eat(){ System.out.println("舔着吃"); } }
B:弊端
不能使用子类的特有功能。
/** * 多态的前提条件之一:必须要有方法的覆盖(即重写) */ public class Test { public static void main(String[] args) { Animal animal = new Dog(); animal.eat(); // animal.sleep(); //报错,找不到符号,接口中没有sleep()抽象方法 } } //接口 interface Animal { public abstract void eat(); } class Dog implements Animal { //继承的方法的重写 public void eat() { System.out.println("狗吃"); } //自己的方法 public void sleep() { System.out.println("夹着尾巴睡"); } }
(4)向上转型和向下转型
A:向上转型
把子类对象赋值给父类或者接口引用 ,例子:
/* 向上转型: 引用变量为父类时,子类实例对象可以自动提升为父类类型。即引用为父类型,可以赋值子类实例对象。 */ class Demo6 { public static void main(String[] args) { Animal a = new Cat(); //多态本身的赋值就是向上转型。 Cat c = new Cat(); //method(c); //method(new Animal()); 不可以 //method(a); 不可以 method2(a); method2(c); //向上转型 Cat c2 = method3(); Animal a2 = method3(); //向上转型 //Cat c3 = method4(); Animal a3 = method4(); } public static void method(Cat c) { System.out.println(c); } public static void method2(Animal animal) { System.out.println(animal); } public static Cat method3(){ //return new Animal(); return new Cat(); } public static Animal method4(){ //return new Animal(); return new Cat(); //向上转型 } } class Animal { String name = "巴马"; int age = 80; public void eat(){ System.out.println("吃了"); } } class Cat extends Animal { String name = "加菲"; int age = 40; public void eat(){ System.out.println("喵吃了"); } }
B:向下转型
把父类或者父接口引用强制转换为子类,例子:
/* 向下转型: 将父类强转成子类,前期父类引用指向的对象为子类对象,即必须是多态的引用。 */ class Demo7 { public static void main(String[] args) { Animal a = new Cat(); Animal a2 = new Animal(); Cat c = (Cat)a; //Cat c2 = (Cat)a2; 不可以 } } class Animal { String name = "巴马"; int age = 80; public void eat(){ System.out.println("吃了"); } } class Cat extends Animal { String name = "加菲"; int age = 40; public void eat(){ System.out.println("喵吃了"); } }
(5)多态中的使用成员特点
A:成员变量
编译运行都看左边
B:成员方法
编译看左边,运行看右边。
总结: 全部看父类类型,只是在调用该方法时,检查子类是否重写,如果重写,调用之类方法,如果没有重写,调用父类的方法。
(6)多态的体现形式
A:具体类多态(几乎不用)
B:抽象类多态
C:接口多态
2:抽象类(掌握)
(1)多个具体的事物具备相同的方法声明,而方法体不同,我们就只抽取方法声明,然后定义到一个类中。
而一个没有方法体的方法是一个抽象方法,一个类中有抽象方法,该类必须定义为抽象类。
(2)抽象类的特点:
A:抽象类或者抽象方法用abstract修饰。
B:抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
C:抽象类不能被实例化。
D:子类继承抽象类,要么是抽象类,要么重写所有父类抽象方法。
例子:
/* 抽象类:包含抽象方法的类 */ class Demo9 { public static void main(String[] args) { //Animal a = new Animal(); Animal a2 = new Pig(); System.out.println("Hello World!"); } } //定义动物类作为抽象父类 abstract class Animal { public abstract void eat(); public abstract void sleep(); //public void sleep(){ // System.out.println(); //} } //定义猪与狗作为子类 class Pig extends Animal { public void eat(){ System.out.println("拱着吃"); } public void sleep(){ System.out.println("躺着睡"); } } /* abstract class Dog extends Animal { public void eat(){ System.out.println("摇着尾巴吃"); } } */ class Dog extends Animal { public void eat(){ System.out.println("摇着尾巴吃"); } public void sleep(){ System.out.println("压着尾巴睡"); } }
(3)抽象类的几个小问题
A:不能被实例化,要构造方法干啥?
给抽象类的成员变量赋值
B:一个类中没有抽象方法,居然定义抽象类,有什么意义?
强制不让该类创建对象
C:abstract抽象关键字不能和哪些关键字共存
a:private 抽象类的方法需要被覆盖,如果private修饰的话,子类无法访问
b:final 抽象类需要继承,final修饰的无法继承
c:static 抽象类抽象方法无方法体,调用无意义
(4)抽象类的成员:
A:成员变量 有变量,也有常量
B:构造方法 有构造方法,用于子类访问父类数据的初始化
C:成员方法 有抽象方法,也有非抽象的方法
(5)抽象类的案例
A:老师案例
例子:
/* 老师示例 具体事物:基础班老师,就业班老师 共性:姓名,年龄,讲课。 */ class Test { public static void main(String[] args) { BaseTeacher bt = new BaseTeacher("刘正风",28); bt.setName("曲阳"); bt.teach(); System.out.println(bt.getName()); bt.teach(); WorkTeacher wt = new WorkTeacher("唐嫣",28); wt.teach(); Teacher t = new BaseTeacher("刘正风",28); t.setName("曲阳"); t.teach(); System.out.println(t.getName()); Teacher t2 = new WorkTeacher("唐嫣",28); t2.teach(); } } //设计抽象概念老师类 abstract class Teacher { private String name; private int age; public Teacher(){} public Teacher(String name,int age){ this.name = name; this.age = age; } public abstract void teach(); public void setName(String name) { this.name = name; } public String getName() { return name; } public void setAge(int age) { this.age = age; } public int getAge() { return age; } } //定义基础班老师 class BaseTeacher extends Teacher { public BaseTeacher(){} public BaseTeacher(String name,int age){ super(name,age); } public void teach() { System.out.println("讲JavaSE"); } } //定义就业班老师 class WorkTeacher extends Teacher { public WorkTeacher(){} public WorkTeacher(String name,int age){ super(name,age); } public void teach() { System.out.println("讲JavaEE/Android"); } }
3:接口(掌握)
(1)当一个抽象类中的方法都是抽象的时候,java就提供了一种更抽象的表达方式,叫接口。(接口里面的方法都是抽象的)
a.定义接口:interface XX {}
b.使用接口:class YY implements XX{}
例子:
/* 比抽象类更为抽象的表现形式 格式: 定义接口:interface XX {} 使用接口:class YY implements XX{} */ class Demo11 { public static void main(String[] args) { //Cat cat = new Cat(); Cat cat2 = new Student(); Cat cat3 = new Person(); System.out.println("Hello World!"); } } interface Cat { public abstract void climb(); } interface Dog { public abstract void guanxianshi(); } class Animal { } class Person extends Animal implements Cat,Dog { public void climb(){ System.out.println("我爬了"); } public void guanxianshi(){ System.out.println("我就管了"); } } class Student extends Animal implements Cat { public void climb(){ System.out.println("我爬了"); } public void guanxianshi(){ System.out.println("我就管了"); } }
(2)接口的成员特点:
A:成员变量 是常量 默认修饰符 public static final
B:成员方法 抽象方法 默认修饰符 public abstract
c: 没有构造方法 (接口不能创建对象)
例子:
/* 接口的成员有固定修饰符: 变量:public static final 将变量变为常量,所以必须显示初始化 方法:public abstract 一定为公共的抽象方法 */ class Demo12 { public static void main(String[] args) { Computer c = new Person(); c.play(); System.out.println(Computer.NO1); } } interface Computer { //public static final String NO1 = "艾尼阿克"; String NO1 = "艾尼阿克"; //public abstract void play(); //public void play(); void play(); //private void play(); 不能使用其他访问权限修饰符 } class Person implements Computer { public void play(){ System.out.println("敲个猜数字"); } /* 不能使用默认的访问权限覆盖公共的访问权限 void play(){ System.out.println("敲个猜数字"); } */ }
(3)接口的特点:
A:接口用interface定义
B:实现类实现接口用implements标识
C:接口不能被实例化
D:子类实现接口的时候,要么是抽象类,要么全部实现接口方法
(4)接口和类的关系
A:类与类的关系
继承关系,只能单继承,可以多层继承。
B:类与接口的关系
实现关系,可以单实现,也可以多实现。
还可以在继承一个类的同时,实现多个接口。 class A extends B implements C,D
C:接口与接口的关系
继承关系,可以单继承,也可以多继承。
(5)接口的思想特点(理解)
A:对外暴露的规则(USB接口)
B:程序的扩展功能(多态)
C:降低程序的耦合性(多态)
D:让类可以多实现
(6)接口和抽象类的区别
共性:都是不断抽取出来的抽象的内容。都不能创建实例对象。
不同:
A:成员特点
抽象类:
成员变量 可以变量,也可以常量
成员方法 可以抽象,也可以非抽象
构造方法 有
接口:
成员变量 只能是常量, 固定修饰符public static final
成员方法 只能是抽象,固定修饰符public abstract
构造方法 无
B:继承或者实现关系特点
a:类与类的关系(继承 extends)
继承关系,只能单继承,可以多层继承。
b:类与接口的关系(实现 implements)
实现关系,可以单实现,也可以多实现。
还可以在继承一个类的同时,实现多个接口。
c:接口与接口的关系(继承 extends)
继承关系,可以单继承,也可以多继承。
C:设计区别
抽象类中定义的是体系的共性内容。表达的是:is a的关系。
接口中定义的是体系的扩展功能。表达的是:like a的关系。
简单总结:
均为抽取出的相同概念的抽象。都不能创建实例对象。
类为单继承,接口为多实现。
继承为”is a”的关系,接口为“like a”的关系。
抽象类中可以定义非抽象方法,共子类直接使用。接口均为抽象方法,因为固定修饰符。
(7)如何实现一个继承体系
分析:由具体到抽象
实现:由抽象到具体