目录
子类与父类
所有类的祖先类都是Object类
用extends关键字来定义一个类的子类,如:
class A { ... } class B extends A { //B为A的子类,A为父类 ... }
继承和子类的继承性
子类的继承性:
① 子类拥有父类非private的属性和方法。(不继承父类构造方法)
② 子类可以拥有自己的属性和方法,对父类进行扩展。
③ 单继承,多重继承。
④ 如果子类和父类不在同一包中,子类不继承父类的友好成员变量。(当用子类构造方法创建一个子类对象时,不仅子类中声明的成员变量被分配了内存,而且父类的成员变量也被分配了内存空间)
Tips:
同一包当中的继承性:继承父类当中不是private的方法和变量
不同包的继承性:只能继承protected类和public类,不继承友好类和private类
子类和对象
子类对象的特点
当用子类创建一个对象时,不仅子类中声明的成员变量被分配了内存,而且父类中的成员变量也都分配了内存空间。但只有被继承的那部分变量分配给了子类。
子类在继承时,也同样为private的方法和变量分配了空间,虽然分配了内存空间但是其并非子类对象的变量,或者说,获取了相应的值和函数,但是并没有直接访问和调用他们的权力。
当然,子类可以通过其他的方法来操作这些没有访问权限的变量,例如:
class A { private int x; public int getX() { return x; } } class B extends A { //显然B的对象没有权利直接访问x的值 ... }
B b = new B(); int i = b.x // 非法 int j = b.getX() // 合法,因为getX方法类型为public,能够被B类继承
instanceod运算符
instanceod运算符是Java独有的双目运算符。
该左面的操作元是对象,右面的操作元是类,当左边的操作元是右侧的类或者其子类创建的对象时,instanceod运算符的结果为true, 否则是false。接上例如:
boolean x; x = b boolean A; // true
成员变量的隐藏和方法重写
变量隐藏:
当子类所声明的成员变量的名字与父类成员变量的名字相同时(声明类型可不同),子类会隐藏所继承的成员变量(想要使用则需使用super关键字)。子类自己定义的方法操作同名成员变量,该成员变量是重新声明的变量。子类调用父类继承的方法中调用的同名成员变量是隐藏的从父类继承的成员变量。
class A { int x = 10; int getX() { return x; } } class B extends A { int x; // 子类又声明了一个x,父类的x被隐藏 setX(int i) { x = i; } }
B b = new B(); b.setX(100); // 此时对象b中B新建立的x值是100 int a = b.getX(); // a的值还是10
方法重写:
规则:
子类定义一个方法,该方法的类型与父类方法的类型一致,并且这个方法的名字、参数个数、参数类型和父类的方法完全相同,该方法就叫子类重写的方法。重写父类的方法时不能降低方法的访问权限(public>protected>友好的>private)。
class A { int x = 10, sum; int getSum(int a) { sum = x + a; return sum; } } class B extends A { int sum; int getSum(int a) { // 重写了方法int getSum(int a) sum = x + x + a; return sum; } }
class A { protected int getSum(int a, int b) { return a + b; } } class B extends A { int getSum(int a, int b) { // 非法,降低了访问权限 return (a + b)*2; } } class C extends A { public int getSum(int a, int b) { // 合法 return a + a + b; } }
目的:
方法的重写会隐藏继承的方法,子类调用同名方法,该方法为重写的方法。若子类未重写父类的某个方法,那这个方法也可以被子类的对象调用,但是调用的是其父类的方法。
Tips:注意重载和重写的区别
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;
重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。
重载对返回类型没有特殊的要求,不能根据返回类型进行区分。
super关键字
(1)用super操作被隐藏的成员变量和方法
(2)通过super.成员变量或方法可以调用被隐藏的父类成员变量或方法。
(3)使用super调用父类的构造方法
当用子类构造方法创建对象时,子类构造方法总是先调用父类的构造方法。由于子类不继承父类的构造方法,因此子类在其构造方法中需要使用super来调用其父类的构造方法。当子类没有明显写出super调用父类的某个构造方法时,会默认在子类构造方法中加入super();所有当父类有多个构造器时,应当含有一个无参构造器,避免子类省略super();时产生调用错误。
super关键字实例如下:
class A { int n = 100; } class B extends A { int n = 10; int g() { return n; } int f() { return super.n; } } //主程序中执行 int i, j; B b = new B(); i = b.g() // i = 10 j = b.f() // b = 100
final关键字
final修饰的成员变量或局部变量为常量不能被修改,如果父类的方法被final修饰,则不允许被子类重写,只能继承(如同不能坏了老祖宗传下来的规矩)。如果类被final修饰,则该类不能被继承。
- final类:final类不能被继承
- final方法:不允许子类修改继承的方法
- 常量:在声明时没有默认值,所以要求程序在声明常量时必须指定该常量的值,而且常量在运行期间不允许再发生变化。
对象上转型
父类声明,子类创建的对象为上转型对象。
对象的上转型对象的实体由子类创建,但是该对象会失去原对象的部分属性与功能,相当于子类对象进行了简化。即小明是人类,简化省去了小明是中国人的特征。
所以上转型对象不能操作子类新增的成员变量,即谁声明听谁的话。上转型对象可以访问子类继承或隐藏的成员变量,也可以调用子类继承的方法或子类重写的实例方法,即简化了全新的,保留了改进的。
不能给父类创建的对象赋值给子类声明的对象,即父亲不能听儿子的。可以将对象的上转型对象强制转换到一个子类对象,就恢复原来的属性和方法。如果子类重写了父类的静态方法,那子类对象的上转型对象不能调用子类重写的静态方法,只能调用父类的静态方法。
例如:
class A { private int a = 100; static void f() { System.out.println("Well done!"); } void outPut() { System.out.println(a); } void print() { System.out.println("Hello Word!"); } } class B extends A { static void f() { System.out.println("Go for it!"); } void print() { System.out.println("This is a Java program"); } void compute(int a, int b) { System.out.println("两数相加的结果是:"+ a + b); } } //显然A是B的父类 //下面用子类B创建一个对象 A a; // 将对象的引用放到父类当中 a = new B(); //用子类创建了一个对象 //或者写作 Animal a; Tiger b = new Tiger(); a = b; //此时称 a 是对象 b 的上转型对象
简言之:
(1)上转型对象不能操作子类新增的变量和方法。
a.compute(10, 20); // 非法,a作为上转型对象不能操作子类新增的compute方法
(2)上转型对象能访问子类继承和隐藏的变量、方法。
a.outPut(); // 合法,a作为上转型对像可以调用子类继承的方法
(3)上转型对象能操作子类继承或者重写的方法,但是如果子类重写了父类的静态方法,那么它只能调用父类的静态方法而不能调用子类重写的静态方法。
a.print(); // 合法,输出This is a Java program"
(4)如果子类重写父类的静态方法,那么子类的上转型对象不能调用子类重写的静态方法,只能调用父类的静态方法。
a.f(); // 合法,输出"Well done",因为上转型对象只能调用父类的静态方法
继承和多态
一个类的各个子类如果都重写了父类中的同一个方法,而且这些子类创建的对象都定义为子类的上转型对象,那么各个子类就会产生各自的功能行为,我们称次现象为“多态”。
多态性:父类的某个方法被子类重写时,可以产生自己的功能和行为。
抽象类和抽象方法(abstract类和abstract方法)
abstract class A{ abstract void speak(); abstract void cooking(){方法体} }
抽象类:用abstract修饰的类
抽象方法:用abstract修饰的方法
抽象方法只能声明,不能有方法体。且不允许使用final和abstract同时修饰一个方法或类。不允许用static修饰abstract方法。
抽象类中可以有抽象方法,抽象类只能被继承不能创建对象。继承抽象类的子类必须重写父类的抽象方法(去掉abstract修饰),而final方法不能被继承,所以抽象类中的抽象方法不能被final修饰。如果抽象类继承抽象类则可以继承父类的抽象方法,也可以重写父类的abstract方法。
抽象类虽然不能创建对象(new),但可以声明对象。作为上转型对象。
例如:
//abstract类当中可以有abstract方法,也可以有非abstract方法 abstract Class A { abstract void a(); // abstract方法 void b(); // 非abstract方法 } //abstract类不能使用new创建该类的对象实体;如果某个非抽象类是抽象类的子类,那么如果它继承的方法中有抽象方法,则必须将其重写,这样才能创建该子类的实体 class B extends A { void a() { // 必须重写abstract方法 ... } }
- ① 抽象类中可以有抽象方法,也可以有非抽象方法。
- ② 抽象方法只允许声明,不允许实现。
- ③ 不允许使用final和static修饰抽象方法。
- ④ 继承抽象类时必须重写它所有的抽象方法。
- ⑤ 抽象类不允许创建对象。
开闭原则
对扩展开发,对修改关闭。
知识点小结
1、子类继承的方法只能操作子类继承和隐藏的成员变量。
2、不可以同时用final和abstract修饰同一个方法。
3、不允许使用static修饰abstract方法。
4、所谓子类继承父类的成员变量作为自己的一个成员变量,就好象它们是在子类中直接声明一样,可以被子类中自己定义的任何实例方法操作。
5、如果在子类中想使用被子类隐藏的成员变量或方法就需要使用关键字super。
6、子类不继承父类的构造方法。
7、 如果在子类的构造方法中,没有显示地写出super关键字来调用父类的某个构造方法,那么编译器默认地有:super();调用父类的无参数的构造方法(如果父类没有这样的构造方法,代码将出现编译错误)
8、在子类的构造方法中显示地写出super时,super关键字形成的语句必须是子类构造方法的第1条语句。
9、如果一个类中有abstract方法,这个类必须是abstract类。
10、代码无法通过编译。(原因是,父类People已经没有了不带参数的构造方法,而子类Student构造方法默认调用People类的不带参数的构造方法)。
11、子类重写父类的方法时,不允许降低方法的访问权限,但可以提高访问权限。
12、如果子类是abstract类,允许子类将父类的非abstract方法重写为abstract方法。
13、如果一个非抽象类是某个抽象类的子类,那么它必须重写父类的抽象方法,即给出方法体(将abstract方法重写为非abstract方法)。
14、abstract子类也要继承abstrat父类的abstract方法 。
15、类中的类方法(static方法)只能操作类变量(static变量),不可以操作实例变量。
16、编译器不提示程序使用了空对象(让一个空对象去调用实例方法),但程序在运行时会出现NullPointerException异常。
17、子类对象的上转型对象操作子类继承的方法或子类重写的实例方法,其作用等价于子类对象去调用这些方法。
18、super关键字形成的语句不一定是子类构造方法中的第1条语句。显示的写出才作为第一句。不写则无。
19、abstract类可以没有abstract方法。
20、abstract方法的abstract关键字,必须放在方法的类型的前面,不可以插在方法类型和方法名字之间。
21、子类重写或新增的方法也能直接操作被子类隐藏的成员变量。
22、如果子类可以继承父类的某个方法,那么子类就有权利重写这个方法。
23、类所声明的变量被称为对象,对象(变量)负责存放引用,以确保对象可以操作分配给该对象的变量以及调用类中的方法。分配给对象的变量被习惯地称做对象的实体。
24、写的话,super关键字形成的语句必须是子类构造方法中的第1条语句。
25、子类声明的成员的变量的名字和从父类继承来的成员变量的名字相同,子类就会隐藏掉所继承的成员变量。方法的修饰(如果有),例如public,abstract,必须放在方法的类型的前面,不可以插在方法类型和方法名字之间。
26、java.lang包中的Object类是所有其他类的祖先类。
类声明的成员的变量的名字和从父类继承来的成员变量的名字相同,子类就会隐藏掉所继承的成员变量。方法的修饰(如果有),例如public,abstract,必须放在方法的类型的前面,不可以插在方法类型和方法名字之间。
26、java.lang包中的Object类是所有其他类的祖先类。
参考
《Java2实用教程(第5版)》
基于《java2实用教程》的java知识点复习整理【 第五章——子类与继承】_农夫的码,没有草原-CSDN博客_java实用教材第五版知识点总结