Java基础:继承、多态、抽象、接口

时间:2022-11-09 21:57:26
第一讲    继承

一、继承概述

1、多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
2、通过extends关键字可以实现类与类的继承
      class 子类名 extends 父类名 {}  
3、单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。
4、有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。
首先我来写两个代码:
//定义学生类
class Student {
String name;
int age;

public Student(){}

//getXxx()/setXxx()

public void eat() {
System.out.println("吃饭");
}
}

//定义老师类
class Teacher {
String name;
int age;

public Teacher(){}

//getXxx()/setXxx()

public void eat() {
System.out.println("吃饭");
}
}
我们观察上面两个代码:
发现name,age成员变量,以及getXxx()/setXxx(),还有eat()等都是相同的。
如果我们后来继续定义类,举例:工人类,军人类。他们是不是也具备这些内容。
那么,我们每一次定义这样的类的时候,都要把这些重复的内容都重新定义一遍。
麻烦不?麻烦。所以,我们要考虑改进?
如何改进呢?
我这想的:我能不能把这些相同的内容给定义到一个独立的类中。
然后,让这多个类和这个独立的类产生一个关系,有了这个关系后,
这多个类就可以具备这个独立的类的功能。
为了实现这个效果,java就提供了一个技术:继承。

父亲:
4个儿子
继承怎么表示呢?继承的格式是什么样子的呢?
class Fu {}

class Zi extends Fu {

}

我们就回头修改我们的代码:
class Person {
String name;
int age;

public Person(){}

//getXxx()/setXxx()

public void eat() {
System.out.println("吃饭");
}
}

class Student extends Person {
public Student(){}
}

class Teacher extends Person {
public Teacher(){}
}

二、继承的好处

1、提高了代码的复用性

     多个类相同的成员可以放到同一个类中

2、提高了代码的维护性

     如果功能的代码需要修改,修改一处即可

3、让类与类之间产生了关系,是多态的前提

     其实这也是继承的一个弊端:类的耦合性很强

4、设计原则:高内聚低耦合。

     简单的理解:内聚就是自己完成某件事情的能力。耦合就是类与类之间的关系。
     我们在设计的时候原则是:自己能完成的就不麻烦别人,这样将来别人产生了修改,就对我的影响较小。由此可见:在开发中使用继承其实是在使用一把双刃剑。今天我们还是以继承的好处来使用,因为继承还有很多其他的特性。
/*
继承概述:
把多个类中相同的内容给提取出来定义到一个类中。

如何实现继承呢?
Java提供了关键字:extends

格式:
class 子类名 extends 父类名 {}

好处:
A:提高了代码的复用性
B:提高了代码的维护性
C:让类与类之间产生了关系,是多态的前提

类与类产生了关系,其实也是继承的一个弊端:
类的耦合性增强了。

开发的原则:低耦合,高内聚。
耦合:类与类的关系
内聚:就是自己完成某件事情的能力
*/

//使用继承前
/*
class Student {
public void eat() {
System.out.println("吃饭");
}

public void sleep() {
System.out.println("睡觉");
}
}

class Teacher {
public void eat() {
System.out.println("吃饭");
}

public void sleep() {
System.out.println("睡觉");
}
}
*/

//使用继承后
class Person {
public void eat() {
System.out.println("吃饭");
}

public void sleep() {
System.out.println("睡觉");
}
}

class Student extends Person {}

class Teacher extends Person {}

class ExtendsDemo {
public static void main(String[] args) {
Student s = new Student();
s.eat();
s.sleep();
System.out.println("-------------");

Teacher t = new Teacher();
t.eat();
t.sleep();
}
}
运行结果:
Java基础:继承、多态、抽象、接口

三、Java中继承的特点

1、Java只支持单继承,不支持多继承。

(1)一个类只能有一个父类,不可以有多个父类。
(2)class SubDemo extends Demo{} //ok
(3)class SubDemo extends Demo1,Demo2...//error

2、Java支持多层继承(继承体系)

     class A{}
     class B extends A{}
     class C extends B{}
/*
Java中继承的特点:
A:Java只支持单继承,不支持多继承。
有些语言是支持多继承,格式:extends 类1,类2,...
B:Java支持多层继承(继承体系)
*/

