学习自华为开发者学院陈璇老师的JAVA系列课程
三、方法重写
3.1 重写的定义
在有父子类关系的两个类中的同名方法
3.2 super关键字的功能
通过supper访问父类的成员
需要父类中的成员是非private
3.3 super关键字的使用
super使用场景:
- 子类方法重写父类方法
-
在子类中定义了和父类同名的成员变量,super可以使被屏蔽的成员可见
案例1 宠物类:
Pet.java:
//父类:提取共性的代码
public class Pet {
private String name = "无名氏"; //昵称
private int health = 100; //健康值,默认100,0~100之间,小于60为不健康
private int love = 0; //亲密度
private String strain = "聪明的拉布拉多犬"; //品种
int age = 1;
public Pet(){
System.out.println("父类无参构造方法");
}
public Pet(String name){
this.name = name;
System.out.println("父类带参构造方法");
}
public Pet(String name, int health, int love){
//this(name); //this可调用本类的构造方法,且必须放在第一行
this.name = name;
this.health = health;
this.love = love;
System.out.println("父类带参构造方法");
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setHealth(int health){
if(health<0 || health>100){
System.out.println("宠物的健康值只能在0~100之间!");
this.health = 60;
return;
}
this.health = health;
}
public int getHealth(){
return this.health;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setLove(int love){
if(love<0 || love>100){
System.out.println("宠物的亲密度只能在0~100之间!");
this.love = 60;
return;
}
this.love = love;
}
public int getLove(){
return this.love;
}
/*
* 输出宠物信息
*/
public void print(){
System.out.println("宠物的自白:\n我的名字叫" + this.name +
",健康值是" + this.health + ",和主人的亲密度是"
+ this.love);
}
}
Dog.java:
/*
* 宠物狗类
*/
public class Dog extends Pet{
//1. 隐藏属性
private String strain = "聪明的拉布拉多犬"; //品种
private int age = 10;
public Dog(){
System.out.println("子类狗狗的无参构造方法");
}
public Dog(String name, int health, int love, String strain){
//通过super调用父类的构造方法,且必须是第一行
//super();
super(name, health, love);
this.strain = strain;
System.out.println("子类狗狗的带参构造方法");
}
//添加属性的setter/getter方法,并加入属性控制语句
public void setStrain(String strain){
this.strain = strain;
}
public String getStrain(){
return this.strain;
}
//重写print()方法
public void print() {
//调用父类的非private的print()
super.print();
System.out.println("我是一只:"+this.strain);
}
public void m1(){
//super不可以调用父类的private属性
//System.out.println(super.name);
//super可以调用父类的非private属性
System.out.println(super.age);
}
public void m2(){
//子类会覆盖父类的同名成员
System.out.println(this.age);
//可以使用super调用父类被子类覆盖的同名成员
System.out.println(super.age);
}
}
Penguin.java:
/*
* 宠物企鹅类
*/
public class Penguin extends Pet{
private String sex = "Q仔";
public void setSex(String sex) {
this.sex = sex;
}
public String getSex() {
return this.sex;
}
//重写print()方法
public void print() {
//调用父类的非private的print()
super.print();
System.out.println("我的性别是:"+this.sex);
}
}
TestPet.java:
import java.util.Scanner;
public class TestPet {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("欢迎您来到宠物店!");
System.out.print("请输入要领养宠物的名字:");
String name = input.next();
System.out.print("请输入要领养宠物的类型:1、狗狗;2、企鹅 ");
int typeNo = input.nextInt();
switch (typeNo){
case 1:
//创建狗狗对象
// Dog dog = new Dog();
// dog.setName(name);
// //狗狗其他属性
// dog.setHealth(-1000);
// System.out.println(dog.getHealth());
//
// dog.setLove(-9);
//
// dog.setStrain("吉娃娃");
// dog.print();
// dog.m1();
Dog dog = new Dog("多多", 100, 89, "吉娃娃");
dog.print();
dog.m2();
break;
case 2:
//接受用户键盘录入信息
System.out.print("请输入企鹅的性别:1、Q妹;2、Q仔 ");
int SexId = input.nextInt();
String sex = (SexId==1) ? "Q妹" : "Q仔";
System.out.print("请输入企鹅的健康值:");
int health = input.nextInt();
System.out.print("请输入企鹅的亲密度:");
int love = input.nextInt();
//创建企鹅对象
Penguin p = new Penguin();
p.setName(name);
p.setSex(sex);
p.setHealth(health);
p.setLove(love);
p.print();
break;
default:
System.out.println("暂时没有这个类型的宠物!");
break;
}
}
}
注意问题:
- Java只支持单根继承
- 一个类只能有一个直接父类
- 一个类可以有多个间接父类
- 继承并非越复杂越好
- 继承树分支太多,旁支不好扩展
- 虚拟机对分支复杂的继承关系,会出现多态绑定的问题
- 继承关系越复杂,对象模型就越复杂,不利于程序扩展和维护
一般开发代码:2~3层的继承关系就可以了
案例2:super调用父类的父类的成员:
Animal.java:
package cn.com.superdemo;
//爷爷类:动物类
public class Animal
{
private int age;
private String sex;
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void print(){
System.out.println("爷爷类的一个方法");
}
}
Person.java:
package cn.com.superdemo;
//父类:人类
public class Person extends Animal{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Student.java:
package cn.com.superdemo;
//孙子类:学生类
public class Student extends Person{
private String sid;
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public void print(){
//调用父类的父类的方法,也是通过super.就可以了,而不用super.super.
super.print();
System.out.println("孙子类");
}
public static void main(String[] args) {
Student s = new Student();
s.print();
}
}
3.4 继承下的构造方法
验证1:
TestPet.java
import java.util.Scanner;
public class TestPet {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("欢迎您来到宠物店!");
System.out.print("请输入要领养宠物的名字:");
String name = input.next();
System.out.print("请输入要领养宠物的类型:1、狗狗;2、企鹅 ");
int typeNo = input.nextInt();
switch (typeNo){
case 1:
//创建狗狗对象
Dog dog = new Dog();
dog.setName(name);
//狗狗其他属性
dog.setHealth(-1000);
System.out.println(dog.getHealth());
dog.setLove(-9);
dog.setStrain("吉娃娃");
dog.print();
// dog.m1();
// Dog dog = new Dog("多多", 100, 89, "吉娃娃");
// dog.print();
// dog.m2();
break;
case 2:
//接受用户键盘录入信息
System.out.print("请输入企鹅的性别:1、Q妹;2、Q仔 ");
int SexId = input.nextInt();
String sex = (SexId==1) ? "Q妹" : "Q仔";
System.out.print("请输入企鹅的健康值:");
int health = input.nextInt();
System.out.print("请输入企鹅的亲密度:");
int love = input.nextInt();
//创建企鹅对象
Penguin p = new Penguin();
p.setName(name);
p.setSex(sex);
p.setHealth(health);
p.setLove(love);
p.print();
break;
default:
System.out.println("暂时没有这个类型的宠物!");
break;
}
}
}
输出:
欢迎您来到宠物店!
请输入要领养宠物的名字:多多
请输入要领养宠物的类型:1、狗狗;2、企鹅 1
父类无参构造方法
子类狗狗的无参构造方法
宠物的健康值只能在0~100之间!
60
宠物的亲密度只能在0~100之间!
宠物的自白:
我的名字叫多多,健康值是60,和主人的亲密度是60
我是一只:吉娃娃
Process finished with exit code 0
检查方法1:打印输出测试语句
检查方法2:在想测试的地方进行断点调试
验证2:
Dog.java:
/*
* 宠物狗类
*/
public class Dog extends Pet{
//1. 隐藏属性
private String strain = "聪明的拉布拉多犬"; //品种
private int age = 10;
public Dog(){
System.out.println("子类狗狗的无参构造方法");
System.out.println("子类狗狗带3个参数的构造方法");
}
public Dog(String name, int health, int love){
super(name, health, love);
System.out.println("子类狗狗带三个参数的构造方法");
}
public Dog(String name, int health, int love, String strain){
//通过super调用父类的构造方法,且必须是第一行
//super();
//super(name, health, love);
this(name, health, love);
this.strain = strain;
System.out.println("子类狗狗带4个参数的构造方法");
}
//添加属性的setter/getter方法,并加入属性控制语句
public void setStrain(String strain){
this.strain = strain;
}
public String getStrain(){
return this.strain;
}
//重写print()方法
public void print() {
//调用父类的非private的print()
super.print();
System.out.println("我是一只:"+this.strain);
}
public void m1(){
//super不可以调用父类的private属性
//System.out.println(super.name);
//super可以调用父类的非private属性
System.out.println(super.age);
}
public void m2(){
//子类会覆盖父类的同名成员
System.out.println(this.age);
//可以使用super调用父类被子类覆盖的同名成员
System.out.println(super.age);
}
}
TestPet.java:
import java.util.Scanner;
public class TestPet {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("欢迎您来到宠物店!");
System.out.print("请输入要领养宠物的名字:");
String name = input.next();
System.out.print("请输入要领养宠物的类型:1、狗狗;2、企鹅 ");
int typeNo = input.nextInt();
switch (typeNo){
case 1:
// //创建狗狗对象
// Dog dog = new Dog();
// dog.setName(name);
// //狗狗其他属性
// dog.setHealth(-1000);
// System.out.println(dog.getHealth());
//
// dog.setLove(-9);
//
// dog.setStrain("吉娃娃");
// dog.print();
// dog.m1();
Dog dog = new Dog("多多", 100, 89, "吉娃娃");
dog.print();
dog.m2();
break;
case 2:
//接受用户键盘录入信息
System.out.print("请输入企鹅的性别:1、Q妹;2、Q仔 ");
int SexId = input.nextInt();
String sex = (SexId==1) ? "Q妹" : "Q仔";
System.out.print("请输入企鹅的健康值:");
int health = input.nextInt();
System.out.print("请输入企鹅的亲密度:");
int love = input.nextInt();
//创建企鹅对象
Penguin p = new Penguin();
p.setName(name);
p.setSex(sex);
p.setHealth(health);
p.setLove(love);
p.print();
break;
default:
System.out.println("暂时没有这个类型的宠物!");
break;
}
}
}
输出:
欢迎您来到宠物店!
请输入要领养宠物的名字:多多
请输入要领养宠物的类型:1、狗狗;2、企鹅 1
父类带参构造方法
子类狗狗带三个参数的构造方法
子类狗狗带4个参数的构造方法
宠物的自白:
我的名字叫多多,健康值是100,和主人的亲密度是89
我是一只:吉娃娃
10
1
3.5 深入了解重写
由于多态具有动态绑定机制,JAVA虚拟机会判断绑定不同子类的相应方法。如果一旦子类的方法访问权限比父类的还小,于是绑定不上,所以多态执行会出现问题
方法重写与方法重载的区别:
方法重载:
- 写在同一个类里面
- 同名不同参
方法重写:
- 有继承关系的父子类中
- 同名同参
Father.java
//父类
public class Father {
void m1() {
System.out.println("父类的m1方法");
}
//方法重载: 在同一个类里面同名不同参的方法
public String m1(int num1) {
System.out.println("父类的m1方法");
return "Test";
}
//方法返回值类型可以是自定义的数据类型
public Father m2() {
System.out.println("父类的m2方法");
return new Father();
}
public static void m3() {
System.out.println("父类的静态方法m3");
}
private void m4() {
System.out.println("父类的私有方法m4");
}
}
Son.java:
//子类
public class Son extends Father{
//子类重写方法不可以比父类方法访问权限小,但可以扩大方法的访问权限
//子类方法只要不严于父类,就构成了方法重写
public void m1() {
System.out.println("子类重写后的m1方法");
}
//子类方法返回值类型可以是父类方法方法返回值类型的子类,也是方法重写
public Son m2() {
System.out.println("子类重写后的m2方法");
return new Son();
}
//父类的静态方法不能被重写为非静态方法
//反之,父类的非静态方法也不能被重写为静态方法
// public void m3() {
// System.out.println("子类的非静态方法m3");
// }
//在子类中可以定义和父类一模一样的静态方法,只是覆盖而非重写
public static void m3() {
//在静态方法中,不能使用super
//super.m3();
Father.m3();
System.out.println("子类的静态方法m3");
Son.m3();
}
//子类无法重写父类的private方法
public void m4() {
System.out.println("子类的私有方法m4");
}
public static void main(String[] args) {
Son son = new Son();
son.m1();
son.m2();
}
}
3.6 Object类
Object是所有类的直接或者间接父类
Object的equals() 与 == 作用相同(引用类型),判断两个对象是否为同一个对象
package cn.com.objdemo;
public class Student{
private int sid;
private String name;
private int age;
private int weight;
public Student() {}
public Student(int sid, String name, int age, int weight) {
this.sid = sid;
this.name = name;
this.age = age;
this.weight = weight;
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
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 int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public static void main(String[] args) {
Student s1 = new Student(1,"张三",18,50);
Student s2 = new Student(1,"张三",18,50);
//判断两个对象是否为同一个对象
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
Student s3 = s1; //传递的是地址
//判断两个对象是否为同一个对象
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));
}
}
3.7 重写Object类方法
package cn.com.objdemo;
public class Student{
private int sid;
private String name;
private int age;
private int weight;
public Student() {}
public Student(int sid, String name, int age, int weight) {
this.sid = sid;
this.name = name;
this.age = age;
this.weight = weight;
}
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
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 int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
//把equals()方法体自定义为我们自己的比较规则即可
//判断obj和this(当前学生对象)是否为同一对象
public boolean equals(Object obj) {
if (this == obj){
//内存地址相同
return true;
}
//如果传进来的obj对象不是Student类型,结果一定是false
if (!(obj instanceof Student)) {
return false;
}
//如果obj是Student类型
Student s = (Student)obj;
//比较s 和 this的sid及name 即可
if (this.sid == s.sid && this.name.equals(s.name)) {
return true;
}else{
return false;
}
}
//重写toString(): 返回学生姓名
public String toString() {
return this.name;
}
public static void main(String[] args) {
Student s1 = new Student(1,"张三",18,50);
Student s2 = new Student(1,"张三",18,50);
//判断两个对象是否为同一个对象
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
Student s3 = s1; //传递的是地址
//判断两个对象是否为同一个对象
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));
System.out.println("_______________________________________");
//输出一个对象时,等同于调用了它的toString()
System.out.println(s1.toString());
System.out.println(s1);
//String不仅重写了equals(),也重写了toString()方法
String s = "test";
System.out.println(s.toString());
System.out.println(s);
}
}
四、多态
4.1 多态的实现
多态:同一个引用类型,使用不同的实例而执行不同的不同的操作
父类类型(父类引用)指向子类对象,虽然传的是父类类型,实际传的是子类对象,JAVA虚拟机会根据具体父类类型指向的具体的子类对象,于是调用具体子类中重写以后的方法,JAVA运行时会去动态绑定,是多态的一种体现。JAVA虚拟机在多态的机制上,动态绑定相对具体对象相应重写以后的方法
继承和方法重写,是实现多态的基础。
Pet.java
//父类:提取共性的代码
public class Pet {
private String name = "无名氏"; //昵称
private int health = 100; //健康值,默认100,0~100之间,小于60为不健康
private int love = 0; //亲密度
private String strain = "聪明的拉布拉多犬"; //品种
// int age = 1;
public Pet(){
System.out.println("父类无参构造方法");
}
public Pet(String name){
this.name = name;
System.out.println("父类带参构造方法");
}
public Pet(String name, int health, int love){
//this(name); //this可调用本类的构造方法,且必须放在第一行
this.name = name;
this.health = health;
this.love = love;
System.out.println("父类带参构造方法");
}
// public int getAge() {
// return age;
// }
//
// public void setAge(int age) {
// this.age = age;
// }
//
public void setHealth(int health){
if(health<0 || health>100){
System.out.println("宠物的健康值只能在0~100之间!");
this.health = 60;
return;
}
this.health = health;
}
public int getHealth(){
return this.health;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setLove(int love){
if(love<0 || love>100){
System.out.println("宠物的亲密度只能在0~100之间!");
this.love = 60;
return;
}
this.love = love;
}
public int getLove(){
return this.love;
}
/*
* 输出宠物信息
*/
public void print(){
System.out.println("宠物的自白:\n我的名字叫" + this.name +
",健康值是" + this.health + ",和主人的亲密度是"
+ this.love);
}
//宠物生病后看病
public void toHospital() {
}
}
Dog.java
/*
* 宠物狗类
*/
public class Dog extends Pet{
//1. 隐藏属性
private String strain = "聪明的拉布拉多犬"; //品种
// private int age = 10;
public Dog(){
System.out.println("子类狗狗的无参构造方法");
System.out.println("子类狗狗带3个参数的构造方法");
}
public Dog(String name, int health, int love){
super(name, health, love);
System.out.println("子类狗狗带三个参数的构造方法");
}
public Dog(String name, int health, int love, String strain){
//通过super调用父类的构造方法,且必须是第一行
//super();
//super(name, health, love);
this(name, health, love);
this.strain = strain;
System.out.println("子类狗狗带4个参数的构造方法");
}
//添加属性的setter/getter方法,并加入属性控制语句
public void setStrain(String strain){
this.strain = strain;
}
public String getStrain(){
return this.strain;
}
//重写print()方法
public void print() {
//调用父类的非private的print()
super.print();
System.out.println("我是一只:"+this.strain);
}
public void toHospital() {
System.out.println("打针、吃药");
this.setHealth(60);
}
}
Penguin.java
import java.awt.*;
/*
* 宠物企鹅类
*/
public class Penguin extends Pet{
private String sex = "Q仔";
public Penguin(){};
public Penguin(String name, int health, int love, String sex){
super(name, health, love);
this.sex = sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getSex() {
return this.sex;
}
//重写print()方法
public void print() {
//调用父类的非private的print()
super.print();
System.out.println("我的性别是:"+this.sex);
}
//为企鹅看病
public void toHospital() {
System.out.println("打针、疗养");
this.setHealth(60);
}
}
Master.java
//主人类
public class Master {
//为宠物看病,如果宠物健康值小于50,就要去宠物医院看病
public void cure(Pet pet){
if (pet.getHealth()<50){
pet.toHospital();
pet.setHealth(60);
}
}
}
TestPet.java
import java.util.Scanner;
public class TestPet {
public static void main(String[] args) {
Master master = new Master();
Scanner input = new Scanner(System.in);
System.out.println("欢迎您来到宠物店!");
System.out.print("请输入要领养宠物的名字:");
String name = input.next();
System.out.print("请输入要领养宠物的类型:1、狗狗;2、企鹅 ");
int typeNo = input.nextInt();
switch (typeNo){
case 1:
//父类类型指向子类对象
Pet dog = new Dog("多多", 30, 89, "吉娃娃");
dog.print();
System.out.println("*************************");
//主人为狗狗看病
master.cure(dog);
System.out.println("*************************");
dog.print();
break;
case 2:
//接受用户键盘录入信息
System.out.print("请输入企鹅的性别:1、Q妹;2、Q仔 ");
int SexId = input.nextInt();
String sex = (SexId==1) ? "Q妹" : "Q仔";
System.out.print("请输入企鹅的健康值:");
int health = input.nextInt();
System.out.print("请输入企鹅的亲密度:");
int love = input.nextInt();
//创建企鹅对象
Pet p = new Penguin(name, health, love, sex);
p.print();
System.out.println("*************************");
//主人为企鹅看病
master.cure(p);
System.out.println("*************************");
p.print();
break;
default:
System.out.println("暂时没有这个类型的宠物!");
break;
}
}
}
4.2 抽象类和抽象方法
抽象方法
抽象类
抽象方法所在的类必须定义为抽象类
抽象类中不一定要有抽象方法
一个抽象类的抽象方法必须被子类实现,除非其子类也是抽象类
//父类:提取共性的代码
//抽象类不能被实例化,实例化抽象类没有任何实际意义
public abstract class Pet {
private String name = "无名氏"; //昵称
private int health = 100; //健康值,默认100,0~100之间,小于60为不健康
private int love = 0; //亲密度
private String strain = "聪明的拉布拉多犬"; //品种
// int age = 1;
public Pet(){
System.out.println("父类无参构造方法");
}
public Pet(String name){
this.name = name;
System.out.println("父类带参构造方法");
}
public Pet(String name, int health, int love){
//this(name); //this可调用本类的构造方法,且必须放在第一行
this.name = name;
this.health = health;
this.love = love;
System.out.println("父类带参构造方法");
}
public void setHealth(int health){
if(health<0 || health>100){
System.out.println("宠物的健康值只能在0~100之间!");
this.health = 60;
return;
}
this.health = health;
}
public int getHealth(){
return this.health;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setLove(int love){
if(love<0 || love>100){
System.out.println("宠物的亲密度只能在0~100之间!");
this.love = 60;
return;
}
this.love = love;
}
public int getLove(){
return this.love;
}
/*
* 输出宠物信息
*/
public void print(){
System.out.println("宠物的自白:\n我的名字叫" + this.name +
",健康值是" + this.health + ",和主人的亲密度是"
+ this.love);
}
//宠物生病后看病
//抽象方法所在的类必须定义为抽象类
//抽象类中不一定要有抽象方法
//一个抽象类的抽象方法必须被(普通)子类实现
//除非其子类也是抽象类
public abstract void toHospital();
}
4.3 向上转型与向下转型
向上转型 类似自动类型转换
向下转型 类似强制类型转换
向下转型,如果没有没有转换为真实的子类类型,会引发ClassCastException,所以需要使用
instanceof
进行类型判断TestPet.java
import java.util.Scanner;
public class TestPet {
public static void main(String[] args) {
Master master = new Master();
Scanner input = new Scanner(System.in);
System.out.println("欢迎您来到宠物店!");
System.out.print("请输入要领养宠物的名字:");
String name = input.next();
System.out.print("请输入要领养宠物的类型:1、狗狗;2、企鹅 ");
int typeNo = input.nextInt();
switch (typeNo){
case 1:
//创建狗狗对象
//父类类型指向子类对象,向上转型
Pet dog = new Dog("多多", 30, 89, "吉娃娃");
//使用向上转型无法调用子类独有的方法
//可使用向下转型
//向下转型,如果没有没有转换为真实的子类类型,会引发ClassCastException
//所以需要使用`instanceof`进行类型判断
if (dog instanceof Dog) {
Dog d = (Dog)dog;
d.catchFly();
}else if (dog instanceof Penguin) {
Penguin p= (Penguin)dog;
p.swim();
}
dog.print();
// dog.m2();
System.out.println("*************************");
//主人为狗狗看病
master.cure(dog);
//主人为狗狗喂食
master.feed(dog);
System.out.println("*************************");
dog.print();
break;
case 2:
//接受用户键盘录入信息
System.out.print("请输入企鹅的性别:1、Q妹;2、Q仔 ");
int SexId = input.nextInt();
String sex = (SexId==1) ? "Q妹" : "Q仔";
System.out.print("请输入企鹅的健康值:");
int health = input.nextInt();
System.out.print("请输入企鹅的亲密度:");
int love = input.nextInt();
//创建企鹅对象
Pet p = new Penguin(name, health, love, sex);
if (p instanceof Dog) {
Dog d = (Dog)p;
d.catchFly();
}else if (p instanceof Penguin) {
Penguin penguin= (Penguin)p;
penguin.swim();
}
Penguin penguin = (Penguin)p;
penguin.swim();
p.print();
System.out.println("*************************");
//主人为企鹅看病
master.cure(p);
//主人为企鹅喂食
master.feed(p);
System.out.println("*************************");
p.print();
break;
default:
System.out.println("暂时没有这个类型的宠物!");
break;
}
}
}
4.4 多态的两种使用方式
- 使用父类作为方法的形参,是Java中实现和使用多态的主要方式
- 使用父类作为方法的返回值,也是Java实现和使用多态的主要方式
案例1:
Animal.java
//动物类
public abstract class Animal {
//动物叫
public abstract void shout();
}
Cat.java
public class Cat extends Animal{
public void shout() {
System.out.println("喵喵喵");
}
}
Dog.java
public class Dog extends Animal{
public void shout() {
System.out.println("汪汪汪");
}
}
Duck.java
public class Duck extends Animal{
public void shout() {
System.out.println("嘎嘎嘎");
}
}
Master.java
import jdk.internal.org.objectweb.asm.tree.analysis.Analyzer;
//农场主人
public class Master {
//赠送动物
//将父类类型作为返回值
// public Cat sendCat() {
// return new Cat();
// }
//
// public Dog sendDog () {
// return new Dog();
// }
//
// public Duck sendDuck () {
// return new Duck();
// }
public Animal sendAnimal(int type) {
Animal animal = null;
switch (type) {
case 1:
animal = new Cat();
break;
case 2:
animal = new Dog();
break;
case 3:
animal = new Duck();
break;
default:
System.out.println("对不起朋友,农场暂时没有这种动物!");
break;
}
return animal;
}
}
Test.java
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Master master = new Master();
System.out.print("朋友,你喜欢什么动物:1.猫 2.狗 3.鸭子:");
int type = input.nextInt();
Animal animal = master.sendAnimal(type);
//如果是4会出现空指针异常,需要用循环升级解决
//多态:根据具体动物子类,调用其重写后的shout()方法
animal.shout();
}
}
案例2:
Goods.java
public abstract class Goods {
//打印输出商品价格
public abstract void printPrice();
}
Foods.java
//食品类
public class Foods extends Goods{
public void printPrice() {
System.out.println("打印输出食品价格");
}
}
TVs.java
//电视类
public class TVs extends Goods{
public void printPrice() {
System.out.println("打印输出电视价格");
}
}
Factory.java
//商品工厂,根据厂家需求生产不同的商品
public class Factory {
//生产商品:使用父类作为方法返回值类型
public Goods getGoods(String str) {
if (str.equals("food")) {
return new Foods();
}else{
return new TVs();
}
}
}
Test.java
public class Test {
public static void main(String[] args) {
Factory factory = new Factory();
Goods goods = factory.getGoods("food");
goods.printPrice();
goods = factory.getGoods("TVs");
goods.printPrice();
}
}
4.5 动态绑定机制与静态绑定机制
实例方法(动态绑定机制)与引用变量实际引用的对象绑定,调用子类重写后的方法,有运行时JVM决定
静态方法(静态绑定机制)与引用变量所声明的类型绑定,实际上在编译阶段就做了绑定
成员变量(包括静态变量和实例变量,静态绑定机制)与引用变量所声明的类型绑定,实际上在编译阶段就做了绑定
普通的,非多态相关的:通过类名可以调用各自类的静态方法
Father.java
public class Father {
int var1 = 10;
static int staticVar = 9;
public void m1() {
System.out.println("父类中的实例方法m1");
}
public static void staticM1() {
System.out.println("父类中的静态方法m1");
}
}
Son.java
public class Son extends Father {
int var1 = 100;
static int staticVar = 90;
public void m1() {
System.out.println("子类重写后的m1方法");
}
//非重写,只是定义了一个与父类同名的静态方法
public static void staticM1() {
System.out.println("子类类中的静态方法m1");
}
public static void main(String[] args) {
//多态的绑定机制
//向上转型,父类引用指向子类对象
Father f = new Son();
//实例方法(动态绑定机制)与引用变量实际引用的对象绑定,调用子类重写后的方法,有运行时JVM决定
f.m1();
//静态方法(静态绑定机制)与引用变量所声明的类型绑定,实际上在编译阶段就做了绑定
f.staticM1();
//普通的,非多态相关的:通过类名可以调用各自类的静态方法
Father.staticM1();
Son.staticM1();
//成员变量(包括静态变量和实例变量,静态绑定机制)与引用变量所声明的类型绑定,实际上在编译阶段就做了绑定
System.out.println(f.var1);
System.out.println(f.staticVar);
}
}
4.6 简单工厂模式
设计模式(23种):
代表了最佳的实践,是软件开发人员在软件开发过程中面临的一般问题的解决方案
分为:
- 创建型:在创建对象的时候隐藏创建逻辑的方式
- 工厂模式
- 简单工厂模式(特例)
- 工厂方法模式
- 抽象工厂模式
- ...
- 单例模式
- ...
- 工厂模式
- 结构型
- 行为型
简单工厂模式一般涉及的类:
- 工厂类
- 客户端类
- 商品类
- 具体商品子类
- 涉及到接口的相关内容
缺点可以用工厂方法模式解决(涉及接口)
Factory.java
//商品工厂,根据厂家需求生产不同的商品
//简单工厂模式:可以加相应的业务代码(日志、判断)
//经常应用简单工厂模式时,生成实例的方法是静态方法
//简单工厂模式:工厂类
//涉及到接口的相关内容:工厂类 商品类(接口或抽象类)具体商品子类 客户端
public class Factory {
//生产商品:使用父类作为方法返回值类型
//简单工厂模式一般声明为静态方法
public static Goods getGoods(String str) {
if (str.equals("food")) {
return new Foods();
}else{
return new TVs();
}
}
}
Test.java
//客户端,测试类
public class Test {
public static void main(String[] args) {
//简单工厂模式一般声明为静态方法,测试类里面不用再声明生成Factory类对象,可以通过类名直接调用Factory的静态方法
//Factory factory = new Factory();
Goods goods = Factory.getGoods("food");
goods.printPrice();
goods = Factory.getGoods("TVs");
goods.printPrice();
}
}
网友评论