方法重写
父子类继承关系中,当子类需要父类的功能,而继承的方法不能完全满足子类的需求,子类里面有特殊的功能,此时可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
方法重写细节
- 前提:父子类继承关系中
- 子类新增方法,和从父类继承的方法,方法名完全相同
- 两个方法的参数列表完全相同
- 重写方法的访问权限修饰符可以被扩大,但是不能被缩小
- public > protected > default > private
- 方法的返回类型可以相同,也可以不同
- 方法抛出异常类型的范围可以被缩小,但是不能被扩大
案例:
//定义父类:员工
class Employee {
//工号、姓名
private String id;
private String name;
public Employee() {}
public Employee(String id, String name) {
this.id = id;
this.name = name;
}
public void doWork() {
System.out.println("员工开始工作...");
}
}
//定义子类:程序员
class Programmer extends Employee {
//等级:初级、中级、高级、资深
private String grade;
public Programmer() {
//默认会调用父类无参构造器
//super();
}
public Programmer(String id,String name,String grade) {
//显式调用父类构造器
super(id,name);
this.grade = grade;
}
//重写
@Override
public void doWork() {
//super.doWork();
System.out.println("我是程序员,级别为" + grade + ", 开始工作:写代码");
}
}
//定义子类:经理
class Manager extends Employee {
//奖金
private double bonus;
public Manager() {
super();
}
public Manager(String id,String name,double bonus) {
super(id,name);
this.bonus = bonus;
}
//重写方法
@Override
public void doWork() {
System.out.println("我是经理,有津贴" + bonus + ", 开始工作:安排部门员工任务");
}
}
//测试类
public class Test06_Override {
public static void main(String[] args) {
//父类对象 调用 doWork方法
Employee e = new Employee("008", "larry");
e.doWork();
System.out.println("------------");
//程序员子类对象 调用 重写方法
Programmer p = new Programmer("010", "kevin", "初级");
p.doWork();
System.out.println("------------");
//经理子类 调用 重写方法
Manager m = new Manager("006", "robin", 201.5);
m.doWork();
}
}
运行结果
注意事项:
- 父类中的静态方法(属于类方法)不能被子类重写 static静态方法算不上重写,它是属于父类所独有的,只是书写格式上跟重写相似 。
- 父类中的私有方法(未被继承)不能被子类重写
重写和重载的区别
重写发生在子父类中 重载发生在一个类中
重写规则:为了覆盖(重写)父类的方法
- 重写要求权限不能缩小 访问修饰符可以扩大 不能被缩小 public>protected>default>private
- 两个方法的方法名 参数列表完全相同
- 要求返回值的返回类型可以相同也可以不同 一般相同
- 方法抛出异常类型的范围可以被缩小 但是不能够被扩大
一般情况下,子类进行方法重写时,最好方法的声明完全一致
结论:
子类继承父类,在调用方法的时候,如果子类中没用重写,那么调用 从父类继承的方法,如果子类重写了这个方法,那么调用到子类重写的方法。( 非常重要 )
多态
多态的前提
- 子类继承父类
- 子类重写父类中的方法
- 父类的引用指向子类对象
案例:
package com.briup.day08;
/**
* @author 谭梦寻
* @version 1.1
*/
public class Test01 {
/*
多态前提:
子类继承父类
子类重写父类中的方法
父类的引用指向子类对象
注意:
当调用属性时,编译和运行都看左边 --》属性也没有重写
当调用非重写方法时,编译和运行都看左边
当调用重写方法时,编译看左边 运行看右边
*/
public static void main(String[] args) {
// 1 面向对象创建字符串对象 通过构造器创建对象
String s = new String("abc");
String s2 = new String("abc");
/*
System.out.println(s.equals(s2));//true
不是一个对象 但是是String类型 比较长度后比较内容 都满足也会返回true
*/
System.out.println(s.equals(s2));//true String里面重写了Object中的equals方法
System.out.println(s==s2);//false 两个引用是否指向同一个对象
Integer i = new Integer(1);
Integer i2 = new Integer(1);
System.out.println(i.equals(i2));// true 同理于String
// 多态 父类型的引用 指向子类型对象 --> 看等号右边
// 隐式转换 大类型 = 小类型 long a = 1;
SuperName superName = new SubName();
superName.method();//son
superName.method2();//Father2
SuperName superName1 = new SuperName();
// superName.method3(); //私有方法无法调用 也无法继承
// superName.method4();//报错
/*
子类对象调用该方法 引用的类型是父类型
如果是重写 编译看左边 运行看右边
即:是否能通过编译 由父类决定 父类引用无法调用子类私有方法
运行结果看子类
如果不是重写 编译和运行都是看左边
*/
SuperName b = new SubName();
Object o = new SuperName();
o = b;//隐式转换
b = (SubName) o;//强制转换 等价于SuperName b = o = new SubName();
String s1 = new String("abc");
// s1 = (String) o;//编译没问题 运行报错 ClassCastException
/*
instanceof
对象类型的比较
判断引用名实际指向的对象,其所属类型是否为右边的类型名,
返回boolean类型结果
*/
Object b2 = new SubName();
System.out.println(b2 instanceof String); //false
System.out.println(b2 instanceof SubName); //true
System.out.println(b2 instanceof Object); //true
}
}
class SuperName {
public static void main(String[] args) {
SuperName superName = new SubName();
superName.method();//son
superName.method2();//Father2
SuperName superName1 = new SuperName();
superName.method3(); //Father3
// superName.method4();//报错
}
public void method() {
System.out.println("Father");
}
public static void method2() {
System.out.println("Father2");
}
private void method3() {
System.out.println("Father3");
}
}
class SubName extends SuperName{
public void method() {
System.out.println("Son");
}
public static void method2() {
System.out.println("Son2");
}
private void method3() {
System.out.println("Son3");
}
public void method4() {
System.out.println("Son4");
}
}
注意:
- 当调用属性时,编译和运行都看左边 --》属性也没有重写
- 当调用非重写方法时,编译和运行都看左边
- 当调用重写方法时,编译看左边 运行看右边
向上转型(隐式转换)
父类引用指向子类对象,多态部分我们已经大量使用
例如, Person p = new Student();
向下转型(显式转换)
子类引用指向父类对象
格式: 子类型 对象名 = (子类型)父类引用;
前提:父类对象本身就是子类类型
Person p = new Student();
Student s = (Student)p; //向下转型
注意事项:先有向上转型,然后才能有向下转型
==和equals的区别
基本数据类型: 1==2 true == false 比较的数值 二进制代码是否相同
引用数据类型: equals 比较的两个引用是否实质相同一个对象 比较地址值(哈希值) equals 只能比较引用类型 即对象 如果equals没有被重写 就使用时Object类中提供的逻辑 比较两个引用的地址值是否相等 如果equals被重写了 就是重写后的逻辑 。
总结:==用于比较基本数据类型,否则会报类似于Operator '==' cannot be applied to 'java.lang.String错误。equals用于比较引用类型。