继承入门
继承概述:让类于类之间产生关系(子父类关系),子类可以直接用父类中的非私有成员
继承的格式:
格式:public class 子类名extends 父类名{}
范例:public class extends Fu{}
Fu:是父类,也被称为基类,超类
Zi:是子类,也被称为派生类
范例:之前的复用性差,代码臃肿,cat和dog相同的代码向上抽取,交给动物类,然后让cat和dog区继承
之前的类:
public class cat {
public String run;
public String eat;
public cat() {
}
public cat(String run, String eat, String sleep) {
this.run = run;
this.eat = eat;
this.sleep = sleep;
}
public String getRun() {
return run;
}
public void setRun(String run) {
this.run = run;
}
public String getEat() {
return eat;
}
public void setEat(String eat) {
this.eat = eat;
}
public String getSleep() {
return sleep;
}
public void setSleep(String sleep) {
this.sleep = sleep;
}
public String sleep;
}
dog类:
public class dog {
public String run;
public String eat;
public dog() {
}
public dog(String run, String eat, String sleep) {
this.run = run;
this.eat = eat;
this.sleep = sleep;
}
public String getRun() {
return run;
}
public void setRun(String run) {
this.run = run;
}
public String getEat() {
return eat;
}
public void setEat(String eat) {
this.eat = eat;
}
public String getSleep() {
return sleep;
}
public void setSleep(String sleep) {
this.sleep = sleep;
}
public String sleep;
}
修改后:找一个公共的类进行接收 使用extends进行实现
public class animal {
private String run;
private String eat;
public animal() {
}
public animal(String run, String eat, String sleep) {
this.run = run;
this.eat = eat;
this.sleep = sleep;
}
public String getRun() {
return run;
}
public void setRun(String run) {
this.run = run;
}
public String getEat() {
return eat;
}
public void setEat(String eat) {
this.eat = eat;
}
public String getSleep() {
return sleep;
}
public void setSleep(String sleep) {
this.sleep = sleep;
}
private String sleep;
}
cat类和dog类就可以进行继承
public class cat extends animal {
}
public class dog extends animal {
}
继承的好处和弊端:
好处:提高了代码的复用性,提高了代码的维护性(一个父类修改之后,子类可以分享,不必每一个都需要去添加),让类于类之间产生了关系,是多态的前提
弊端:继承是侵入性和灵活性(导致子类必须拥有父类菲斯有的属性和方法,让子类的规则多了一些约束),增强了代码的耦合性(代码之间存在关系都可以将其称之为耦合,让后期的维护产生了很多麻烦)
什么时候使用继承?
当类于类之间,存在相同(共性的内容),,并且产生is a关系,就可以考虑使用继承,来优化代码
继承的特点:
JAVA只能支持单继承,不支持多继承,但支持多层继承
一个子类只能继承一个父类,不能继承多个父类,但父类可以继承别的类
例子:一个儿子有一个爸爸,但是爸爸又一个爷爷,儿子可以继承爸爸,也可以继承爷爷
A,B,C三个类,A继承B,B继承C,A可以打印出C和B的方法,但不能同时继承C,B
因为如果同时继承B,C,两个类中有相同的方法,java不知道使用哪一个,为了防止这种情况出现,就会使用单继承
继承的成员访问特点:
实例:
子类:
public class zi extends fu{
public void method(){
System.out.println(a);
}
}
父类:
public class fu {
int a =10;
}
测试类:
public class test {
public static void main(String[] args) {
zi Z=new zi();
Z.method();
}
}
输出a=10
如果子类中有a的变量呢?
子父类出现的重名呢 子类中的a=20;
以前的知识点 就近原则 由此可得a=20 如果想的到父类的10呢 需要使用关键super
子类代码可以这样写
public class zi extends fu{
int a=20;
public void method(){
int a=30
System.out.println(a);//就近原则a=30
System.out.println(this.a);//调用子类的a=20
System.out.println(super.a); //调用父类的a=10
}
}
在子类方法中访问一个变量
首先子类局部范围找
其次子类成员范围找
再是父类成员范围找
注意:如果子父类中,出现了重名的成员变量,通过就近原则,会优先使用子类的,
如果要使用父类的,可以通过super关键字,进行区分
super关键字的用法和this关键字的用法相似:
this:代表了本类对象的引用
super:代表了父类存储空间的标识(可以理解为父类对象引用)
继承中的成员方法总结:
实例:
子类:
public class zi extends fu{
}
父类:
public class fu {
public void show(){
System.out.print("父类show方法");
}
}
测试类:
public class test {
public static void main(String[] args) {
zi Z=new zi();
Z.show();
}
}
不会报错 控制台会显示父类show方法
能不能再子类中创建重名方法
子类:
public class zi extends fu{
public void show(){
System.out.print("子类show方法");
}
}
父类:
public class fu {
public void show(){
System.out.print("父类show方法");
}
}
测试类:
public class test {
public static void main(String[] args) {
zi Z=new zi();
Z.show();
}
}
不会报错,会显示子类show方法
如果再子类中写一个方法调用show方法会是那个呢
子类:
public class zi extends fu{
public void show(){
System.out.print("子类show方法");
}
public void method(){
show();
}
}
父类:
public class fu {
public void show(){
System.out.print("父类show方法");
}
}
测试类:
public class test {
public static void main(String[] args) {
zi Z=new zi();
Z.method();
}
}
不会报错,会显示子类show方法,系统会默认加入this关键字,如果想要父类的方法,就用super关键字
继承中成员方法访问特点
通过子类对象访问一个方法
子类成员范围找
父类成员范围找
如果找不到就会报错
方法重写:
概念:在继承体系中,子类出现了和父类完全一致的方法声明(方法名,参数列表,返回值类型)
回顾一下方法重载:
在同一个类中,方法名相同,参数列表不同,于返回无关
方法重写的使用场景:
当子类需要父类的功能,而功能主体子类有自己特定的内容,这样,即沿袭了父类的功能,又定义子类特有的内容
案例:
需求定义一个手机类1.0版本 可以打电话,语言 1.1版本打电话,语言(英文和中文)
zi
public class phnepro extends phone{
@Override
public void voice(){
super.voice();
System.out.println("speak english");
}
}
fu:
public class phone {
public void call(String name){
System.out.println("给"+name+"打电话");
}
public void voice(){
System.out.println("我会说中文");
}
}
测试类:
public class test {
public static void main(String[] args) {
phnepro phone=new phnepro();
phone.voice();
phone.call("彭于晏");
}
}
@Override//是一个注解 检查当前方法是否是一个正确的重写方法
方法重写注意事项:
父类中私有方法不能被重写
父类中静态方法,子类必须通过静态方法进行重写,父类非静态方法,子类也必须通过非静态方法进行重写
如果一个子类中,也存在一个方法声明一模一样的方法,可以理解为子类将父类中同名的方法进行了隐藏,并非是方法重写
子类重写父类方法时,访问权限必须大于等于父类
权限修饰符
private: 同一个类中
默认 什么都不写: 同一个类中,同一个包中子类无关类
protected: 同一个类中 同一个包中子类无关类,不同的子类
public: 同一个类中 同一个包中子类无关类,不同的子类 不同包的无关类
继承中构造方法的访问特点:
子类中所有的构造方法默认都会访问父类中无参的构造方法
因为子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据
所以子类在初始化之前,一定会完成父类的初始化
怎么初始化?
构造方法的第一条语句默认都是super();
注意:如果我们编写的类,没有手动指定父类,系统也会自动继承Object(Java继承体系中最顶层的父类)
父类中没有空参构造,只有有参构造会怎么办 (回顾:有了有参构造之后系统就不会提供无参构造的)
子类会出现一个错误,
解决方式1:子类通过super,手动调用父类的带参构造方法
解决方式2:子类通过this去调用本类的其他构造方法,本类其他构造方法在通过super去手动调用父类的带参构造方法
注意:this()super()必须放在构造方法的第一行有效语句,并且二者不能共存
抽象类概述(个人认为Java的第四大特征)
抽象方法:将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体明确,该方法就可以定义为抽象方法
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类
抽象方法格式:
public abstract 返回值类型 方法名(参数列表);
抽象类定义格式:
public abstract class 类名{}
举例:定义一个Cat和Dog
Cat类方法eat吃鱼 drink喝水
Dog类方法eat吃肉 drink喝水
动物类:
public abstract class animal {
public void drink(){
System.out.println("喝水");
}
public abstract void eat();
}
Cat类:
public class Cat extends animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
Dog类:
public class Dog extends animal{
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
测试类:
public class test {
public static void main(String[] args) {
Cat c=new Cat();
Dog d=new Dog();
c.drink();
d.drink();
c.eat();
d.eat();
}
}
抽象类注意事项:
抽象类不能被实例化,
抽象类中不一定有抽象方法,由抽象方法的一定是抽象类
可以有构造方法
抽象类的子类 要么重写抽象类中全部的抽象方法,要么是抽象类