/*
class Father {}
class Mother {}
class Son exnteds Father {} //正确的
class Son extends Father,Mother {} // 错误的
*/

class GrandFather {
public void show() {
System.out.println("我是爷爷");
}
}

class Father extends GrandFather {
public void method(){
System.out.println("我是老子");
}
}

class Son extends Father {}

class ExtendsDemo2 {
public static void main(String[] args) {
Son s = new Son();
s.method(); //使用父亲的
s.show(); //使用爷爷的
}
}
运行结果:
Java基础:继承、多态、抽象、接口

3、Java中继承的注意事项

(1)子类只能继承父类所有非私有的成员(成员方法和成员变量)
         其实这也体现了继承的另一个弊端:打破了封装性
(2)子类不能继承父类的构造方法,但是可以通过super(后面讲)关键字去访问父类构造方法。
(3)不要为了部分功能而去继承
(4)我们到底在什么时候使用继承呢?
         继承中类之间体现的是:”is a”的关系。
/*
继承的注意事项:
A:子类只能继承父类所有非私有的成员(成员方法和成员变量)
B:子类不能继承父类的构造方法,但是可以通过super(马上讲)关键字去访问父类构造方法。
C:不要为了部分功能而去继承
class A {
public void show1(){}
public void show2(){}
}

class B {
public void show2(){}
public void show3(){}
}

//我们发现B类中出现了和A类一样的show2()方法,所以,我们就用继承来体现
class B extends A {
public void show3(){}
}
这样其实不好,因为这样你不但有了show2(),还多了show1()。
有可能show1()不是你想要的。

那么,我们什么时候考虑使用继承呢?
继承其实体现的是一种关系:"is a"。
Person
Student
Teacher
水果
苹果
香蕉
橘子

采用假设法。
如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。
*/
class Father {
private int num = 10;
public int num2 = 20;

//私有方法,子类不能继承
private void method() {
System.out.println(num);
System.out.println(num2);
}

public void show() {
System.out.println(num);
System.out.println(num2);
}
}

class Son extends Father {
public void function() {
//num可以在Father中访问private
//System.out.println(num); //子类不能继承父类的私有成员变量
System.out.println(num2);
}
}

class ExtendsDemo3 {
public static void main(String[] args) {
// 创建对象
Son s = new Son();
//s.method(); //子类不能继承父类的私有成员方法
s.show();
s.function();
}
}

4、继承中成员变量的关系

在子类方法中访问一个变量
(1)首先在子类局部范围找
(2)然后在子类成员范围找
(3)最后在父类成员范围找(肯定不能访问到父类局部范围)
(4)如果还是没有就报错。(不考虑父亲的父亲…)
/*
类的组成:
成员变量:
构造方法:
成员方法:
而现在我们又讲解了继承,所以,我们就应该来考虑一下,类的组成部分的各自关系。

继承中成员变量的关系:
A:子类中的成员变量和父类中的成员变量名称不一样,这个太简单。
B:子类中的成员变量和父类中的成员变量名称一样,这个怎么玩呢?
在子类方法中访问一个变量的查找顺序:
a:在子类方法的局部范围找,有就使用
b:在子类的成员范围找,有就使用
c:在父类的成员范围找,有就使用
d:如果还找不到,就报错。
*/
class Father {
public int num = 10;

public void method() {
int num = 50;
}
}

class Son extends Father {
public int num2 = 20;
public int num = 30;

public void show() {
int num = 40;
System.out.println(num);
System.out.println(num2);
// 找不到符号
System.out.println(num3);
}
}

class ExtendsDemo4 {
public static void main(String[] args) {
//创建对象
Son s = new Son();
s.show();
}
}

5、super关键字

(1)super的用法和this很像
        this代表本类对应的引用。
        super代表父类存储空间的标识(可以理解为父类引用)
(2)用法(this和super均可如下使用)
Java基础:继承、多态、抽象、接口

/*
问题是:
我不仅仅要输出局部范围的num,还要输出本类成员范围的num。怎么办呢?
我还想要输出父类成员范围的num。怎么办呢?
如果有一个东西和this相似,但是可以直接访问父类的数据就好了。
恭喜你,这个关键字是存在的:super。

this和super的区别?
分别是什么呢?
this代表本类对应的引用。
super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员)

怎么用呢?
A:调用成员变量
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量
B:调用构造方法
this(...)调用本类的构造方法
super(...)调用父类的构造方法
C:调用成员方法
this.成员方法 调用本类的成员方法
super.成员方法 调用父类的成员方法
*/
class Father {
public int num = 10;
}

