Java 面向对象-多态
1.多态概述
什么是多态?
多种状态,通一个对象在不同情况下表现出不同的状态或行为
Java中实现多态的步骤
·要有继承(或实现)关系
·要有方法重写
·父类引用指向子类对象(is a 关系)
例子:
//定义父类 Animal public class Animal { //成员变量 //姓名 private String name; //成员方法 public void eat(){ System.out.println("正在吃东西"); } //构造方法 //无参构造 public Animal() { } //带参构造 public Animal(String name) { this.name = name; } //公共访问方式:getXXX() ,setXXX() public void setName(String name) { this.name = name; } public String getName() { return name; } }
//定义子类 Dog public class Dog extends Animal{ //需求:狗吃骨头,所以要优化父类中的eat()方法 public void eat(){ System.out.println(this.getName()+"正在吃骨头"); } }
//测试类 public class Test { /* 动物案例: 已知父类Animal ,成员变量为:姓名 成员方法:eat() 其有一子类Dog,请用该案例模拟多态 */ public static void main(String[] args) { //演示多态 /* Java中实现多态的三个步骤 1.要有继承(或实现)关系 2.要有方法重写 3.要有父类引用指向子类对象 */ //多态 Animal an = new Dog(); an.setName("哈士奇"); an.eat(); } }
运行结果:
多态关系中成员方法的使用
需求:父类型变量作为参数时,可以接收任意子类对象
分析:
A:定义方法,参数类型为父类型Animal
showAnimal(Animal animal)
B:分别创建Dog类和Mouse类
C:调用showAnimal方法演示效果
//定义父类 Animal public class Animal { //成员变量 private String name; //成员方法 public void eat() { System.out.println("吃饭"); } //构造方法 //无参构造 public Animal() { } //带参构造 public Animal(String name) { this.name = name; } //公共访问方式:getXXX() ,setXXX() public void setName(String name) { this.name = name; } public String getName() { return name; } }
//定义子类 Dog public class Dog extends Animal { //成员方法 public void eat(){ System.out.println(this.getName()+"吃骨头"); } }
//定义子类 Mouse public class Mouse extends Animal{ public void eat(){ System.out.println(this.getName()+"吃奶酪"); } }
//测试类 public class Test { public static void main(String[] args) { /* 需求: 定义方法,参数类型为父类型Animal showAnimal(Animal animal) 分别创建Dog类和Mouse类 调用showAnimal方法演示效果 */ //用来测试Dog类和Mouse类 Dog d = new Dog(); d.setName("哈士奇"); showAnimal(d); Mouse m = new Mouse(); m.setName("Jerry"); showAnimal(m); System.out.println("=============="); //多态的作用 Animal dog = new Dog(); dog.setName("狗"); Animal mouse = new Mouse(); mouse.setName("老鼠"); showAnimal(dog); showAnimal(mouse); } //传统做法 //需求:在该类中定义showAnimal方法 public static void showAnimal(Dog d){ d.eat(); } public static void showAnimal(Mouse m){ m.eat(); } //多态的做法 public static void showAnimal(Animal an){ an.eat(); } }
运行结果:
多态关系中成员变量的使用
需求:子父类中定义了同名的成员变量,如何调用
分析
A:子类中定义同名属性name并分别初始化值
String name;
B:在测试类中以多态的方式创建对象并打印name属性值:Animal animal = new Dog();
C:在测试类中以普通方式创建对象并打印name属性值:Dog dog = new Dog();
//定义父类 Animal public class Animal { String name = "Animal"; }
//定义子类 Dog public class Dog extends Animal{ String name = "Dog"; }
//测试类 public class Test { public static void main(String[] args) { Animal an = new Dog(); System.out.println(an.name);//Animal Dog dog = new Dog(); System.out.println(dog.name);//Dog } }
运行结果:
结论:
多态关系中成员变量是不能重写
2.多态的好处和弊端
多态的好处
·可维护性:基于继承关系,只需要维护父类代码,提高了代码的复用性,大大大降低了维护程序的工作量
·可拓展性:把不同的子类对象都当做父类看待,屏蔽了不同子类对象间的差异,做出通用的代码,以适应不同的需求
多态的弊端
不能使用子类特有成员
解决方案:
类型转换
当需要子类特有功能时,需要进行类型转换
向上转型(自动型转换)
-子类型转换成父类型
Animal animal = new Dog();
向下转型(强制转换)
-父类型转换成子类型
Dog dog =(Dog)animal;
注意事项
·只能在继承层次捏进行转换(ClassCastException)
·将父类对象转换成子类型之前,使用instanceof进行检查
if(an.instanceof Dog){ //判断an是否时Dog类型的对象
//是Dog类型对象
Dog dog =(Dog)animal;
}
4.抽象类的特点
抽象类的特点
1.修饰符:必须用abstract关键字修饰
-修饰符 abstract class 类名{}
-修饰符 abstract 返回值类型 方法名();
2.抽象类不能被实例化,只能创建子类对象
3.抽象类的子类只有两个选择
-重写父类所有抽象方法
-定义成抽象类
抽象类的成员特点
1.成员变量:
可以有普通的成员方法
也可以有成员常量(final)
2.成员方法:
可以有普通方法,也可以有抽象方法
抽象类不一定有抽象方法,有抽象方法的类一定是抽象类(或接口)
3.构造方法:
像普通类一样有构造方法
案例:
需求:开发团队中有程序员和经理两种角色,他们都有姓名、工资、工号等属性,都有工作行为,经理还要奖金属性。请使用继承思想设计出上述需求中的类,并分别创建对象使用
分析
A:经理和程序员都是员工,把他们的共同的属性和行为定义子在父类Employee中,由于并不明确工作的具体内容,所以父类中工作的方法定义成抽象方法;
name ,salary, id , work()
B:定义经理类Manager,继承Employee,属性和行为:bonus;work();
C:定义程序员类Coder,继承Employee,属性和行为:work();
D:在测试类中分别创建对象并使用
//定义一个父类 抽象类 Employee public abstract class Employee { //成员变量 //姓名 private String name; //工号 private String id; //工资 private double salary; //成员方法 抽象方法 //工作 public abstract void work(); //公共访问方式 public void setName(String name) { this.name = name; } public void setId(String id) { this.id = id; } public void setSalary(double salary) { this.salary = salary; } public String getName() { return name; } public String getId() { return id; } public double getSalary() { return salary; } //构造方法 //无参构造 public Employee() { } //全参构造 public Employee(String name, String id, double salary) { this.name = name; this.id = id; this.salary = salary; } }
//定义一个子类 Manager 经理类继承父类 Employee public class Manager extends Employee{ //成员变量 //奖金 private double bonus; //实现抽象方法 public void work() { System.out.println(this.getName()+"正在监督"); } //公共访问方式 public void setBonus(double bonus) { this.bonus = bonus; } public double getBonus() { return bonus; } //构造方法 public Manager() { } public Manager(String name, String id, double salary, double bonus) { super(name, id, salary); this.bonus = bonus; } }
//定义一个子类 Coder 程序员类 继承抽象类 Employee public class Coder extends Employee{ //实现抽象方法 public void work() { System.out.println(this.getName()+"正在写代码"); } //构造方法 public Coder() { } public Coder(String name, String id, double salary) { super(name, id, salary); } }
//测试类 /* 需求:开发团队中有程序员和经理两种角色,他们都有姓名、工资、工号等属性,都有工作行为, 经理还要奖金属性。请使用继承思想设计出上述需求中的类,并分别创建对象使用 分析: A:经理和程序员都是员工,把他们的共同的属性和行为定义子在父类Employee中, 由于并不明确工作的具体内容,所以父类中工作的方法定义成抽象方法; name ,salary, id , work() B:定义经理类Manager,继承Employee,属性和行为:bonus;work(); C:定义程序员类Coder,继承Employee,属性和行为:work(); D:在测试类中分别创建对象并使用 */ public class Test { public static void main(String[] args) { //创建经理对象 Employee manager = new Manager(); manager.setName("张三"); manager.work(); //创建程序员类 Employee coder = new Coder(); coder.setName("李四"); coder.work(); } }
运行结果:
5.final关键字
final的概念
最终的、最后的
final 的作用
1.修饰类:该类不能被继承
String,System
2.修饰方法:该方法不能被重写
不能与abstract共存
3.修饰变量:最终变量,即常量,只能赋值异常
不建议修饰引用类型数据,因为仍然可以通过引用修改对象的内部数据,意义不大
6.static关键字
static 的概念
静态的
static 的作用
用于修饰类的成员:
1.成员变量:类变量
2.成员方法:类方法
调用方式:
类名.成员变量;
类名.成员方法(参数);
static 修饰成员变量
特点:被本类所有对象共享
-随意修改静态变量的值是有风险的,为了降低风险,可以同时用final关键字修饰,即公有静态常量(注意命名的变化)
static 修饰成员方法
1.静态方法
-静态方法中没有对象this,所以不能访问非静态成员
2.静态方法的使用场景
-只需要访问静态成员
-不需要访问对象状态,所需参数都由参数列表显示提供
7.接口概述
接口的概念
接口技术用于描述具有什么功能,但并不给出具体实现,类要遵守从接口描述的统一规则进行定义,所以,接口时对外提供的一组规则、标准
接口的定义
·定义接口使用关键字 interface
interface 接口名{}
·类和接口是实现关系,用implements表示
class 类名 implements 接口名
接口的特点
接口创建对象的特点:
1.接口不能实例化
通过多态的方式实例化子类对象
2.接口的子类(实现类)
可以是抽象类,也可以是普通类
如果是抽象类,不要重写接口的方法,如果是普通类,必须重写所有接口方法
接口继承关系的特点:
1.接口与接口之间的关系
继承关系,可以多继承,格式
接口 extends 接口1,接口2,接口3.....
2.继承和实现的区别
继承体系的是”is a“的关系,父类中定义共性内容
实现体系的是”like a “的关系,接口中定义扩展功能
8.接口成员的特点
接口成员变量的特点
接口没有成员变量,只有公有的、静态的常量
public static final 常量名 = 常量值;
接口成员方法的特点
JDK7之前,公有的、抽象方法:
public abstract 返回值 方法名()
JDK8之后,可以有默认方法和静态方法:
public default 返回值类型 方法名(){}
JDK9之后,可以有私有方法:
private 返回值类型 方法名(){}
接口构造方法的特点
接口不能够实例化,也没有需要初始化的成员
所以接口没有构造方法