共计 4102 个字符,预计需要花费 11 分钟才能阅读完成。
继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法。或子类从父类继承方法,使得子类具有父类相同的行为。父类更通用,子类更具体。子类会具有父类的一般特性也会具有自身的特性。
继承的特性
1. 子类拥有父类非 private 的属性、方法。
基类的 protected 成员是包内可见的,并且对子类可见;若子类与基类不在同一包中,那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的 protected 方法。
对于子类可以继承的父类成员变量,如果在子类中出现了同名称的成员变量,则会发生隐藏现象,即子类的成员变量会屏蔽掉父类的同名成员变量。如果要在子类中访问父类中同名成员变量,需要使用 super 关键字来进行引用。
2. 子类可以对父类进行扩展。子类可以用自己的方式实现父类的方法。
重写 (Override) —— 只能发生在继承关系里 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
方法的重写规则:参数列表,返回类型必须完全与被重写方法的相同;访问权限不能比父类中被重写的方法的访问权限更低;声明为 final 的方法不能被重写;声明为 static 的方法不能被重写,但是能够被再次声明;构造方法不能被重写。
重载 (Overload) ——- 继承,和同一个类 重载 (overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。最常用的地方就是构造器的重载。
重载规则: 被重载的方法必须改变参数列表 (参数个数或类型不一样);被重载的方法可以改变返回类型,和访问修饰符;方法能够在同一个类中或者在一个子类中被重载
3. Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 A 类继承 B 类,B 类继承 C 类,所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
4. 提高了类之间的耦合性
5. 继承的初始化顺序父类对象属性初始化 —-> 父类对象构造方法 —-> 子类对象属性初始化 —> 子类对象构造方法
6. 构造器子类是不继承父类的构造器的,它只是调用。子类的构造过程必须调用父类的构造方法。如果子类的构造方法中没有显示调用父类的构造方法,则系统默认调用父类无参的构造方法。如果用 super 关键字在子类里调用父类的构造方法,则必须在子类的构造方法中的第一行。所以,子类的每一个构造方法的第一条语句默认都是 super()。显式调用或隐式调用(无参构造方法)。例如:
class SuperClass {
private int n;
SuperClass(){
System.out.println(“SuperClass()”);
}
SuperClass(int n) {
System.out.println(“SuperClass(int n)”);
this.n = n;
}
}
// SubClass 类继承
class SubClass extends SuperClass{
private int n;
SubClass(){ // 自动调用父类的无参数构造器
System.out.println(“SubClass”);
}
public SubClass(int n){
super(300); // 调用父类中带有参数的构造器
System.out.println(“SubClass(int n):”+n);
this.n = n;
}
}
// SubClas2 类继承
class SubClass2 extends SuperClass{
private int n;
SubClass2(){
super(300); // 调用父类中带有参数的构造器
System.out.println(“SubClass2”);
}
public SubClass2(int n){// 自动调用父类的无参数构造器
System.out.println(“SubClass2(int n):”+n);
this.n = n;
}
}
public class TestSuperSub{
public static void main (String args[]){
System.out.println(“——SubClass 类继承 ——“);
SubClass sc1 = new SubClass();
SubClass sc2 = new SubClass(100);
System.out.println(“——SubClass2 类继承 ——“);
SubClass2 sc3 = new SubClass2();
SubClass2 sc4 = new SubClass2(200);
}
}
输出结果为:
——SubClass 类继承 ——
SuperClass()
SubClass
SuperClass(int n)
SubClass(int n):100
——SubClass2 类继承 ——
SuperClass(int n)
SubClass2
SuperClass()
SubClass2(int n):200
要注意的是:如果子类构造方法中既没有显示调用父类的构造方法,而父类没有无参的构造方法,则编译出错。(补充说明,虽然没有显示声明父类的无参的构造方法,系统会自动默认生成一个无参构造方法,但是,如果你声明了一个有参的构造方法,而没有声明无参的构造方法,这时系统不会动默认生成一个无参构造方法,此时称为父类有没有无参的构造方法。)
7. Object 类 Object 类是所有类的父类,如果一个类没有使用 extends 关键字明确标识继承另一个类,那么这个类默认继承 Object 类。Object 类中的方法,适合所有子类!!!
封装
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。封装可以使我们容易地修改类的内部实现,而无需修改使用了该类的客户代码。并且,可以对成员变量进行更精确的控制。
多态
指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)。
多态存在的三个必要条件继承、重写、父类引用指向子类对象(向上转型)
向上转型(小类型转换到大类型)
Animal animal = new Dog()
1. 可以调用父类中所有的方法和属性;2. 如果子类重写了父类的方法,则调用子类重写的方法;3. 子类特有的属性和方法不可以调用。
向下转型(大类型转换到小类型)
Animal animal = new Dog()
Dog dog2 = (Dog)animal
1. 父类引用没有指向该子类的对象,则不能向下类型转换,如:Dog dog2 = (Dog)new Animal();2. 父类的引用指向其他子类的对象,则不能通过强制转为该子类的对象,如:Animal animal = new Dog();Dog dog2 = (Dog)animal;Cat cat = (Cat)animal;// 编译 Cat,运行 Dog;3. 有风险, 可能出现数据溢出
instanceof 运算符,来解决引用对象的类型,避免类型转换的安全性问题。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 类型的数据。
if(animal instanceof Cat){
Cat cat = (Cat)animal;
}
instanceof 和 getClass 这两种方法都可以比较一个对象是否和另一个对象属于同一个类的实例,但是两者在判断上面是有差别的。Instanceof 进行类型检查规则是: 你属于该类吗?或者你属于该类的派生类吗?而通过 getClass 获得类型信息采用 == 来进行检查是否相等的操作是严格的判断, 不会存在继承方面的考虑。
多态的应用实例:Java 多态 ——一个案例 彻底搞懂它
继承链中对象方法的调用优先级
1. 了解继承关系;2. 优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O);3. 判断是不是多态,多态需要考虑子类是否有重写该方法,如果有重写需要调用重写的方法。
public class A {
public String show(D obj) {
return (“A and D”);
}
public String show(A obj) {
return (“A and A”);
}
}
public class B extends A{
public String show(B obj){
return (“B and B”);
}
public String show(A obj){
return (“B and A”);
}
}
public class C extends B{
}
public class D extends B{
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(“1–” + a1.show(b));
System.out.println(“2–” + a1.show(c));
System.out.println(“3–” + a1.show(d));
System.out.println(“4–” + a2.show(b));
System.out.println(“5–” + a2.show(c));
System.out.println(“6–” + a2.show(d));
System.out.println(“7–” + b.show(b));
System.out.println(“8–” + b.show(c));
System.out.println(“9–” + b.show(d));
}
}
运行结果:
1–A and A
2–A and A
3–A and D
4–B and A
5–B and A
6–A and D
7–B and B
8–B and B
9–A and D