class Son extends Father {
public int num = 20;

public void show() {
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(super.num);
}
}

class ExtendsDemo5 {
public static void main(String[] args) {
Son s = new Son();
s.show();
}
}

6、继承中构造方法的关系

(1)子类中所有的构造方法默认都会访问父类中空参数的构造方法
(2)原因:
         因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。
         每一个构造方法的第一条语句默认都是:super()
(3)如果父类中没有构造方法,该怎么办呢?        子类通过super去显示调用父类其他的带参的构造方法
        子类通过this去调用本类的其他构造方法
        本类其他构造也必须首先访问了父类构造
         一定要注意:super(…)或者this(….)必须出现在第一条语句山,否则,就会有父类数据的多次初始化
/*
继承中构造方法的关系
A:子类中所有的构造方法默认都会访问父类中空参数的构造方法
B:为什么呢?
因为子类会继承父类中的数据,可能还会使用父类的数据。
所以,子类初始化之前,一定要先完成父类数据的初始化。

注意:子类每一个构造方法的第一条语句默认都是:super();
*/
class Father {
int age;

public Father() {
System.out.println("Father的无参构造方法");
}

public Father(String name) {
System.out.println("Father的带参构造方法");
}
}

class Son extends Father {
public Son() {
//super();
System.out.println("Son的无参构造方法");
}

public Son(String name) {
//super();
System.out.println("Son的带参构造方法");
}
}

class ExtendsDemo6 {
public static void main(String[] args) {
//创建对象
Son s = new Son();
System.out.println("------------");
Son s2 = new Son("林青霞");
}
}

运行结果:

Java基础:继承、多态、抽象、接口

7、方法重写

(1)子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖,方法复写。
         使用特点:如果方法名不同,就调用对应的方法;如果方法名相同,最终使用的是子类自己的
(2)方法重写的应用:
         当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
(3)方法重写的注意事项
        父类中私有方法不能被重写
        子类重写父类方法时,访问权限不能更低
        父类静态方法,子类也必须通过静态方法进行重写。
/*
方法重写:子类中出现了和父类中方法声明一模一样的方法。

方法重载:
本类中出现的方法名一样,参数列表不同的方法。与返回值无关。

子类对象调用方法的时候:
先找子类本身,再找父类。

方法重写的应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。
这样,即沿袭了父类的功能,又定义了子类特有的内容。

案例:
A:定义一个手机类。
B:通过研究,我发明了一个新手机,这个手机的作用是在打完电话后,可以听天气预报。
按照我们基本的设计,我们把代码给写出来了。
但是呢?我们又发现新手机应该是手机,所以,它应该继承自手机。
其实这个时候的设计,并不是最好的。
因为手机打电话功能,是手机本身就具备的最基本的功能。
所以,我的新手机是不用在提供这个功能的。
但是,这个时候,打电话功能就没有了。这个不好。
最终,还是加上这个功能。由于它继承了手机类,所以,我们就直接使用父类的功能即可。
那么,如何使用父类的功能呢?通过super关键字调用
*/
class Phone {
public void call(String name) {
System.out.println("给"+name+"打电话");
}
}

class NewPhone extends Phone {
public void call(String name) {
//System.out.println("给"+name+"打电话");
super.call(name);
System.out.println("可以听天气预报了");
}
}

class ExtendsDemo9 {
public static void main(String[] args) {
NewPhone np = new NewPhone();
np.call("林青霞");
}
}
运行结果:
Java基础:继承、多态、抽象、接口

8、final关键字

     通过子类重写父类方法,来说明父类不能被人动的方法,也别动了。为了强制不能动,Java就提高了final关键字final关键字是最终的意思,可以修饰类,成员变量,成员方法。
     修饰类,类不能被继承
     修饰变量,变量就变成了常量,只能被赋值一次
     修饰方法,方法不能被重写

9、继承练习

