diff --git a/03:类与对象/04.md b/03:类与对象/04.md index 30e8bce..94037d8 100644 --- a/03:类与对象/04.md +++ b/03:类与对象/04.md @@ -372,59 +372,235 @@ main函数开起来比较奇怪,为什么在Faculty内中,又使用new 方 ``` +可以看到,这是典型的函数调用栈的方式:最先进入的函数最后退出。其实PPP类还隐式调用了Object(),会在Object小节讲解。 +## 3. Overriding 覆盖父类的方法 +在很多时候,子类型可能需要改变父类型的一些行为(函数),这时子类型可以定义一个与父类型一样的函数,但是实现不一样,这样父类型的实现就被隐藏了。 +### 3.1. 继承父类型的函数 -## 3. Overriding 覆盖父类的方法 +先来看看子类型继承父类型,拥有父类型的全部能力的情况: + +```java +class Fruit { + public String toString() { + return "This is fruit."; + } +} + +class Apple extends Fruit { + +} + +public class Test { + public static void main(String[] args) { + Apple apple = new Apple(); + System.out.println(apple.toString()); // 输出:This is fruit. + } +} +``` + +Apple中没有toString()函数,但是其父类型后,因此Apple也得到了这样的能力。其实是间接调用父类型的toString()函数。 + +### 3.2. 覆盖父类型的函数 + +如果在Apple中也定义一个toString()函数会有什么样的结果? + +```java +class Fruit { + public String toString() { + return "This is fruit."; + } +} + +class Apple extends Fruit { + public String toString() { + return "This is an apple."; + } +} + +public class Test { + public static void main(String[] args) { + Apple apple = new Apple(); + System.out.println(apple.toString()); // 输出:This is an apple. + } +} +``` + +Apple类型中的 toString() 函数覆盖了父类型的同名函数,这样的方式叫做 override。在Apple类型的对象上面调用toString()会出现Apple类自己toString()函数的行为,而不会调用Fruit类型的toString()。换句话说,子类型如果定义了和父类型一样的函数,父类型的这个同名函数将不可见。 + +### 3.3. 使用super关键字调用父类型被隐藏的函数 + +子类如果覆盖了父类的某个函数,但是在子类中(只能在直接子类中)任然有办法调用父类被隐藏的函数。 + +```java +class Fruit { + public String toString() { + return "This is fruit."; + } +} + +class Apple extends Fruit { + public String toString() { + return super.toString() + "\nThis is an apple."; + } + + public void printFruitToString() { + System.out.println(super.toString()); + } +} + +public class Test { + public static void main(String[] args) { + Apple apple = new Apple(); + System.out.println(apple.toString()); + apple.printFruitToString(); + } +} +``` + +结果是: + +``` +This is fruit. +This is an apple. +This is fruit. +``` + +1、2行输出是`System.out.println(apple.toString());` 的结果。可以看到第1行是Apple类中`toString()`函数使用`super.toString()`调用了Fruit类中`toString`的结果。第3行使用Apple的函数`printFruitToString()`,本质也是使用了`super.toString()`。 + +**注意:super关键字只能在直接子类中使用,表示其直接父类。** + +### 3.4. Overriding vs. Overloading + +> An instance method can be overridden only if it is accessible. Thus a private method cannot be overridden, because it is not accessible outside its own class. If a method defined in a subclass is private in its superclass, the two methods are completely unrelated. +> +> (了解)实例函数在子类中可以访问的情况下才可以被覆盖。如果父类中有一个私有函数,子类中定义了一个函数(与父类函数名,参数都一样),那么这两个函数没有任何关系。 +> +> Like an instance method, a static method can be inherited. However, a static method cannot be overridden. If a static method defined in the superclass is redefined in a subclass, the method defined in the superclass is hidden. +> +> (了解)和实例函数一样,静态函数可以被子类继承;但是静态函数不能被覆盖;如果子类型重新定义了父类型的静态函数,父类型的静态函数将被一直隐藏。 + +![image-20230312150607935](img/image-20230312150607935.png) + +覆盖(Overriding):只在父类型函数和字类型函数一样的情况下出现; + +重载(Overloading):函数签名不一样 + +上图中左边是覆盖,右边是重载。 + +## 4. Object类 + +如果在定义的时候不使用关键字(extends)指定父类,那么默认其父类是Object。也就是说,所有的引用类型都是从Object直接或者是间接继承(扩展)而来的。 + +```java +class Fruit{ + +} +// 与下面是一样的 +class Fruit extends Object{ + +} +``` + +### 4.1. toString方法 +这样以来,所有引用类型都具备Object所具备的所有能力,最常用的就是toString()方法。 +toString()方法是在Object中定义的方法,会打印一个该对象的描述。表述的大约格式是:类名@对象地址 -## 4. Overriding vs. Overloading +```java +class Fruit{ + +} +public class Test { + public static void main(String[] args) { + Fruit fruit = new Fruit(); + System.out.println(fruit.toString()); + } +} +``` +试试上面的例子。 -## 5. Object类 +## 5. Polymorphism多态 +> Polymorphism means that a variable of a supertype can refer to a subtype object. +> +> 多态是指直接或者间接的父类型引用变量可以用来引用字类型的对象。很难理解,有什么用? +> +> A class defines a type. A type defined by a subclass is called a subtype, and a type defined by its superclass is called a supertype. Therefore, you can say that Circle is a subtype of GeometricObject and GeometricObject is a supertype for Circle. +> +> 上面是说父类型和字类型的关系。例如借用本章开头的分类图:猫种可以说成是属于猫属、猫科、食肉动物目。。。就是这意思,这有什么用? +我们先来看看一个例子: -### 5.1. toString方法 +```java +class Fruit { + public String toString() { + return "This is fruit."; + } +} +class Apple extends Fruit { + public String toString() { + return "This is an apple."; + } +} +class Orange extends Fruit { + public String toString() { + return "This is an orange."; + } +} -## 6. Polymorphism多态 +public class Test { + public static void main(String[] args) { + Apple apple = new Apple(); + Orange orange = new Orange(); + printInfo(apple); + printInfo(orange); + } + + static void printInfo(Fruit fruit) { + System.out.println(fruit.toString()); + } +} +``` -### 6.1. 动态函数绑定 +### 5.1. 动态函数绑定 -## 7. 引用类型的类型转换 +## 6. 引用类型的类型转换 -### 7.1. 子类型转换成父类型 +### 6.1. 子类型转换成父类型 -### 7.2. 父类型转换成子类型 +### 6.2. 父类型转换成子类型 -## 8. equals 方法 +## 7. equals 方法 -## 9. ArrayList类 +## 8. ArrayList类 -## 10. protected 访问修饰 +## 9. protected 访问修饰 -## 11. final 修饰 +## 10. final 修饰 diff --git a/03:类与对象/img/image-20230312150607935.png b/03:类与对象/img/image-20230312150607935.png new file mode 100644 index 0000000..2d8186c Binary files /dev/null and b/03:类与对象/img/image-20230312150607935.png differ