JAVA学习day09 JavaSE基础——多态、抽象类、接口
1、多态
1.1 多态概述
多态是继封装、继承之后,Java面对对象的第三大特征。Java作为面对对象的语言,可以用来描述一个事物的多种形态。如一个Student类继承了Person类,一个Student类的对象既可以是Student,也可以是Person。
Java中多态的代码体现在一个子类继承父类后,这个子类的对象(实例化对象)既可以给子类的变量赋值,也可以给这个子类的父类变量赋值。
多态的目的之一就是子类重写父类方法。
最终多态的体现为一个父类引用可以指向子类对象。
1.2 多态的定义格式
父类类型 变量名 = new 子类类型();
代码体现:
public class Person {
public void eat(){
}
}
public class Student extends Person {
@Override
public void eat() {
System.out.println("学生爱吃炸鸡");
}
}
public class Test {
public static void main(String[] args) {
Student stu = new Student();
Person p = new Student();
stu.eat();
p.eat();
}
}
1.3 多态中的成员访问特点
● 成员变量
编译看左边,运行看左边;
● 成员方法
编译看左边,运行看右边;
● 构造方法
创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化;
看如下代码:
public class Fu {
int num = 10;
public void show(){
System.out.println("fu show");
}
}
public class Zi extends Fu {
int num = 20;
@Override
public void show() {
System.out.println("zi show");
}
}
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println(zi.num);
zi.show();
Fu fu = new Zi();
System.out.println(fu.num);
fu.show();
}
}
运行结果:
图 1-1 运行结果截图
在上面的测试类中我创建了两个子类的对象,一个用多态的父类引用指向子类对象,也就是多态,另一个是子类自己的引用对象,分别用这两个对象去调用成员变量和成员方法,可以看到在访问成员变量时,编译和运行都看左边,访问成员方法时,编译看左边,运行看右边,所以fu.show() 打印出来是 zi show。
1.4 多态的好处
提高了代码的维护性(继承)和扩展性(多态)。
1.5多态的弊端以及多态中的向上转型和向下转型
● 多态的弊端:不能访问子类特有的功能;
● 解决弊端:
把父类的引用类型强制向下转型;向上转型其实就是说的多态;
看下面一段代码:
public class Animal {
public void eat(){
}
public void sleep(){
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫白天睡觉");
}
//子类特有的功能
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
public class Test {
public static void main(String[] args) {
Animal an = new Cat();
an.eat();
an.sleep();
// an.catchMouse(); 父类引用不能访问子类特有的功能
//向下转型
Cat c = (Cat) an;
c.catchMouse();
}
}
运行结果:
图 1-2 运行结果截图
1.6 多态中的内存图解
2. 抽象类
2.1 抽象类的概述
当编写一个类时,我们往往会为该类定义一些方法,这些方法是用来描述该类的功能具体实现方式,那么这些方法都有具体的方法体。但是有的时候,某个父类只是知道子类应该包含怎么样的方法,但是无法准确知道子类如何实现这些方法。比如一个图形类应该有一个求周长的方法,但是不同的图形求周长的算法不一样。那该怎么办呢?
分析事物时,发现了共性内容,就出现向上抽取。会有这样一种特殊情况,就是方法功能声明相同,但方法功能主体不同。那么这时也可以抽取,但只抽取方法声明,不抽取方法主体。那么此方法就是一个抽象方法。
当定义了抽象方法的类也必须被abstract关键字修饰,被abstract关键字修饰的类是抽象类。
2.2 抽象类和抽象方法的定义
// 抽象类
public abstract class 类名{
//抽象方法
public abstract 返回值类型 方法名();
}
2.3 抽象类的特点
(1)抽象类和抽象方法都需要被abstract 修饰;抽象方法一定要定义在抽象类中。
(2)抽象类不能直接创建对象,但抽象类中有构造方法,这是因为子类继承抽象类时在创建对象时用于给父类中的数据进行初始化。
(3)抽象类要实现实例化需要通过子类的实例化实现。
(4)抽象类中有抽象方法时,继承它的子类必须重写抽象方法,否则子类也还是抽象类。
2.5抽象类中的成员特点
● 抽象类的成员特点: 成员变量既可以是变量,也可以是常量。 成员方法既可以是抽象的,也可以是非抽象的。
● 抽象类的成员方法特性:
抽象方法强制要求子类重写,非抽象方法子类可以继承。
2.6 代码练习抽象类
假如我们在开发一个系统时需要对员工(Employee)类进行设计,员工包含3个属性:姓名、工号以及工资(salary)。
经理(Manager)也是员工,除了含有员工的属性外,另为还有一个奖金(bonus)属性。
然后定义工作的方法.
请使用继承的思想设计出员工类和经理类。
public abstract class Employee {
String name;
double salary;
int jobNumber;
public abstract void work();
}
public class Manager extends Employee {
int bonus;
@Override
public void work() {
System.out.println("经理在管理员工");
}
}
public class Test {
public static void main(String[] args) {
Employee employee = new Manager();
employee.name = "张三";
employee.jobNumber = 700;
employee.salary = 16000;
Manager manager = (Manager) employee;
manager.bonus = 3000;
System.out.println("经理:"+employee.name+"\r\n"+"工号:"
+employee.jobNumber+"\r\n"+"工资:"+employee.salary+"\r\n"+"奖金:"+((Manager) employee).bonus);
employee.work();
}
}
运行结果:
图 1-3 运行结果截图
3. 接口
3.1 接口概述
在Java中,接口可以看做是功能的集合,同样可以看作是比抽象类更抽象的类。
在接口中,只描述了应该具备的方法,但没有具体的实现,具体的实现由接口的实现类来完成。
3.2 接口的定义
与定义类不同,接口定义时需要用到 interface 关键字。
//定义格式
public interface 接口名{
抽象方法1;
抽象方法2;
......
}
● 接口中的方法均为公共访问的抽象方法,方法默认修饰符加了 public abstract ;
● 接口中无法定义普通的成员变量;接口中成员变量相当于常量,默认修饰符:public static final
3.3 类与类 ,类与接口, 接口与接口的关系
类与类:继承关系,只支持单继承,可以多层继承;
类与接口:实现关系,支持单实现和多实现;并且还可以在继承一个类的同时实现多个接口;
接口与接口:继承关系,可以单继承和多继承。
3.4 抽象类和接口的区别
● 抽象类:
成员变量:可以是变量,也可以是常量;
成员方法:可以是抽象方法,也可以是非抽象方法;
构造方法:有构造方法;
● 接口:
成员变量:只能是常量;
成员方法:默认修饰符 public abstract ,只能是抽象方法。
3.5 接口案例
public interface MyInterface {
public abstract void sing();
public abstract void jump();
public abstract void rap();
public abstract void showInformation();
}
public abstract class Person {
String name;
int age;
char sex;
public Person(String name, int age, char sex ){
this.name = name;
this.age = age;
this.sex = sex;
}
public abstract void eat();
public abstract void sleep();
}
public class Student extends Person implements MyInterface{
public Student(String name, int age, char sex) {
super(name, age, sex);
}
@Override
public void eat() {
System.out.println(this.name+"爱吃鸡");
}
@Override
public void sleep() {
System.out.println(this.name+"睡觉很晚");
}
@Override
public void sing() {
System.out.println(this.name+"会唱歌");
}
@Override
public void jump() {
System.out.println(this.name+"会跳舞");
}
@Override
public void rap() {
System.out.println(this.name+"会rap");
}
@Override
public void showInformation() {
System.out.println("姓名:"+this.name+"\r\n"+"年龄:"+this.age+"\r\n"+"性别:"+this.sex);
}
}
public class MyTest {
public static void main(String[] args) {
Student student = new Student("张三",21,'男');
student.showInformation();
student.eat();
student.sleep();
student.sing();
student.jump();
student.rap();
}
}
运行结果:
图 1-4 运行结果截图