(1)学生案例和老师案例讲解
/*
学生案例和老师案例讲解

学生:
成员变量;姓名,年龄
构造方法:无参,带参
成员方法:getXxx()/setXxx()
老师:
成员变量;姓名,年龄
构造方法:无参,带参
成员方法:getXxx()/setXxx()

看上面两个类的成员,发现了很多相同的东西,所以我们就考虑抽取一个共性的类:
人:
成员变量;姓名,年龄
构造方法:无参,带参
成员方法:getXxx()/setXxx()

学生 继承 人
老师 继承 人
*/
//定义人类
class Person {
//姓名
private String name;
//年龄
private int age;

public Person() {
}

public Person(String name,int age) { //"林青霞",27
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

//定义学生类
class Student extends Person {
public Student() {}

public Student(String name,int age) { //"林青霞",27
//this.name = name;
//this.age = age;
super(name,age);
}
}

//定义老师类
class Teacher extends Person {

}

class ExtendsTest4 {
public static void main(String[] args) {
//创建学生对象并测试
//方式1
Student s1 = new Student();
s1.setName("林青霞");
s1.setAge(27);
System.out.println(s1.getName()+"---"+s1.getAge());

//方式2
Student s2 = new Student("林青霞",27);
System.out.println(s2.getName()+"---"+s2.getAge());

//补齐老师类中的代码并进行测试。
}
}
运行结果:
Java基础:继承、多态、抽象、接口
(2)猫狗案例讲解
/*
猫狗案例讲解

先找到具体的事物,然后发现具体的事物有共性,才提取出一个父类。

猫:
成员变量:姓名,年龄,颜色
构造方法:无参,带参
成员方法:
getXxx()/setXxx()
eat()
palyGame()
狗:
成员变量:姓名,年龄,颜色
构造方法:无参,带参
成员方法:
getXxx()/setXxx()
eat()
lookDoor()

共性:
成员变量:姓名,年龄,颜色
构造方法:无参,带参
成员方法:
getXxx()/setXxx()
eat()

把共性定义到一个类中,这个类的名字叫:动物。
动物类:
成员变量:姓名,年龄,颜色
构造方法:无参,带参
成员方法:
getXxx()/setXxx()
eat()

猫:
构造方法:无参,带参
成员方法:palyGame()
狗:
构造方法:无参,带参
成员方法:lookDoor()
*/
//定义动物类
class Animal {
//姓名
private String name;
//年龄
private int age;
//颜色
private String color;

public Animal() {}

public Animal(String name,int age,String color) {
this.name = name;
this.age = age;
this.color = color;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getColor() {
return color;
}

public void setColor(String color) {
this.color = color;
}

public void eat() {
System.out.println("不要睡了,该吃饭了");
}
}

//定义猫类
class Cat extends Animal {
public Cat() {}

public Cat(String name,int age,String color) {
super(name,age,color);
}

public void playGame() {
System.out.println("猫玩英雄联盟");
}
}

//定义狗类
class Dog extends Animal {
public Dog() {}

public Dog(String name,int age,String color) {
super(name,age,color);
}

public void lookDoor() {
System.out.println("狗看家");
}
}

//测试类
class ExtendsTest5 {
public static void main(String[] args) {
//测试猫
//方式1
Cat c1 = new Cat();
c1.setName("Tom");
c1.setAge(3);
c1.setColor("白色");
System.out.println("猫的名字是:"+c1.getName()+";年龄是:"+c1.getAge()+";颜色是:"+c1.getColor());
c1.eat();
c1.playGame();
System.out.println("---------------");

//方式2
Cat c2 = new Cat("杰瑞",5,"土豪金");
System.out.println("猫的名字是:"+c2.getName()+";年龄是:"+c2.getAge()+";颜色是:"+c2.getColor());
c2.eat();
c2.playGame();

//作业:测试狗
}
}
运行结果:
Java基础:继承、多态、抽象、接口

第二讲    多态

一、多态概述

1、某一个事物,在不同时刻表现出来的不同状态。
举例:猫可以是猫的类型。猫 m = new 猫();同时猫也是动物的一种,也可以把猫称为动物。动物 d = new 猫();
2、多态前提和体现
     有继承关系
     有方法重写
     有父类引用指向子类对象
3、多态中的成员访问特点:
     (1)成员变量:编译看左边,运行看左边。
     (2)构造方法:创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
     (3)成员方法:编译看左边,运行看右边。动态绑定
     (4)静态方法:编译看左边,运行看左边。(静态和类相关,算不上重写,所以,访问还是左边的)
当方法被 static private final三个关键字其中一个修饰,执行的静态绑定由于成员方法存在方法重写,所以它运行看右边。
/*
多态:同一个对象(事物),在不同时刻体现出来的不同状态。
举例:
猫是猫,猫是动物。
水(液体,固体,气态)。

多态的前提:
A:要有继承关系。
B:要有方法重写。
其实没有也是可以的,但是如果没有这个就没有意义。
动物 d = new 猫();
d.show();
动物 d = new 狗();
d.show();
C:要有父类引用指向子类对象。
父 f = new 子();

用代码体现一下多态。
*/
class Fu {
public int num = 100;

public void show() {
System.out.println("show Fu");
}

public static void function() {
System.out.println("function Fu");
}
}

class Zi extends Fu {
public int num = 1000;
public int num2 = 200;

public void show() {
System.out.println("show Zi");
}

public void method() {
System.out.println("method zi");
}

public static void function() {
System.out.println("function Zi");
}
}

class DuoTaiDemo {
public static void main(String[] args) {
//要有父类引用指向子类对象。
//父 f = new 子();
Fu f = new Zi();
System.out.println(f.num);
//找不到符号
//System.out.println(f.num2);

f.show();
//找不到符号
//f.method();
f.function();
}
}

二、多态的好处和弊端

1、多态的好处

提高了程序的维护性(由继承保证)
提高了程序的扩展性(由多态保证)

2、多态的弊端

不能访问子类特有功能
那么我们如何才能访问子类的特有功能呢?
A:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了)
B:把父类的引用强制转换为子类的引用。(向下转型)

3、多态中的转型问题

向上转型:从子到父,父类引用指向子类对象。
向下转型:从父到子,父类引用转为子类对象。
/*
多态的弊端:
不能使用子类的特有功能。

我就想使用子类的特有功能?行不行?
行。

怎么用呢?
A:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了)
B:把父类的引用强制转换为子类的引用。(向下转型)

对象间的转型问题:
向上转型:
Fu f = new Zi();
向下转型:
Zi z = (Zi)f; //要求该f必须是能够转换为Zi的。
*/
class Fu {
public void show() {
System.out.println("show fu");
}
}

class Zi extends Fu {
public void show() {
System.out.println("show zi");
}

public void method() {
System.out.println("method zi");
}

}

class DuoTaiDemo4 {
public static void main(String[] args) {
//测试
Fu f = new Zi();
f.show();
//f.method();

//创建子类对象
//Zi z = new Zi();
//z.show();
//z.method();

//你能够把子的对象赋值给父亲,那么我能不能把父的引用赋值给子的引用呢?
//如果可以,但是如下
Zi z = (Zi)f;
z.show();
z.method();
}
}
运行结果:
Java基础:继承、多态、抽象、接口
4、多态继承中的内存图解Java基础:继承、多态、抽象、接口
5、多态中的对象变化内存图解Java基础:继承、多态、抽象、接口

第三讲    抽象类

一、抽象类概述

     回想前面我们的猫狗案例,提取出了一个动物类。并且我们在前面也创建过了动物对象,其实这是不对的。为什么呢?因为,我说动物,你知道我说的是什么动物吗?只有看到了具体的动物,你才知道,这是什么动物。 所以说,动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫,狗才是具体的动物。同理,我们也可以推想,不同的动物吃的东西应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。

二、抽象类特点

1、抽象类和抽象方法必须用abstract关键字修饰
2、格式:
            abstract class 类名 {}
            public abstract void eat();
3、抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
4、抽象类不能实例化
     那么,抽象类如何实例化呢?按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
5、抽象类的子类
     要么是抽象类
     要么重写抽象类中的所有抽象方法
/*
抽象类的概述:
动物不应该定义为具体的东西,而且动物中的吃,睡等也不应该是具体的。
我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类。

抽象类的特点:
A:抽象类和抽象方法必须用abstract关键字修饰
B:抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
C:抽象类不能实例化
因为它不是具体的。
抽象类有构造方法,但是不能实例化?构造方法的作用是什么呢?
用于子类访问父类数据的初始化
D:抽象的子类
a:如果不想重写抽象方法,该子类是一个抽象类。
b:重写所有的抽象方法,这个时候子类是一个具体的类。

抽象类的实例化其实是靠具体的子类实现的。是多态的方式。
Animal a = new Cat();
*/

//abstract class Animal //抽象类的声明格式
abstract class Animal {
//抽象方法
//public abstract void eat(){} //空方法体,这个会报错。抽象方法不能有主体
public abstract void eat();

public Animal(){}
}

//子类是抽象类
abstract class Dog extends Animal {}

//子类是具体类,重写抽象方法
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
}

class AbstractDemo {
public static void main(String[] args) {
//创建对象
//Animal是抽象的; 无法实例化
//Animal a = new Animal();
//通过多态的方式
Animal a = new Cat();
a.eat();
}
}
运行结果:
Java基础:继承、多态、抽象、接口

2、抽象类的成员特点

(1)成员变量
可以是变量,也可以是常量
(2)构造方法
有构造方法,但是不能实例化,那么,构造方法的作用是什么呢?用于子类访问父类数据的初始化
(3)成员方法
可以有抽象方法 限定子类必须完成某些动作,也可以有非抽象方法 提高代码服用性
/*
抽象类的成员特点:
成员变量:既可以是变量,也可以是常量。
构造方法:有。
用于子类访问父类数据的初始化。
成员方法:既可以是抽象的,也可以是非抽象的。

抽象类的成员方法特性:
A:抽象方法 强制要求子类做的事情。
B:非抽象方法 子类继承的事情,提高代码复用性。
*/
abstract class Animal {
public int num = 10;
public final int num2 = 20;

public Animal() {}

public Animal(String name,int age){}

public abstract void show();

public void method() {
System.out.println("method");
}
}

class Dog extends Animal {
public void show() {
System.out.println("show Dog");
}
}

class AbstractDemo2 {
public static void main(String[] args) {
//创建对象
Animal a = new Dog();
a.num = 100;
System.out.println(a.num);
//a.num2 = 200;
System.out.println(a.num2);
System.out.println("--------------");
a.show();
a.method();
}
}
运行结果:
Java基础:继承、多态、抽象、接口

第四讲    接口

一、接口概述

