1. 什么是继承?
继承?因为我们在定义多个类的过程中,发现不同类中有着相同的成员属性和成员方法,将公共的成员变量/方法进行抽取,放到一个单独的类中,然后通过类似语法:public class B extends A{} ,说明类B继承于A,此时,B可以叫子类、派生类,而A类可以叫父类、派生类、基类。
例如:
//Teacher类 继承自 UnitTeacher类
public class Teacher extends UnitTeacher{
public void teach(){
System.out.println("讲课");
}
}
//Test测试
Teacher teach1 = new Teacher();
teach1.speak();
//继承后子类的实例可以访问父类的成员属性和成员方法
补充:此时观察反编译文件中看不到子类中被添加了父类的成员属性和方法,因为反编译文件只能看见省略/补充的内容,而子类的继承是通过虚拟机JVM实现的,所以反编译class文件中没有父类的成员属性和方法。
2. 访问修饰符
访问修饰符 | 限制类中的成员(成员变量、成员方法、构造器)能够被访问的范围 |
---|---|
private | 本类 |
缺省 | 本包 |
protected | 本包+其他包的继承子类 |
public | 任意位置 |
- 对于一个具体的类而言,我们通常使用public 和 缺省 。
- 对于成员变量和成员方法,我们通过四种选择,对访问范围做出规定。
解释说明:(以成员变量为例)
-
对于private而言,自然是只有本类使用,同一个包中的类都需要进行get/set方法才能对其进行访问。
-
对于public类而言,任何位置都可以进行访问,我们很多工具类都是在任何类中都可以进行访问。
-
对于protected,本包可以访问,以及其他包的继承子类,以下为不同包的举例:
//以接下来为例,讲述protected //背景介绍:Test类与Teacher类不同包 //Teacher其还有父类Person,期内有private包裹的的成员变量age,name,且有对于的get/set方法 //Teacher类共有两个成员变量,分别为salary和starScore double salary; protected double starScore; //Test类中 package com.itheima.study; //导入包 import com.itheima.rehearse.Teacher; public class Test { public static void main(String[] args) { Teacher teach1 = new Teacher(); teach1. //此时实例化的对象teach1只能得到其父类的get/set对age和name进行访问 //salary因为其是缺省修饰,只能在本包中访问,而protected想要访问,如果跨包,需要得到Teacher的子类,所以:先把Test继承到Teacher,接着就可以通过实例化实现访问starScore // Test ts = new Test(); // ts.starScore = 9.9; }//psvm }
上述案例总结:
-
对于 private修饰的age/name而言,如果是private类,是只能本类,所以通过的是 public void setName(String name) {this.name = name;}方法,访问的关键在于public
-
对于salary因为其是缺省修饰,只能在本包中访问,所以不能访问
-
对于protected修饰的starScore,如果是本包,缺省即可,但是这里说的是在其他包中建立Teacher继承+实例化,也就是上面的把Test继承到Teacher,且实例化Test。
模块依赖:对于不同模块之间的类想要使用,需要点击模块>Open Module Settings>Dependencies>点击+>选择Module Dependency>选择其他模块
说明:
对于跨模块,我们可以简单的理解为就是模块之间混在一起,也就是说,整体的情况非常像同模块,不同包的情况,private无法直接访问,通过get/set,缺省因为同包也不能用,protected可以通过继承+实例化使用。
3. java继承的特点
-
java是单继承(子继承父,父无法继承子),但是可以多层继承
-
如果不写继承,就是继承于Object类(祖宗类)
-
就近原则:先访问自己类中,如果没有,才会去父类中寻找
【在子类中,如果对于局部变量,子类成员变量,父类成员变量,如果出现重名情况,分别使用 变量名,this.变量名,super.变量名,对它们进行访问】
如果需要在子类中直接使用父类的同名变量,可以使用super.XXX 直接访问父类的成员变量
子类的构造方法中,可以通过super(参数列表);调用父类的构造器,必须写在第一行
正如我们之前的构造器方法重载一样,通过this(参数列表),调用其他构造器,且必须写在第一行
4. 方法重写
定义:当子类觉得父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法。
-
对于重写的方法要求:
- 方法名称相同,参数列表相同
- 返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。
- 对于返回值是基本数据类型来说,返回值的数据类型必须与父类一致。
- 对于返回值是类来说,子类重写方法返回的类可以与父类返回值类相同或为其子类。
- 对于访问修饰符/访问权限而言,子类的访问修饰符范围不小于父类的访问修饰符(public > protected > 缺省)
- 私有方法、静态方法不能被重写
-
使用@Override 提示下面的方法是重写方法,会自动校验父类是否有同名的方法,帮助我们校验书写格式是否正确。
//注意O需要大写 @Override public void speak(){ System.out.println("老师正在大声说话——重写父类方法"); }
override 重写方法快捷方式:ctrl + O
鼠标右键>generate>override Methods>可以选择父类的实例方法进行快速重写,也会帮添加@Override。
重写方法内就会出现super.方法名();这就是在执行父类的实例方法,删除自己写新的就可以了。
5. 子类构造器特点
特点:
- 子类构造器执行前,会先调用父类的构造方法,等价于给子类构造器第一行加了super();。
- 提示:如果父类的只剩下有参数构造器,子类在默认调用父类无参构造器时就会出错,这时要么子类通过手动调用父类有参构造:super(参数列表);要么给父类补回无参构造方法。
6. 多态
多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态。
- 对象多态:使用子类的实例赋给父类
- 行为多态:当父类调用父类的方法时,由于是将子类的实例交给父类,调用的也就是子类中重写后的方法。
6.1 多态形成需要的条件
- 有继承/实现关系;
- 存在方法重写
- 存在父类引用子类对象;
6.2 多态存在的问题:
多态后,父类没有办法使用子类独有的方法/属性,只能使用子类中重写的方法,如果非要调用子类的方法,可以使用(强制转) 转回子类。
补充概念:向下转型,多态中的强制类型转换,父类类型的引用强制转换为子类类型。
如果我们不确定是否能够强制类型转换 ?
答:可以使用 对象/实例 instanceof 类 检测是否能够转换类型
- 多态案例:把 多态的父类 当作参数输入:
//前情提要:Teacher类和Cosultant类都是UnitTeacher的子类,且通过重写,两个子类中也有了自己的speak方法
//举例:
public class Test {
public static void main(String[] args) {
UnitTeacher Uteach = new UnitTeacher();
//相同的outSpeack方法,放置的数据类型都是UnitTeacher,结果却是子类的重写方法
outSpeack(new Teacher());
outSpeack(new Cosultant());
}//psvm
public static void outSpeack(UnitTeacher Uteach) {
Uteach.speak();
}
}//Test类