继承的概述
面对对象有三大特征分别是:封装性、继承性、多态性
继承是多态的前提,如果没有继承就没有多态
继承主要解决的问题就是:共性抽取
这里的继承并不是父子关系而是师徒关系
师徒关系是师傅会多少就会教给徒弟多少,所以每个徒弟是一样的
特点:
1、子类可以拥有父类的内容
2、子类还可以拥有自己专有的内容
继承的格式
在继承的关系中,子类就是一个父类,也就是说子类可以被当作父类看待。
例如父类是员工,子类是讲师,那么讲师其实也可以是员工。
定义父类格式:
public class父类名称{
}
定义子类名称:
public class 子类名称 extends 父类名称{
}
通过下面代码来解释继承
首先定义一个父类
public class carryon {
public void method(){
System.out.println("方法执行");
}
}
然后定义一个子类
public class zilei extends carryon{
}
最后写一个主函数
public class show {
public static void main(String[] args) {
zilei zhanshi=new zilei();
zhanshi.method();
}
}
我们可以看到,父类中有执行成功的语句,子类中并没有,但是我们在主函数中写了继承的使用格式,在运行主函数时继承了父类,
运行结果如下图
这样就达到了代码复用的效果,省去了在相似类中重复写相同的代码的麻烦。
比如我定义一个员工类,一个助教类,一个班助类,这三个类都需要姓名和工号,那我用继承就只需要写一个姓名和工号的代码,其他两个类中代码可以为空,也可以加上子类特有的。
继承中成员变量的访问特点
首先看一段代码
定义父类
public class carryon {
int num=10;
}
定义子类
public class zilei extends carryon{
int num2=20;
int num=1333;
}
使用主函数调用一下
public class show {
public static void main(String[] args) {
carryon fu =new carryon();
zilei zi=new zilei();
System.out.println(fu.num);
System.out.println(zi.num);//子类可以拥有父类继承下的东西
System.out.println(zi.num2);
}
}
当父类和子类中变量重名时,
创建子类对象时访问有两种形式
1、直接通过子类对象访问成员变量
等号左边是谁就优先用谁,没有则向上找
2、间接通过成员方法访问成员变量
该方法属于谁就优先用谁,没有则向上找
父类
public class zilei extends carryon{
int num2=20;
int num=1333;
public void methodzi(){
System.out.println(num);//因为本类中有num优先使用本类中的
}
}
==================================
子类
public class carryon {
int num=10;
public void method (){
System.out.println(num);//使用的是本类当中的
}
}
==================================
主函数代码
public class show {
public static void main(String[] args) {
carryon fu =new carryon();
zilei zi=new zilei();
System.out.println(fu.num);
System.out.println(zi.num);
//子类可以拥有父类继承下的东西
System.out.println(zi.num2);
System.out.println("==========");
System.out.println(zi.num);
//等号左边是子类就优先用子类
System.out.println("==========");
zi.methodzi();//优先使用本类
}
}
运行结果
区分三种子类方法中的重名
局部变量: 直接写变量名
本类中的成员变量: this.成员变量名
父类中的成员变量: super.成员变量名
用代码来理解一下
父类
public class carryon {
int num=10;
}
====================
子类
public class zilei extends carryon{
int num=20;
public void method (){
int num=50;
System.out.println(num);//输出50,局部变量
System.out.println(this.num);//输出20,本类的成员变量
System.out.println(super.num);//输出10,父类中的成员变量
}
}
=====================
主方法
public class show {
public static void main(String[] args) {
zilei zi=new zilei();
zi.method();
}
}
继承中成员方法的访问特点
原则:创建的对象是谁就优先用谁,如果没有则向上找
用代码理解:
父类
public class carryon {
public void methodfu(){
System.out.println("父类方法执行");
}
public void method(){
System.out.println("父类重名方法执行");
}
}
===============================
子类
public class zilei extends carryon{
int num=20;
public void methodzi (){
System.out.println("子类方法执行");
}
public void method(){
System.out.println("子类重名方法执行");
}
}
================================
主方法
public class show {
public static void main(String[] args) {
zilei zi = new zilei();
zi.methodfu();//子类中没有,所以向上找
zi.methodzi();
//重名的时候呢?
zi.method();//创建的对象是谁就优先用谁,如果没有则向上找
}
}
方法重名时,创建的对象是谁就优先用谁,如果没有则向上找。
继承中方法的覆盖重写
重写(Override) :在继承关系中,方法名称一样,参数列表也一样
重载(Overload):方法名称一样,参数列表不一样
方法的覆盖重写特点:创建的是子类对象优先用子类方法
方法的覆盖重写的注意事项:
1、必须保证父子类之间方法的名称相同,参数列表也相同
@override:写在方法前面,用来检测是不是有效重写,如果不是有效重写就会报错。这个注解即使不写,只要满足要求也是有效重写。
2、子类方法的返回值必须小于等于父类方法的返回值范围
java.lang.Object类是所有类的公共最高父类,java.lang.String就是Object的子类
3、子类方法的权限必须大于等于父类方法的权限修饰符
权限修饰符:比如public >protected > >(default)>private
default不是关键字,而是什么都不写留空
父类
public class fu {
public Object method(){
return null;
}
}
子类
public class zi extends fu {
@Override
public Object method(){
return null;
}
}
主方法
public class override {
}
什么时候应该覆盖重写呢?
拿一张图给大家理解
这里的案例中,比如我们需要添加新的显示姓名和显示头像的功能,
那么直接使用重写就可以省去很多的繁琐。
代码演示如下
旧款手机
public class phone {
public void call(){
System.out.println("打电话");
}
public void send(){
System.out.println("发短信");
}
public void show(){
System.out.println("显示号码");
}
}
=================================
新款手机
public class newphome extends phone{
@Override
public void show(){
super.show();//父方法拿来使用
System.out.println("显示头像");
System.out.println("显示姓名");
}
}
=================================
public class text {
public static void main(String[] args) {
phone ph = new phone();
ph.call();
ph.send();
ph.show();
System.out.println("===========");
newphome ph2 = new newphome();
ph2.call();
ph2.send();
ph2.show();
}
}
运行结果
继承中构造方法的访问特点
继承关系中父子类构造方法的访问特点
先访问父类构造方法,再访问子类构造方法,先有父后有子
1、子类构造方法中默认有一个隐含的super()调用,什么都不写则默认赠送这个
代码演示
父类
public class demo10fu {
public demo10fu(){
System.out.println("父类方法!");
}
}
===========================================
子类
public class demo08 extends demo10fu{
public demo08(){
//super();默认赠送无参数父类构造,如果父类有参数则不再赠送
System.out.println("子类方法!");
}
}
============================================
主方法
public class demo09 {
public static void main(String[] args) {
demo08 zilei=new demo08();
}
}
运行结果
先执行父类方法再执行子类方法,因为构造方法是无参数的,会默认赠送一个无参数的super()
那么有参数的构造方法呢?
2、可以通过super关键字来子类构造父类重载构造
也是看个代码
父类
public class demo10fu {
public demo10fu(int num){
System.out.println("父类方法!");
}
}
===========================================
子类
public class demo08 extends demo10fu{
public demo08(){
//super();默认赠送无参数父类构造,如果父类有参数则不再赠送
super(10);
System.out.println("子类方法!");
}
}
===========================================
主方法
public class demo09 {
public static void main(String[] args) {
demo08 zilei=new demo08();
}
}
super的父类构造调用,必须是子类构造方法的第一个语句
两个就会报错
super关键字用来访问父类内容,this关键字用来访问子类内容
Java继承的三个特点
Java语言是单继承的
一个类的直接父类只能有唯一一个
class A{}
class B extends A{}//正确
class C{}
class D extends A,C{}//错误
原理
Java语言可以多级继承
class A{}
classB extends A{} //正确
class C extends B{} //正确