第五章Java类的继承与多态
此笔记通过观看【尚学堂】+《Java程序设计(赖小平主编)清华大学出版社》整理得出
5.1类的继承
继承与派生是互逆关系。
继承的解析:例如动物类的派生是鸟类、鱼类等,反过来,鸟类、鱼类是动物类的继承。
子类可以继承父类的属性和方法,还可以添加一些新的属性和方法。
虽然说可以继承父类的属性跟方法,但是有些属性跟方法不能被使用(要看属性跟方法的访问修饰符)
【语法格式:】
访问修饰符 class 子类名extends 父类名{ [成员变量声明] [构造器声明] [成员方法声明] }
【实例测试】
注:选中类按Ctrl+t,可以看到类之间的继承关系
说明:
1、 Java只支持单继承,不允许多重继承(一个子类只能有一个父类,一个父类可以派生多个子类)
2、 Java支持多层继承(一个父类派生子类,子类又可以派生子类,类似于家族)
3、 子类可以继承父类的方法和属性
4、 子类不能继承父类的构造方法(在子类中可以用super调用父类的构造器)
5、 父类不拥有子类新增的属性跟方法
【实例 测试员工类跟经理类的工资待遇】
package cn.gdlgxy.David;
/**
* 测试员工跟经理的工资待遇
* @author 卟淡
*
*/
class Employee{ //员工类
private String name; //姓名
private char sex; //性别
private double salary; //工资
public Employee(String name,char sex,double salary){ //带参数的构造方法
this.name = name;
this.sex = sex;
this.salary = salary;
}
public String getName() { //获取姓名
return name;
}
public void setName(String name) { //设置姓名
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getSalary() { //获取月薪
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getMoney() {
return "姓名:" + name + "\n性别:"+ sex + "\n工资:" + salary;
}
}
class Manager extends Employee{
private double bonus;
public Manager(String name,char sex,double salary,double bonus) {
super(name,sex,salary); //调用父类的构造方法
this.bonus = bonus;
}
public double getBonus() { //获取奖金
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
public double getIncome() { //获取月收入
return getSalary() + getBonus();
}
}
public class TestSalary {
public static void main(String[] args) {
Manager mng = new Manager("David",'男',5000,3000);
System.out.println(mng.getMoney());
System.out.println("提成:" + mng.getBonus() + "\n月收入:" + mng.getIncome());
}
}
结果:
5.1.1 方法的重写(override)
子类通过重写父类的方法,可以用自身行为替换父类的行为。
说明:
1、 方法名形参相同
2、 子类返回值类型和声明异常类型小于等于父类
3、 子类访问权限大于等于父类
5.1.2 操作符instanceof
特别注意的是,强制向下转型并不是都能成功执行,由于父类的对象变量引用的对象类型有可能是父类型,导致转型失败。建议用instanceof操作符判断当前对象变量引用的对象的实质类型。
【语法格式】
对象变量名 instanceof 类型名;
返回值类型为boolean型。
当对象变量引用的对象的真是类型与指定类型一致是,返回true,否则false
If(pe instanceof Student){ //如果类型匹配
Student pe2 = (Student)pe; //可以安全的强制向下转型
}
【实例 测试instanceof】
package objectClassTest;
/**
* 测试instanceof
* @author 卟淡
*
*/
class People{
private String name;
private int age;
public People(String name,int age) {
this.name = name; //引用成员变量(把name赋回给成员变量)
this.age = age;
}
public String setName(){
return name;
}
public void getName(String name) {
this.name = name;
}
public int setAge()throws Exception {
if(age<=1&&age>=130)throw new Exception("年龄不正常");
return age;
}
public void getAge(int age) {
this.age = age;
}
public void walk() {
System.out.println("人在走路...");
}
public void talk() {
System.out.println("人在说话...");
}
}
class Student extends People{
String id;
public Student(String name,int age,String id) {
super(name,age);
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void talk() { //重写方法
System.out.println("他在说话...");
}
public void Print() { //新增方法
System.out.println("在学习....");
}
}
public class Person{
public static void main(String[] args) {
System.out.println("===测试instanceof方法=====");
People pe = new People("小黑",19);
Student stu = new Student("小黑",20,"12345678");
System.out.println("对象pe是People吗:" + (pe instanceof People));
//对象pe是People吗:true
System.out.println("对象pe是Student吗:" + (pe instanceof Student));
//对象pe是Student吗:false
System.out.println("对象stu是People吗:" + (stu instanceof People));
//对象stu是People吗:true 子类对象类型对象与父类类型匹配
People a = new Student("David",18,"155515515"); //上转型
System.out.println("对象a是People吗:" + (a instanceof People));
System.out.println("对象a是Student吗:" + (a instanceof Student));
//对象a是People吗:true
//对象a是Student吗:true
//上转型对象与父类类型匹配,又与子类类型匹配
}
}
5.1.3 Object类
Object类是所有java类的根基类,也就意味着所有的java的对象都拥有Object类的方法和属性。
按Ctrl查看源码
Object类中的toString()方法
源码:
Integer.toHexString(hashCode())
可认为是地址,@+16进制的hasCode
根据如上源码得知,默认会返回“类名 + @+16进制的hasCode”。在打印输出或者用字符串连接对象时,会自动调用该对象的toString()方法。
注:也可重写toString方法。
Object类中的equal方法
“==”比较双方是否相同。如果是基本类型则表示值相等,如果是引用数据类型则表示地址相等则为同一个对象。
Object类中定义有:public Boolean equals(Object obj)方法,提供定义“对象内容相等”的逻辑
注:此方法暂未做深入了解,若遇到再进行解决。
5.1.4 super关键字
关键字super用于指代父类的对象。用super做前缀,引用父类被覆盖的成员变量,调用父类被重写的成员方法,以及调用父类的构造方法。
- 1、 引用父类被覆盖的成员变量
【实例】
结果:
200
100
- 2、 调用父类被重写的成员方法
说明:
1、 具有相同的方法名称、参数列表和返回值类型
2、 更小的访问权限
3、 同为static或非static
4、 抛出的异常不能更大
格式:
super.成员方法名(参数列表)
【实例】
package cn.gdlgxy.David;
/**
* 调用父类被重写的方法和调用父类的构造方法
* @author 卟淡
*
*/
class Person{
private String name;
private int age;
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getInfo() {
return "Name:" +name + "\nAge:"+age;
}
}
public class Student01 extends Person {
String school;
/*public Student01(String school) {
super();
若父类没有定义默认的构造器,构造方法1编译出错:no super()
当Person手动定义一个默认的构造器:public Person() { }
上面会默认自动使用“super()(写不写都可以)”调用父类的构造器
this.school = school;
}*/
public Student01(String name,int age,String school) {
super(name,age); //显式调用父类的构造方法
this.school = school;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public String getInfo() {
//重写方法---并使用super关键字调用了父类的方法
return super.getInfo()+"\nSchool:"+school;
}
public static void main(String[] args) {
Student01 student = new Student01("David",20,"gdlgxy");
System.out.println(student.getInfo());
}
}
- 3、 调用父类的构造方法
格式:
super(父类构造方法属性)
【实例】
Super关键字调用构造方法的原则如下:
(1) 作为第一条语句
(2) 只能在子类的构造方法中使用
(3) 只能用super调用父类的构造方法,不能使用方法名直接调用父类构造方法
在子类中,使用构造器创建对象时,子类的构造器一定先调用父类的构造器对父类的属性进行属性初始化,然后才对自己的属性初始化。在默认情况下,子类构造器调用父类无参的默认构造器,但如果父类没有定义默认的构造器,子类的构造器中必须显式地使用super关键字调用父类中定义的其它构造器,否则,编译出错。
【实例】