
父类中定义的方法,无法输出子类中特有的属性
方法的重写或方法的覆盖
1)子类根据需求对从父类继承的方法
2)重写时,可以用super.方法的方式来保留父类的方法
3)构造方法不能被重写
1)方法名相同
2)参数列表相同
3)返回值类型相同或者是其子类
4)访问权限不能严于父类
5)父类的静态方法不能被子类覆盖为非静态方法,父类的非静态方法不能被子类覆盖为静态方法
(保持一致)
6)子类可以定义与父类同名的静态方法,以便在子类中隐藏父类的静态方法
(注:静态方法中无法使用super)
7)父类的私有方法不能被子类覆盖
8)不能抛出比父类方法更多的异常
| 比较项 | 位置 | 方法名 | 参数表 | 返回值 | 访问修饰符 |
|---|---|---|---|---|---|
| 方法重载 | 同类 | 相同 | 不相同 | 无关 | 无关 |
| 方法重写 | 子类 | 相同 | 相同 | 相同或是其子类 | 不能比父类严格 |
package com.learn.demo06;
public class Pet{
// 定义Dog类、Penguin类、Cat类、...等类中相同的代码
private String name;
private int health;
private int love;public Pet() {
}public Pet(String name, int health, int love) {
this.name = name;
this.health = health;
this.love = love;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public int getHealth() {
return health;
}public void setHealth(int health) {
this.health = health;
}public int getLove() {
return love;
}public void setLove(int love) {
this.love = love;
}// 定义一个方法输出对象的name、health、love属性值
public void printInfo(){
System.out.println("昵称:"+this.getName()+",健康值:"+this.getHealth()+",亲密度:"+this.getLove());
}
}
package com.learn.demo06;
public class Dog extends Pet {
// 这里只需要定义Dog类中特有的属性
private String strain; // 品种public Dog() {
}public Dog(String name, int health, int love, String strain) {
super(name, health, love); // super关键字
this.strain = strain;
}public String getStrain() {
return strain;
}public void setStrain(String strain) {
this.strain = strain;
}// 重新定义输出dog类对象信息的方法
public void printInfo(){
//对于name、health、love属性值,父类Pet中已经做出了输出操作,所有可以调用父类Pet中的printInfo()方法
super.printInfo();
// 加一个输出Dog类中特有属性
System.out.println("品种:"+this.getStrain());
}
}
package com.learn.demo06;
public class Test {
public static void main(String[] args) {
// 使用有参构造方法创建Dog类对象
Dog dog1 = new Dog("来福",100,100,"哈士奇");
// 调用Pet类中的printInfo()方法输出dog1对象的信息
// 父类Pet中的printInfo()方法只能输出dog1对象的name、health、love的属性值
// 不能够输出dog1对象的strain信息,也就说明Pet类中的printInfo()方法不足以满足子类使用,这时候可以在子类中重新定义输出方法
dog1.printInfo();
}
}
public class Test { // 自行测试
public static void main(String[] args) {// 使用无参构造方法
/*Penguin penguin1 = new Penguin();
penguin1.setName("QQ");
penguin1.setHealth(66);
penguin1.setLove(52);
penguin1.setSex("公");
penguin1.printInfo();*/
// 输出结果 昵称:QQ,健康值:66,亲密度:52
// 输出结果无法显示出子类中的特有属性sexSystem.out.println("*在Dog子类中进行方法重写后*");
// 使用有参构造方法
Dog dog1 = new Dog("狗儿",77,88,"中华田园犬");
dog1.printInfo();
// 输出结果 昵称:狗儿,健康值:77,亲密度:88
// 品种为:中华田园犬}
}
Object类是所有类的父类
// 使用Cat类的无参构造方法创建对象
Cat cat1 = new Cat();
// 此时调用了几个无参构造方法
// Cat类继承Pet类,Object是Pet类的父类
// 所以调用了三个构造方法Cat()、Pet()、Object()
Object类被子类经常重写的方法
| 方法 | 说明 |
|---|---|
| toString() | 返回当前对象本身的有关信息,按字符串对象返回 |
| equals() | 比较两个对象是否是同一个对象,是则返回true |
| hashCode() | 返回该对象的哈希代码值 |
| getClass() | 获取当前对象所属的类信息,返回Class对象 |
package methodagain.demo02;
public class Student {
private String name;
private int age;public Student() {
}public Student(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;
}
}
package methodagain.demo02;
public class StudentTest {
public static void main(String[] args) {// 创建两个Student对象
Student student1 = new Student("张三",20);
Student student2 = new Student("张三",20);// 直接输出两个对象
System.out.println("student1 = " + student1);
System.out.println("student2 = " + student2);
// 输出结果
// student1 = methodagain.demo02.Student@1b6d3586
// student2 = methodagain.demo02.Student@4554617cSystem.out.println("------ ------ ------ ------ ------ ------");
// 通过Student类对象调用toString()方法输出信息
String result1 = student1.toString(); // Student类中没有,默认继承Object类中的toString()方法
String result2 = student2.toString();
System.out.println("result1 = " + result1);
System.out.println("result2 = " + result2);
// 输出结果
// result1 = methodagain.demo02.Student@1b6d3586
// result2 = methodagain.demo02.Student@4554617cSystem.out.println("------ ------ ------ ------ ------ ------");
// getClass().getName() + '@' + Integer.toHexString(hashCode())
// 自行调用方法实现输出对象的地址值
String result3 = student1.getClass().getName() + '@' + Integer.toHexString(student1.hashCode());
System.out.println("result3 = " + result3);
// 输出结果
// result3 = methodagain.demo02.Student@1b6d3586/*
* 上面代码的操作输出的都是对象在内存中的地址值,输出无意义
* 我们希望直接输出对象名或者通过对象名调用toString()方法,输出的是对象的所有属性值
* 由此说明,父类(Object)中的toString()方法不足以满足子类的使用,所以可以对父类中的toString()方法进行重写
*/}
}
package methodagain.demo03;
public class Student {
private String name;
private int age;public Student() {
}public Student(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 String toString() {
return "qwert";
}*/ // 第一次重写toString()方法public String toString() {
return "姓名:"+this.getName()+"年龄:"+this.getAge();
} // 第二次重写toString()方法
}
package methodagain.demo03;
public class StudentTest {
public static void main(String[] args) {// 创建两个Student对象
Student student1 = new Student("张三",20);
Student student2 = new Student("张三",20);// 直接输出两个对象
System.out.println("student1 = " + student1);
System.out.println("student2 = " + student2);
// 输出结果
// student1 = qwert 第一次重写输出结果
// student2 = qwert
// student1 = 姓名:张三年龄:20 第二次重写输出结果
// student2 = 姓名:张三年龄:20System.out.println("------ ------ ------ ------ ------ ------");
// 通过Student类对象调用toString()方法输出信息
String result1 = student1.toString(); // Student类中没有,默认继承Object类中的toString()方法
String result2 = student2.toString();
System.out.println("result1 = " + result1);
System.out.println("result2 = " + result2);
// 输出结果
// result1 = qwert
// result2 = qwert
// result1 = 姓名:张三年龄:20
// result2 = 姓名:张三年龄:20System.out.println("------ ------ ------ ------ ------ ------");
// getClass().getName() + '@' + Integer.toHexString(hashCode())
// 自行调用方法实现输出对象的地址值
String result3 = student1.getClass().getName() + '@' + Integer.toHexString(student1.hashCode());
System.out.println("result3 = " + result3);
// 输出结果
// result3 = methodagain.demo02.Student@1b6d3586
// 这里严格调用输出地址的方法,所以输出还是地址值
}
}
package methodagain.demo04;
public class Student {
private String name;
private int age;public Student() {
}public Student(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 String toString() {
return "姓名:"+this.getName()+",年龄:"+this.getAge();
}@Override
public boolean equals(Object obj) {
// 如果调用此方法比较的两个对象是同一个对象,地址值肯定相同
if (this == obj) {
return true;
}
// 如果比较的地址值不相同,说明这是两个不同的对象
// 首先将传递过来的student判断一下是否是Student类型的对象
if (obj instanceof Student) {
Student student = (Student)obj;
// 比较当前对象和传递过来对象的属性值
if (this.getName().equals(student.getName()) &&
this.getAge() == student.getAge()) {
return true;
}}
return false;
}
}
package methodagain.demo04;
public class StudentTest {
public static void main(String[] args) {// 创建两个Student对象
Student student1 = new Student("张三",24);
Student student2 = new Student("张三",24);// 直接输出两个对象
System.out.println("student1 = " + student1); // student1 = 姓名:张三年龄:24
System.out.println("student2 = " + student2); // student2 = 姓名:张三年龄:24
// 输出两个对象在内存中的地址
System.out.println(
"student1的地址值:"+student1.getClass().getName() + '@' + Integer.toHexString(student1.hashCode()));
System.out.println(
"student1的地址值:"+student2.getClass().getName() + '@' + Integer.toHexString(student2.hashCode()));
// 输出结果
// student1的地址值:methodagain.demo04.Student@1b6d3586
// student1的地址值:methodagain.demo04.Student@4554617c// 比较两个对象
/*
* 关系运算符(比较运算符):
* > >= < <=只能比较数值类型的数据
* == != 既可以比较数值类型的数据,还可以比较引用数据类型的数据,比较引用数据类型比较的地址值
* */
boolean result1 = student1 == student2;
System.out.println("student1对象和student2对象相等:"+result1); // false
boolean result2 = student1 != student2;
System.out.println("student1对象和student2对象不相等:"+result2); // true// 通过Object类中给的equals()方法比较两个对象
boolean result3 = student1.equals(student2);
System.out.println("student1对象和student2对象相等:"+result3); // false
/*
* student1对象调用的equals()方法在Student类中是不存在,但是可以调用
* 因为Student类默认继承父类Object类中存在,所以Student类可以调用
*
* 这是Object类中equals()方法代码
* public boolean equals(Object obj) {
return (this == obj);
}
* 可见返回值底层逻辑还是 == ,比较的还是地址值
* 因此equals()方法比较的也是两个对象的地址值
* *//*
* 面试题:
* == 和 equals() 的区别:
* == 既可以比较基本数据类型,也可以比较引用数据类型
* 比较基本数据类型比较的是数值,比较引用数据类型比较的是地址值
* equals() 方法是Object类中的方法,比较的是两个对象的地址值
* 因为底层逻辑是 ==
* *//*
* 那么,
* 比较两个对象时,不再比较地址,比较属性值
* 如果两个对象的name和age属性值相同,则认为他们是同一个对象
* 所以,
* Student类的父类Object类中的equals()方法满足不了Student类的需求,
* 因此需要在Student类中进行重写
* */// 重写equals()方法之后
boolean result4 = student1.equals(student2);
System.out.println("student1对象和student2对象相等:"+result4); // true
}
}
package methodagain.demo05;
public class StringDemo01 {
public static void main(String[] args) {
String string1 = "qwert";
String string2 = "yuiop";// 比较两个字符串的内容
System.out.println("两个字符串内容相同:"+string1.equals(string2));
// 输出结果 falseString string3 = "qwert";
String string4 = "qwert";// 比较两个字符串的内容
System.out.println("两个字符串内容相同:"+string3.equals(string4));
// 输出结果 true// Ctrl点击equals()方法
// String类重写了Object类中的方法,比较两个字符串之间的内容
/*
* 说明:
* 比较两个字符串的内容
* String类也是Object的子类
* Object类中的equals()方法比较的是两个对象的地址值,不能满足String类中要求比较两个对象的内容需求
* 所以在String类中重写equals()方法
* String类中的equals()方法比较的是两个字符串的内容
* */
}
}
package polymorphic.demo01;
// 定义父类Pet类,默认继承Object类
public class Pet {// 定义子类中共有的属性和方法
private String name;
private int health;
private int love;public Pet() {
}public Pet(String name, int health, int love) {
this.name = name;
this.health = health;
this.love = love;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public int getHealth() {
return health;
}public void setHealth(int health) {
if (health > 0) {
this.health = health;
} else {
this.health = 60;
}
}public int getLove() {
return love;
}public void setLove(int love) {
this.love = love;
}// 重写toString()方法
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
", health=" + health +
", love=" + love +
'}';
}// 定义一个方法输出宠物的name health love属性值
// this.getName() 与 this.name 效果一样
// 因为private修饰属性在本类中可以调用
public void printInfo() {
System.out.println("昵称:"+this.getName()+
",健康值:"+this.getHealth()+
",亲密度:"+this.getLove());
}
}
package polymorphic.demo01;
public class Dog extends Pet {
// 定义Dog类中特有的属性
private String strain;public Dog() {
// 默认调用父类Pet类中的无参构造方法
}public Dog(String name, int health, int love, String strain) {
super(name, health, love);
this.strain = strain;
}public String getStrain() {
return strain;
}public void setStrain(String strain) {
this.strain = strain;
}@Override
public String toString() {
return "Dog{" +
"strain='" + strain + '\'' +
'}';
}// 重写Pet类中的printInfo()方法
public void printInfo() {
// 调用父类的printInfo
super.printInfo();
// 添加输出Dog类中的strain属性值
System.out.println("品种:"+this.getStrain());
}public void eat() {
System.out.println("狗狗吃狗粮");
}
}
package polymorphic.demo01;
public class Penguin extends Pet {
private String sex;
public Penguin() {
}public Penguin(String name, int health, int love, String sex) {
super(name, health, love);
this.sex = sex;
}public String getSex() {
return sex;
}public void setSex(String sex) {
this.sex = sex;
}@Override
public String toString() {
return "Penguin{" +
"sex='" + sex + '\'' +
'}';
}// 重写Pet父类中的printInfo()方法
public void printInfo() {
super.printInfo();
// 添加输出Penguin类中sex属性的语句
System.out.println("性别:"+this.getSex());
}// 定义一个方法
public void swimming() {
System.out.println("企鹅会游泳");
}}
package polymorphic.demo01;
public class Test01 {
public static void main(String[] args) {
// 使用Dog类的有参构造方法创建对象
Dog dog1 = new Dog("壮实",100,100,"萨摩耶");
// dog1对象调用printInfo()方法,调用的是Dog类中重写的printInfo()方法
// 对象调用方法先从自己的类查找,没有再查找父类
dog1.printInfo();
// 输出结果
// 昵称:壮实,健康值:100,亲密度:100
// 品种:萨摩耶
dog1.eat(); // 输出结果 狗狗吃狗粮System.out.println("------ ------ ------");
/*// 使用Penguin类的有参构造方法创建对象
// 测试一下 传参
Penguin penguin1 = new Penguin("Q1",-60,100,"公");
penguin1.printInfo();
// 输出结果
// 昵称:Q1,健康值:-60,亲密度:100
// 性别:公
Penguin penguin2 = new Penguin();
penguin2.setName("Q2");
penguin2.setHealth(-60);
penguin2.setLove(100);
penguin2.setSex("母");
penguin2.printInfo();
// 输出结果
// 昵称:Q2,健康值:60,亲密度:100
// 性别:母
// 这里通过get/set方法对属性合理进行判断
// 而通过创建对象时,利用有参构造方法传参则无法对属性值进行合理判断*/// 使用Penguin类的有参构造方法创建对象
Penguin penguin1 = new Penguin("QQ",100,100,"公");
// penguin1对象调用printInfo()方法,调用Penguin类中重写后的printInfo()方法
penguin1.printInfo();
// 调用Penguin类中的swimming()方法
penguin1.swimming();
// 输出结果
// 昵称:QQ,健康值:100,亲密度:100
// 性别:公
// 企鹅会游泳}
}
<父类型> <引用变量名> = new <子类型>();
注意:
1)此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法,不是父类的方法
2)此时通过父类引用变量无法调用子类特有的方法
package polymorphic.demo01;
public class Test02 {
public static void main(String[] args) {// 创建Dog对象
// 父类的引用(对象名/变量名)指向子类的实例(对象)
// 即:向上转型
Pet pet = new Dog("一千",100,100,"萨摩耶");
// 写的时候是从左向右写,看的时候是从右向左看// 使用pet对象调用printInfo()方法,调用的是Dog类重写后的printInfo()方法,也能输出品种
pet.printInfo();
// 输出结果
// 昵称:一千,健康值:100,亲密度:100
// 品种:萨摩耶System.out.println("------ ------ ------");
// 将pet引用指向Penguin类对象
pet = new Penguin("帝王",100,100,"母");
// 使用pet对象调用printInfo()方法,调用的是Penguin类重写后的printInfo()方法,也能输出性别
pet.printInfo();
// 输出结果
// 昵称:帝王,健康值:100,亲密度:100
// 性别:母// 方法重写是实现多态的前提
}
}
同一个父类引用,指向的不同的子类实例,执行操作不一样
操作不一样,体现在子类重写的方法中,所以说方法重写是实现多态的前提
<子类型> <引用变量名> = (<子类型>) <父类型的引用变量>;
注意:
1)在向下转型的过程中,如果没有转换为真实子类类型,会出现类型转换异常
思考:那么父类的引用能不能调用子类编写特有的方法
package polymorphic.demo01;
public class Test03 {
public static void main(String[] args) {Pet pet = new Dog("一千",100,100,"萨摩耶");
pet.printInfo();
// 输出结果
// 昵称:一千,健康值:100,亲密度:100
// 品种:萨摩耶// 使用pet对象调用Dog类中特有的方法eat()
// 父类的引用无法直接调用子类中特有的方法
// pet.eat(); 报错// 如果要调用,需要向下转型(理解为基本数据类型中的强制类型转换)
// 向下转型
// 子类的引用指向父类的引用
Dog dog = (Dog)pet;
dog.eat();
// 输出结果 狗狗吃狗粮System.out.println("------ ------ ------");
pet = new Penguin("帝王",100,100,"母");
// ------ ------ ------ ------ ------ ------
pet.printInfo();
// 输出结果
// 昵称:帝王,健康值:100,亲密度:100
// 性别:母
Penguin penguin1 = (Penguin)pet;
penguin1.swimming();
// 输出结果 企鹅会游泳
// ------ ------ ------ ------ ------ ------// 如果在pet指向Penguin对象后进行如下操作:
// Dog dog2 = (Dog)pet;
// dog2.eat();
/*
* 报错:ClassCastException 类型转换异常
* */
// 因为pet指向的是Penguin类对象,在向下转型中应该将其转换为Penguin对象,不能将其转换为其它子类对象// 为了避免在向下转型中过程中,出现类型转换异常
// 可以使用instanceof运算符进行类型判断,instanceof运算符的结果是布尔值
if (pet instanceof Dog) {
Dog dog2 = (Dog)pet;
dog2.eat();
} else if(pet instanceof Penguin) {
Penguin penguin2 = (Penguin)pet;
penguin2.swimming(); // 输出结果 企鹅会游泳
}}
}
package methodagain02.demo01;
public class Pet {
private String name;
private int health;
private int love;public Pet() {
// super()
}public Pet(String name, int health, int love) {
// super()
this.name = name;
this.health = health;
this.love = love;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public int getHealth() {
return health;
}public void setHealth(int health) {
this.health = health;
}public int getLove() {
return love;
}public void setLove(int love) {
this.love = love;
}// 建议所有类重写toString()方法
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
", health=" + health +
", love=" + love +
'}';
}public void printInfo() {
System.out.println("昵称:"+this.getName()+
",健康值:"+this.getHealth()+
",亲密度:"+this.getLove());
} //在子类重写// Pet类中定义一个普通方法
public void petMethod() {
System.out.println("在子类中不进行重写");
}
}
package methodagain02.demo01;
public class Dog extends Pet {
// 定义Dog类继承Pet类
private String strain;public Dog() {
}public Dog(String strain) {
this.strain = strain;
}public Dog(String name, int health, int love, String strain) {
super(name, health, love);
this.strain = strain;
}public String getStrain() {
return strain;
}public void setStrain(String strain) {
this.strain = strain;
}@Override
public String toString() {
return "Dog{" +
"strain='" + strain + '\'' +
'}';
}// 重写Pet类中printInfo()方法
public void printInfo() {
super.printInfo();
System.out.println("品种:" + this.getStrain());
}// 在Dog类中定义特有方法
public void eat() {
System.out.println("狗狗吃狗粮");
}
}
package methodagain02.demo01;
public class Penguin extends Pet{
private String sex;
public Penguin() {
}public Penguin(String name, int health, int love, String sex) {
super(name, health, love);
this.sex = sex;
}public String getSex() {
return sex;
}public void setSex(String sex) {
this.sex = sex;
}// toString方法重写就是输出对象信息
@Override
public String toString() {
return "Penguin{" +
"sex='" + sex + '\'' +
'}';
}public void printInfo() {
super.printInfo();
System.out.println("性别:"+ this.getSex());
}public void swimming() {
System.out.println("企鹅会游泳");
}}
package methodagain02.demo01;
public class Master {
// 在该类中定义给各种宠物看病的方法
// 定义一个给Dog类看病的方法
public void cure(Dog dog) {
// 狗的健康值小于60
if (dog.getHealth() < 60) {
System.out.println("狗看病打针,健康值恢复到80");
dog.setHealth(80);
return;
}
}// 定义一个给Penguin类看病的方法
public void cure (Penguin penguin) {
if (penguin.getHealth() < 60) {
System.out.println("企鹅生病治疗,健康值恢复到70");
penguin.setHealth(70);
}
}// 需要定义一个给Cat类对象看病的方法
public void cure (Cat cat) {
if (cat.getHealth() < 60) {
System.out.println("猫咪生病挂水,健康值恢复到90");
cat.setHealth(90);
}
}}
package methodagain02.demo01;
public class Cat extends Pet {
private String color;
public Cat() {
}public Cat(String name, int health, int love, String color) {
super(name, health, love);
this.color = color;
}public String getColor() {
return color;
}public void setColor(String color) {
this.color = color;
}@Override
public String toString() {
return "Cat{" +
"color='" + color + '\'' +
'}';
}public void printInfo() {
super.printInfo();
System.out.println("颜色:"+this.getColor());
}// 定义一个Cat类特有的方法
public void play() {
System.out.println("猫咪喜欢躲迷藏");
}
}
package methodagain02.demo01;
public class Test {
public static void main(String[] args) {
// 创建Dog对象
Dog dog1 = new Dog("旺财",55,100,"金毛");
dog1.printInfo();
// 昵称:旺财,健康值:55,亲密度:100
// 品种:金毛// 创建Master对象
Master master = new Master();
// 带Dog对象看病
master.cure(dog1); // 狗看病打针,健康值恢复到80
dog1.printInfo();
// 昵称:旺财,健康值:80,亲密度:100
// 品种:金毛System.out.println("------ ------ ------");
// 创建Penguin对象
Penguin penguin1 = new Penguin("企鹅",45,100,"公");
penguin1.printInfo();
// 昵称:企鹅,健康值:45,亲密度:100
// 性别:公
master.cure(penguin1);
penguin1.printInfo();
// 企鹅生病治疗,健康值恢复到70
// 昵称:企鹅,健康值:70,亲密度:100
// 性别:公// ------ ------ ------ ------ ------ ------
// 然后又养了一只猫咪,需要定义一个Cat类
Cat cat1 = new Cat("Tom",30,100,"浅蓝色");
cat1.printInfo();
// 昵称:Tom,健康值:30,亲密度:100
// 颜色:浅蓝色// 这时想要给cat1去看病,还需要在Master类中重新定义一个方法
// 在Master类中定义方法之后才能调用
master.cure(cat1);
cat1.printInfo();
// 猫咪生病挂水,健康值恢复到90
// 昵称:Tom,健康值:90,亲密度:100
// 颜色:浅蓝色/*
* 问题:
* 后续如果创建其它类,像老虎、狮子、大象等
* 还需要看病的话,还得在Master类中重新定义方法,过于繁琐
* */
}
}
利用多态重写之后
package methodagain02.demo02;
public class Pet {
private String name;
private int health;
private int love;//
public Pet() {
// super()
}public Pet(String name, int health, int love) {
// super()
this.name = name;
this.health = health;
this.love = love;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public int getHealth() {
return health;
}public void setHealth(int health) {
this.health = health;
}public int getLove() {
return love;
}public void setLove(int love) {
this.love = love;
}// 建议所有类重写toString()方法
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
", health=" + health +
", love=" + love +
'}';
}public void printInfo() {
System.out.println("昵称:"+this.getName()+
",健康值:"+this.getHealth()+
",亲密度:"+this.getLove());
} //在子类重写// Pet类中定义一个普通方法
public void petMethod() {
System.out.println("在子类中不进行重写");
}// 定义一个带宠物看病的方法
public void toHospital() {
System.out.println("宠物生病,需要看病");
}
}
package methodagain02.demo02;
public class Dog extends Pet {
// 定义Dog类继承Pet类
private String strain;public Dog() {
}public Dog(String strain) {
this.strain = strain;
}public Dog(String name, int health, int love, String strain) {
super(name, health, love);
this.strain = strain;
}public String getStrain() {
return strain;
}public void setStrain(String strain) {
this.strain = strain;
}@Override
public String toString() {
return "Dog{" +
"strain='" + strain + '\'' +
'}';
}// 重写Pet类中printInfo()方法
public void printInfo() {
super.printInfo();
System.out.println("品种:" + this.getStrain());
}// 在Dog类中定义特有方法
public void eat() {
System.out.println("狗狗吃狗粮");
}// 父类Pet中toHospital()方法满足不了Dog类看病的需求
// 所以进行重写
public void toHospital() {
if (this.getHealth() < 60) {
System.out.println("狗看病打针,健康值恢复到80");
this.setHealth(80);
}
}
}
package methodagain02.demo02;
public class Penguin extends Pet {
private String sex;
public Penguin() {
}public Penguin(String name, int health, int love, String sex) {
super(name, health, love);
this.sex = sex;
}public String getSex() {
return sex;
}public void setSex(String sex) {
this.sex = sex;
}// toString方法重写就是输出对象信息
@Override
public String toString() {
return "Penguin{" +
"sex='" + sex + '\'' +
'}';
}public void printInfo() {
super.printInfo();
System.out.println("性别:"+ this.getSex());
}public void swimming() {
System.out.println("企鹅会游泳");
}
public void toHospital() {
if (this.getHealth() < 60) {
System.out.println("企鹅生病治疗,健康值恢复到70");
this.setHealth(70);
}
}}
package methodagain02.demo02;
public class Master {
// 定义一个给宠物Pet看病的方法
public void cure(Pet pet) {
// 当宠物pet的健康值小于60的时候,需要看病
if (pet.getHealth() < 60) {
// 在这里,从代码上看,调用的是Pet类中的toHospital()方法
// 实际上调用的是pet引用指向的子类中重写的toHospital()方法
pet.toHospital();
}
}}
package methodagain02.demo02;
public class Test {
public static void main(String[] args) {/*// 创建Dog类对象,自己给自己看病,笑死了
Dog dog1 = new Dog("神医",55,100,"边牧");
dog1.printInfo();
// 昵称:神医,健康值:55,亲密度:100
// 品种:边牧
System.out.println("------");
dog1.toHospital();
// 狗看病打针,健康值恢复到80
System.out.println("------");
dog1.printInfo();
// 昵称:神医,健康值:80,亲密度:100
// 品种:边牧// 在父类Pet定义的toHospital()方法,在子类中重写,子类可以调用,但是不符合现实逻辑
// 需要创建一个主人对象,带宠物看病,哈哈哈*/// ------ ------ ------ ------ ------ ------
// 创建Master对象
Master master = new Master();
// 创建Dog对象
Dog dog1 = new Dog("来福",45,100,"金毛");
dog1.printInfo();
// 带宠物看病
master.cure(dog1); // 这里传Pet类对象,Pet子类的对象是可以的
dog1.printInfo();System.out.println("------ ------ ------ ------ ------ ------");
// 向上转型:父类引用(对象名)指向子类的实例(对象)
Pet pet = new Dog("旺财",50,100,"金毛");
// 这里从代码来看,调用的是Pet类中的printInfo()方法
// 实际上调用的是pet引用指向子类Dog类中重写后的printInfo()方法
pet.printInfo();
System.out.println("------");
master.cure(pet); // 狗看病打针,健康值恢复到80
System.out.println("------");
pet.printInfo();
// 昵称:旺财,健康值:80,亲密度:100
// 品种:金毛pet = new Penguin("QQ",30,100,"公");
pet.printInfo();
System.out.println("------");
master.cure(pet); // 企鹅生病治疗,健康值恢复到70
System.out.println("------");
pet.printInfo();
// 昵称:QQ,健康值:70,亲密度:100
// 性别:公}
}
使用abstract修饰的方法为抽象方法
1)抽象方法没有方法体
2)抽象方法所在的类要定义为抽象类
3)抽象方法必须在子类中重写,如果子类不重写父类中的抽象方法,那么子类也要定义为抽象类
(一般都会在子类中重写)
使用abstract修饰的类为抽象类
1)抽象类不能直接实例化(不能直接通过new的形式来创建抽象类的引用(对象))
因为实例化抽象类没有意义,所以我们一般将父类定义为抽象类
2)抽象类中可以没有抽象方法,也可以定义抽象方法,可以有普通方法
3)如果抽象类中定义可多个抽象方法,那么子类中必须重写这个抽象类中所有的抽象方法,否则子类也要定义为抽象类
package methodagain02.demo03;
//public class Pet {
public abstract class Pet { // 改成抽象类
private String name;
private int health;
private int love;//
public Pet() {
// super()
}public Pet(String name, int health, int love) {
// super()
this.name = name;
this.health = health;
this.love = love;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public int getHealth() {
return health;
}public void setHealth(int health) {
this.health = health;
}public int getLove() {
return love;
}public void setLove(int love) {
this.love = love;
}// 建议所有类重写toString()方法
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
", health=" + health +
", love=" + love +
'}';
}public void printInfo() {
System.out.println("昵称:"+this.getName()+
",健康值:"+this.getHealth()+
",亲密度:"+this.getLove());
} //在子类重写// Pet类中定义一个普通方法
public void petMethod() {
System.out.println("在子类中不进行重写");
}// 定义一个带宠物看病的方法
/*public void toHospital() {
// System.out.println("宠物生病,需要看病");
// 不用方法体
}*/
// 如上不用方法体,则可以直接写成
// public void toHospital(); 报错
// 再改
// 需要写成抽象方法加一个abstract
// public abstract void toHospital(); 报错
// 抽象方法需要写在抽象类中
// 所以Pet类需要改成 public abstract class Pet// 再试一下
public abstract void toHospital();}
// 在Dog类中定义特有方法
public void eat() {
System.out.println("狗狗吃狗粮");
}// 父类Pet中toHospital()方法满足不了Dog类看病的需求
// 所以进行重写
public void toHospital() {
if (this.getHealth() < 60) {
System.out.println("狗看病打针,健康值恢复到80");
this.setHealth(80);
}
}
public void toHospital() {
if (this.getHealth() < 60) {
System.out.println("猫看病打针,健康值恢复到60");
this.setHealth(60);
}
}
public class Master {
// 定义一个给宠物Pet看病的方法
public void cure(Pet pet) {
// 当宠物pet的健康值小于60的时候,需要看病
if (pet.getHealth() < 60) {
// 在这里,从代码上看,调用的是Pet类中的toHospital()方法
// 实际上调用的是pet引用指向的子类中重写的toHospital()方法
pet.toHospital();
// 在多态中因为pet引用指向的是子类中重写的toHospital()方法
// 所以父类中的toHospital()方法体内可以不写任何内容
}
}}
package methodagain02.demo04;
public abstract class Automobile {
/*
* 汽车租赁公司可以租赁轿车和客车,轿车和客车具有相同属性和方法,可以将相同的属性和方法抽取出来放在父类Autonobile类中
* 轿车
* 属性:品牌、车牌号、每日租金、型号
* 方法:根据天数计算租金 (租金折扣)
* 客车:
* 属性:品牌、车牌号、每日租金、座位数
* 方法:根据天数计算租金 (租金折扣)
* */
private String brand; // 品牌
private String carNum; // 车牌号
private double dayPrice; // 每日租金public Automobile() {
}public Automobile(String brand, String carNum, double dayPrice) {
this.brand = brand;
this.carNum = carNum;
this.dayPrice = dayPrice;
}public String getBrand() {
return brand;
}public void setBrand(String brand) {
this.brand = brand;
}public String getCarNum() {
return carNum;
}public void setCarNum(String carNum) {
this.carNum = carNum;
}public double getDayPrice() {
return dayPrice;
}public void setDayPrice(double dayPrice) {
this.dayPrice = dayPrice;
}@Override
public String toString() {
return "Automobile{" +
"brand='" + brand + '\'' +
", carNum='" + carNum + '\'' +
", dayPrice=" + dayPrice +
'}';
}// 定义一个计算租金的方法 轿车和客车租金计算不同 所以我们定义抽象方法
public abstract double calcRentMoney(int days);}
package methodagain02.demo04;
public class Car extends Automobile {
private String type;
public Car() {
}public Car(String brand, String carNum, double dayPrice, String type) {
super(brand, carNum, dayPrice);
this.type = type;
}public String getType() {
return type;
}public void setType(String type) {
this.type = type;
}@Override
public String toString() {
return "Car{" +
"type='" + type + '\'' +
'}';
}// 重写抽象父类Automobile中的抽象方法
@Override
public double calcRentMoney(int days) { // 方法重写参数表相同
// 计算租金
double money = days * this.getDayPrice();
// 根据租赁天数不同,租金又折扣
if (days < 5) {
money *= 0.95;
} else if (days >= 5 && days <= 10) {
money *= 0.9;
}else {
money *= 0.8;
}
return money;
}
}
package methodagain02.demo04;
public class Bus extends Automobile {
private int sites;
public Bus() {
}public Bus(String brand, String carNum, double dayPrice, int sites) {
super(brand, carNum, dayPrice);
this.sites = sites;
}public int getSites() {
return sites;
}public void setSites(int sites) {
this.sites = sites;
}@Override
public String toString() {
return "Bus{" +
"sites=" + sites +
'}';
}@Override
public double calcRentMoney(int days) {
// 计算租金
double money = days * this.getDayPrice();
// 根据天数打折
if (days < 10) {
money *= 0.95;
}else if (days >= 10 && days <=20) {
money *=0.9;
}else {
money *=0.66;
}
return money;
}
}
package methodagain02.demo04;
public class Test {
public static void main(String[] args) {// Automobile是抽象类,不能直接new对象,可以通过多态形式,将Automobile的引用指向子类实例
// Automobile automobile = new Automobile();Automobile automobile = new Car("奥迪","皖A88866",600,"RS7");
// 租赁5天,计算租金
double rentMoney1 = automobile.calcRentMoney(3);
System.out.println(rentMoney1);automobile = new Bus("绿源","皖66688",300,9);
double rentMoney2 = automobile.calcRentMoney(8);
System.out.println(rentMoney2);}
}
1)使用父类作为方法的形参,是Java中实现和使用多态的主要方式
2)使用父类作为方法的返回值,也是Java中实现和使用多态的主要方式
// 在Master类中定义一个赠送动物的方法
public Pet givePet(String type) {
Pet pet = null; // 局部变量需要有初始值
if (type.equals("狗")) {
pet = new Dog("旺财",100,100,"哈士奇");
} else if (type.equals("猫")) {
pet = new Cat("猫咪",100,100,"黑色");
}
return pet;
}// 在main()方法中测试
// 主人根据你的需求赠送动物给你
Master master = new Master();
Pet pet1 = master.givePet("狗");
// 输出pet1信息
pet1.printInfo();Pet pet2 = master.givePet("猫");
pet2.printInfo;Pet pet3 = master.givePet("qwert");
pet3.printInfo; // 报错 NullPointerException 空指针异常
System.out.println(pet3); // 输出结果 null