       继续回到我们的猫狗案例,我们想想狗一般就是看门,猫一般就是作为宠物了,对不。但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的,对不。所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可。

二、接口特点

1、接口用关键字interface表示
     格式:interface 接口名 {}
2、类实现接口用implements表示
     格式:class 类名 implements 接口名 {}
3、接口不能实例化
     那么,接口如何实例化呢?按照多态的方式,由具体的子类实例化。其实这也是多态的一种,接口多态。
4、接口的子类
     要么是抽象类
     要么重写接口中的所有抽象方法

三、接口成员特点

1、成员变量
     只能是常量,默认修饰符 public static final
2、构造方法
     没有,因为接口主要是扩展功能的,而没有具体存在
3、成员方法
     只能是抽象方法,默认修饰符 public abstract

四、类、接口之间的关系

1、类与类
     继承关系,只能单继承,但是可以多层继承
2、类与接口
     实现关系,可以单实现,也可以多实现。还可以在继承一个类的同时实现多个接口
3、接口与接口
     继承关系,可以单继承,也可以多继承

五、抽象类和接口的区别

Java基础:继承、多态、抽象、接口

六、接口练习

1、猫狗案例,加入跳高的额外功能

/*
猫狗案例,加入跳高的额外功能

分析:从具体到抽象
猫:
姓名,年龄
吃饭,睡觉
狗:
姓名,年龄
吃饭,睡觉

由于有共性功能,所以,我们抽取出一个父类:
动物:
姓名,年龄
吃饭();
睡觉(){}

猫:继承自动物
狗:继承自动物

跳高的额外功能是一个新的扩展功能,所以我们要定义一个接口
接口:
跳高

部分猫:实现跳高
部分狗:实现跳高
实现;
从抽象到具体

使用:
使用具体类
*/
//定义跳高接口
interface Jumpping {
//跳高功能
public abstract void jump();
}

//定义抽象类
abstract class Animal {
//姓名
private String name;
//年龄
private int age;

public Animal() {}

public Animal(String name,int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

//吃饭();
public abstract void eat();

//睡觉(){}
public void sleep() {
System.out.println("睡觉觉了");
}
}

//具体猫类
class Cat extends Animal {
public Cat(){}

public Cat(String name,int age) {
super(name,age);
}

public void eat() {
System.out.println("猫吃鱼");
}
}

//具体狗类
class Dog extends Animal {
public Dog(){}

public Dog(String name,int age) {
super(name,age);
}

public void eat() {
System.out.println("狗吃肉");
}
}

//有跳高功能的猫
class JumpCat extends Cat implements Jumpping {
public JumpCat() {}

public JumpCat(String name,int age) {
super(name,age);
}

public void jump() {
System.out.println("跳高猫");
}
}

//有跳高功能的狗
class JumpDog extends Dog implements Jumpping {
public JumpDog() {}

public JumpDog(String name,int age) {
super(name,age);
}

public void jump() {
System.out.println("跳高狗");
}
}

class InterfaceTest {
public static void main(String[] args) {
//定义跳高猫并测试
JumpCat jc = new JumpCat();
jc.setName("哆啦A梦");
jc.setAge(3);
System.out.println(jc.getName()+"---"+jc.getAge());
jc.eat();
jc.sleep();
jc.jump();
System.out.println("-----------------");

JumpCat jc2 = new JumpCat("加菲猫",2);
System.out.println(jc2.getName()+"---"+jc2.getAge());
jc2.eat();
jc2.sleep();
jc2.jump();

//定义跳高狗并进行测试的事情自己完成。
}
}
运行结果:
Java基础:继承、多态、抽象、接口

2、老师和学生案例,加入抽烟的额外功能

/*
老师和学生案例,加入抽烟的额外功能

分析:从具体到抽象
老师:姓名,年龄,吃饭,睡觉
学生:姓名,年龄,吃饭,睡觉

由于有共性功能,我们提取出一个父类,人类。

人类:
姓名,年龄
吃饭();
睡觉(){}

抽烟的额外功能不是人或者老师,或者学生一开始就应该具备的,所以,我们把它定义为接口

抽烟接口。

部分老师抽烟:实现抽烟接口
部分学生抽烟:实现抽烟接口

实现:从抽象到具体

使用:具体
*/
//定义抽烟接口
interface Smoking {
//抽烟的抽象方法
public abstract void smoke();
}

//定义抽象人类
abstract class Person {
//姓名
private String name;
//年龄
private int age;

public Person() {}

public Person(String name,int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

//吃饭();
public abstract void eat();

//睡觉(){}
public void sleep() {
System.out.println("睡觉觉了");
}
}

//具体老师类
class Teacher extends Person {
public Teacher() {}

public Teacher(String name,int age) {
super(name,age);
}

public void eat() {
System.out.println("吃大白菜");
}
}

//具体学生类
class Student extends Person {
public Student() {}

public Student(String name,int age) {
super(name,age);
}

public void eat() {
System.out.println("吃红烧肉");
}
}

//抽烟的老师
class SmokingTeacher extends Teacher implements Smoking {
public SmokingTeacher() {}

public SmokingTeacher(String name,int age) {
super(name,age);
}

public void smoke() {
System.out.println("抽烟的老师");
}
}

//抽烟的学生
class SmokingStudent extends Student implements Smoking {
public SmokingStudent() {}

public SmokingStudent(String name,int age) {
super(name,age);
}

public void smoke() {
System.out.println("抽烟的学生");
}
}

class InterfaceTest2 {
public static void main(String[] args) {
//测试学生
SmokingStudent ss = new SmokingStudent();
ss.setName("林青霞");
ss.setAge(27);
System.out.println(ss.getName()+"---"+ss.getAge());
ss.eat();
ss.sleep();
ss.smoke();
System.out.println("-------------------");

SmokingStudent ss2 = new SmokingStudent("刘意",30);
System.out.println(ss2.getName()+"---"+ss2.getAge());
ss2.eat();
ss2.sleep();
ss2.smoke();

//测试老师留给自己练习
}
}
运行结果:
Java基础:继承、多态、抽象、接口

第五讲    权限修饰符

Java基础:继承、多态、抽象、接口