第五章 子类与继承
换个方法,先把书上后面的小节内容提出来
1.继承是一种由已有的类创建新类的机制。利用继承,我们可以先创建一个共有属性的一般类,根据该类再创建具有特殊属性的新类。
2.所谓子类继承父类的成员变量作为自己的一个成员变量,就好像它们是在子类中直接声明一样,可以被子类中自己声明的任何实例方法操作。
3.所谓子类继承父类的方法作为子类中的一个方法,就好像它们是在子类中直接声明一样,可以被子类中自己声明的任何实例方法调用。
4.子类继承的方法只能操作子类继承和隐藏的成员变量。
5.子类重写或新增的方法能操作子类继承和新声明的成员变量,但不能直接操作隐藏的成员变量(需使用关键字super操作隐藏的成员变量)
6.多态是面向对象编程的又一重要特性。子类可以体现多态,即子类可以根据各自的需要重写父类的某个方法,子类通过方法的重写可以把父类的状态和行为改变为自身的状态和行为。
7.在使用多态设计程序时,要熟练使用上转型对象以及面向抽象编程的思想,以便体现程序设计所提倡的“开-闭原则”。
1.子类与父类
利用继承,可以先编写一个共有属性的一般类,根据该一般类再编写具有特殊属性的新类,新类继承一般类的状态和行为,并根据需要增加它自己的新的状态和行为。由继承而得到的类称为子类,被继承的类称为父类(超类)。
- 声明子类
使用关键字extends来定义一个类的子类,格式如下:
class 子类名 extends 父类名 {
…
}
例如:
class Student extends People {
…
}
把Student类定义为People类的子类、People类是Student类的父类 - 类的树形结构
Java的类按继承关系形成树形结构这个树形结构中,根节点是Object类(Object是java.lang包中的类),即Object是所有类的祖先类。除了Object类每个类有且仅有一个父类,一个类可以有多个或零个子类。如果一个类(除了Object类)的声明中没有使用extends关键字,这个类被系统默认为是Object的子类,即类声明“class A”与“class A extends Object”是等同的。
2.子类的继承性
-
子类和父类在同一包中的继承性
如果子类和父类在同一个包中,那么,子类自然地继承了其父类中不是private的成员变量作为自己的成员变量,并且也自然地继承了父类中不是private的方法作为自己的方法,继承的成员变量或方法的访问权限保持不变。 -
子类和父类不在同一个包中的继承性
如果子类和父类不在同一个包中,那么,子类继承了父类的protected、public成员变量做为子类的成员变量,并且继承了父类的protected、public方法为子类的方法,继承的成员或方法的访问权限保持不变。
3.子类与对象
(1) 子类的构造方法创建一个子类的对象时,不仅子类中声明的成员变量被分配了内存,而且父类的成员变量也都分配了内存空间,但只将子类继承的那部分成员变量作为分配给子类对象的变量 。
子类中有一部分方法是从父类继承的,这部分方法可以操作子类未继承的变量 。
(2)instanceof运算符
instanceof运算符是Java独有的双目运算符,其左面的操作元是对象,右面的操作元是类,当左面的操作元是右面的类或其子类所创建的对象时,instanceof运算的结果是true,否则是false
4.方法的重写
子类通过重写可以隐藏已继承的实例方法 。
- 规则:
如果子类可以继承父类的某个实例方法,那么子类就有权利重写这个方法。- 目的:
子类通过方法的重写可以隐藏继承的方法,子类通过方法的重写可以把父类的状态和行为改变为自身的状态和行为。
***方法重写是指: 子类中定义一个方法,这个方法的类型和父类的方法的类型一致或者是父类的方法的类型的子类型,并且这个方法的名字、参数个数、参数的类型和父类的方法完全相同。- 重写父类的方法时,不允许降低方法的访问权限,但可以提高访问权限(访问限制修饰符按访问权限从高到低的排列顺序是:public、protected、友好的、private。)
举个例子
package com.zy.University;
public class University { //父类
void enterRule(double math,double english,double chinese) {
double total=math+english+chinese;
if(total>180)
System.out.println("考分"+total+"达到大学最低录取线");
else
System.out.println("考分"+total+"未达到大学录取分数线");
}
}
package com.zy.University;
public class ImportantUniversity extends University{ //子类
void enterRul(double math,double english,double chinese) {
double total=math+english+chinese;
if(total>220)
System.out.println("考分"+total+"达到重点大学录取分数线");
else
System.out.println("考分"+total+"未达到录取分数线");
}
}
package com.zy.University;
public class Example5_4 {
public static void main(String[] args) {
double math=64,english=76.5,chinese=66;
ImportantUniversity univer=new ImportantUniversity();
univer.enterRule(math, english, chinese);//调用重写的方法
math=89;
english=80;
chinese=86;
univer =new ImportantUniversity();
univer.enterRule(math, english, chinese);//调用重写的方法
}
}
5.super关键字
- 子类可以隐藏从父类继承的成员变量和方法,如果在子类中想使用被子类隐藏的成员变量或方法就可以使用关键字super。
- this和super的区别
this代表本类对应的应用
super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员。
调用成员变量
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量
调用构造方法
this(…) 调用本类的构造方法
super(…)调用父类的构造方法
super和this的细分可以看一下这个
?点我
class Student{
int number;String name;
Student() {
}
Student(int number,String name) {
this.number=number;
this.name=name;
System.out.println("我的名字是:"+name+ "学号是:"+number);
}
}
class UniverStudent extends Student {
boolean 婚否;
UniverStudent(int number,String name,boolean b) {
super(number,name);
婚否=b;
System.out.println("婚否="+婚否);
}
}
public class Example5_8 {
public static void main(String args[]) {
UniverStudent zhang=new UniverStudent(9901,"张三",false);
}
}
6.final关键字
final关键字可以修饰类、成员变量和方法中的局部变量。
- final类
可以使用final将类声明为final类。final类不能被继承,即不能有子类。如:
final class A {
… …
} - final方法
如果用final修饰父类中的一个方法,那么这个方法不允许子类重写。 - 常量
如果成员变量或局部变量被修饰为final的,就是常量 - final修饰变量的初始化时机
1.被final修饰的变量只能赋值一次!
2.在构造方法完毕前。(非静态的常量)
7.对象的上转型对象
我看了好久的书和视频,个人觉得很抽象。下面都是官方解释定义,菜鸟级的我也不能很好的解释,小可爱们找别的文章看看吧,或者看视频,我师父?说的,入门级选手,视频为主,书为辅
假设,A类是B类的父类,当用子类创建一个对象,并把这个对象的引用放到父类的对象中时,比如:
A a;
a=new B();
或
A a;
B b=new B();
a=b;
这时,称对象a是对象b的上转型对象。
注意
1.上转型对象不能操作子类新增的成员变量;不能调用子类新增的方法。
2.上转型对象可以访问子类继承或隐藏的成员变量,也可以调用子类继承的方法或子类重写的实例方法。上转型对象操作子类继承的方法或子类重写的实例方法,其作用等价于子类对象去调用这些方法。因此,如果子类重写了父类的某个实例方法后,当对象的上转型对象调用这个实例方法时一定是调用了子类重写的实例方法。
3.如果子类重写了父类的静态方法,那么子类对象上转型对象不能调用子类重写的静态方法,只能调用父类的静态方法。
4. ?说的经典图
//父类
class 类人猿 {
int tag=5;
void crySpeak(String s) {
System.out.println(s);
}
}
//子类
class People extends 类人猿 {
int tag=6;
int x=5;
//子类新的方法
void computer(int a,int b) {
int c=a*b;
System.out.println(c);
}
// 方法重写
void crySpeak(String s) {
System.out.println("***"+s+"***");
}
}
public class Example5_10 {
public static void main(String args[]) {
类人猿 monkey=new People(); //monkey是People对象的上转型对象
// 可以调用子类重写的
monkey.crySpeak("I love this game");
// 调不了子类新增的方法
// monkey.computer(5,6);
System.out.println("tag"+monkey.tag);
People people = new People();
//普通的子类对象 啥都可以调
System.out.println("子类对象"+people.tag);
people.crySpeak("子类对象"+"shujuku");
people.computer(9, 1);
// People people=(People)monkey; //把上转型对象强制转化为子类的对象
// people.computer(10,10);//computer是子类新增的方法
}
}
8.继承与多态
多态性就是指父类的某个方法被其子类重写时,可以各自产生自己的功能行为
class 动物 {
void cry() {
}
}
class 狗 extends 动物 {
void cry() {
System.out.println("汪汪.....");
}
}
class 猫 extends 动物 {
void cry() {
System.out.println("喵喵.....");
}
}
public class Example5_11 {
public static void main(String args[]) {
动物 animal;
animal = new 狗();
animal.cry();
animal=new 猫();
animal.cry();
}
}
运行结果
汪汪…
喵喵…
9.abstract类和abstract方法
用关键字abstract修饰的类称为abstract类(抽象类)。如:
abstract class A {
… …
}
用关键字abstract修饰的方法称为abstract方法(抽象方法),例如:
abstract int min(int x,int y);
注意:
1.abstract类中可以有abstract方法
2.abstract类不能用new运算创建对象
abstract class A{
abstract int add(int x,int y);
int sub(int x,int y) {
return x-y;
}
}
class B extends A{
int add(int x,int y){ //子类必须重写父类的方法
return x+y;
}
}
public class Example5_12 {
public static void main(String[] args) {
B b=new B();
int sum=b.add(30, 20);//调用子类重写的add方法
int sub=b.sub(30, 20);//调用子类继承的sub方法
System.out.println("sum="+sum);
System.out.println("sum="+sub);
A a; //抽象类声明对象
a = b; //a是b的上转型对象
sum=a.add(30,20); //调用子类重写的方法
sub=a.sub(30,20); //调用子类继承的方法34
System.out.println("sum="+sum);
System.out.println("sum="+sub);
}
}
10.面向抽象编程
在设计一个程序时,可以通过在abstract类中声明若干个abstract方法,表明这些方法在整个系统设计中的重要性,方法体的内容细节由它的非abstract子类去完成。
所谓面向抽象编程,是指当设计某种重要的类时,不让该类面向具体的类,而是面向抽象类,即所设计类中的重要数据是抽象类声明的对象,而不是具体类声明的对象。
面向抽象编程的目的:
为了应对用户需求的变化,将某个类中经常因需求变化而需要修改动的代码从该类中分离出去。面向抽象编程的核心是让类中每种可能的变化对应地交给抽象类的一个子类去负责,从而让类的设计者不去关心具体实现,避免所设计的类依赖于具体的实现,面向抽象编程使设计的类更容易应对用户需求的变化。(简单的说是方便程序员??,也方便用户了??)
11.开-闭原则
所谓“开-闭原则”(Open-Closed Principle)就是让设计的系统应当对扩展开放,对修改关闭。
在设计系统时,应当首先考虑到用户需求的变化,将应对用户变化的部分设计为对扩展开放,而设计的核心部分是经过精心考虑之后确定下来的基本结构,这部分应当是对修改关闭的,即不能因为用户的需求变化而再发生变化,因为这部分不是用来应对需求变化的。
如果系统的设计遵守了“开-闭原则”,那么这个系统一定是易维护的,因为在系统中增加新的模块时,不必去修改系统中的核心模块。