重写也称为覆盖, 是指子类与父类的方法名相同但是可以有不同的权限(子类权限需大于父类),返回值(J2SE 5.0以后增加的功能,且子类的返回值必须是父类返回值的子类)或者方法实现。

重写体现了子类补充或者改变父类方法的能力, 通过重写, 可以使一个方法在不同的子类中表现出不同的行为。

public class Animal {
    protected void cry(){
        System.out.println("animal crying")
}
}
public class Cat exrends Animal{
@Override
    public void Cry(){
        System.out.println("Cat crying")
}
}

需要注意的是, 重写方法不能声明比被重写方法更宽泛的检查异常, 比如父类方法中声明了IOException, 那么子类重写方法只能申明IOException或者其子类或者不声明, 不能声明Exception

why?  因为try  catch的时候,只能捕获到父类声明的异常范围

存疑: 在kotlin中, 下面代码并没有报错, 难道kotlin中可以?

open class Animal {
    open fun cry(){
        println("cry...")
        throw IOException()
    }
}
class Dog: Animal() {
    override fun cry(){
        println()
        throw Exception()
    }
}
class Test {
    val dog = Dog()

    fun test(){
        try {
            dog.cry()
        } catch (e: Exception){

        }
    }
}

子类可以继承父类的非私有成员变量和成员方法, 但是如果子类声明的成员变量与父类的同名, 则子类不能继承父类的成员变量, 此时称子类的成员变量隐藏了父类的成员变量。

如果子类声明的成员方法与父类的同名, 且方法返回值,参的个数和类型都相同, 则称为子类重写了父类的成员方法 。

这时, 如果子类想要访问父类的成员变量/成员方法, 就需要用到super关键字

 

声明为static/ final的方法 (private也属于final) 不能被子类重写 

因为这部分方法是静态绑定的, 编译器一开始就能确定要调用的版本, 并且在整个运行期间是不可变的, 在类加载的时候就会把符号引用转化为该方法的真正引用, 并不具有多态性

与之对应, 在程序运行期间才确定调用版本的方法叫做动态绑定,此时,虚拟机会为每个类创建一个方法表, 列出所有方法的签名和实际调用的方法,这样一来,虚拟机运行时只需要查找该表就行了。 只有动态绑定的方法才具有多态性。

当然我们可以在子类中声明一个和父类同样方法名的static方法, 但它实际上和父类的方法是两个互不相干的方法 

重构: 是指子类与父类方法名相同但方法实现不同。 重构是特殊的重写 

public class Dog exrends Animal{
@Override
    protected void Cry(){
        System.out.println("Dog crying")
}
}

 

重载: 发生在同一个类之间。 同一个类中,同名方法的参数类型/个数/顺序不同

最常见的重载就是构造方法, 因为构造方法的名称已经由类名确定, 那么如果希望以不同的方式来实例化对象,就必然要用到方法重载

重载以参数来区分方法,返回类型可同可不同, 但参数必须不同

public class Wolf exrends Animal{
@Override
    protected void Cry(){
        System.out.println("Dog crying")
}
 
protected void eat(String meat){
        System.out.println("Wolf eat:" + meat)
}
 
protected void eat(String meat, String water){
        System.out.println("Wolf eat:" + meat+ ", and drink: "+water)
}
}