java继承

为什么需要继承?

下面这个例子中猫和狗有相同的name属性,但我们需要实现两个差不多的类,为了解决这个问题,我们可以使用继承。

class Cat{
    public  String name;
    public void eat(){
        System.out.println(name+"猫吃饭");
    }
}
class Dog{
    public  String name;
    public void eat(){
        System.out.println(name+"狗吃饭");
    }
}
public class 继承 {
    public static void main(String[] args) {
        Cat cat=new Cat();
        Dog dog=new Dog();
        cat.name="mi";
        dog.name="i";
        cat.eat();
            dog.eat();
    }
}

 继承中,我们就可以把共同属性取出来。

class A{
    public  String name;
    public void eat(){
        System.out.println(name+"正在吃饭");
    }
}
class Cat extends A{
    
}
class Dog extends A{
    
}
public class 继承 {
    public static void main(String[] args) {
        Cat cat=new Cat();
        Dog dog=new Dog();
        cat.name="mi";
        dog.name="i";
        cat.eat();
            dog.eat();
    }
}

继承最大的意义是可以对代码进行复用。

我们把Dog和Cat叫子类或者派生类,把A叫父类或者基类/超类。

子类和父类是is-a的关系。

extends是 继承关键字。

继承时修饰符可以不写。

new创建对象时,堆中也会有父类中的成员。

注意:

1. 子类会将父类中的成员变量或者成员方法继承到子类中了
2. 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了
3.只能继承一个类,不能多继承。
继承可以传递,就是可以有另一个类继承Dog,其中这个Dog是继承类A的。
  • 父类成员的访问 

子类访问父类成员变量。

1.子类不存在父类同名变量

class A{
    public  int a;
    }
class Sys extends A{
public int c;
public void sys(){
    System.out.println(a);
}
}

public class 继承 {
    public static void main(String[] args) {
        Sys cat=new Sys();
        cat.sys();
    }
}

 2.子类存在父类同名变量

 如果父类和子类有同名成员变量,那么优先访问子类自己的。

但是Sys创建的对象中含有父类和子类的b。

在子类方法中 或者 通过子类对象访问成员时
如果访问的成员变量子类中有,优先访问自己的成员变量。
如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
如果访问的成员变量与父类中成员变量同名,则优先访问自己的。
同名时使用super可以强制访问父类的成员。

 super暂且理解为父类的引用。正确的理解是只是一个关键字。因为写时没有实例化父类对象。

那如果子类和父类方法重名呢?

class A{
    public  int a;
    public int b=1;
    public void test1(){
        System.out.println("父类");
    }
}
class Sys extends A{
public int c;
public int b=2;
public void test1(){
    System.out.println("子类");
}
public void sys(){
   test1();
}
}

public class 继承 {
    public static void main(String[] args) {
        Sys cat=new Sys();
        cat.sys();
    }
}

依然 是就近原则。

 强制使用父类也可以用super。

 如果重名,一个有参数一个没参数(构成重载),那么传参的调用有参数的,没传参的调用没参数的。

If two methods of a class (whether both declared in the same class, or both inherited by a class, or one declared and one inherited) have the same name but signatures that are not override-equivalent, then the method name is said to be overloaded.

如果一个类的两个方法(无论是在同一个类中声明的,还是由一个类继承的,或者一个声明的和一个继承的)具有相同的名称,但签名不是重写等效的,那么方法名称被称为重载。

所以重载不一定在一个类中,继承下来的名字相同的也可以是重载。

通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到 则访问,否则编译报错。
通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同 ( 重载 ) ,根据调用 方法适传递的参数选择合适的方法访问,如果没有则报错;

 super注意事项:

1. 只能在非静态方法中使用
2. 在子类方法中,访问父类的成员变量和方法
静态方法中使用就会报错,因为static不依赖对象,而super是和对象有关系的。
this和super都不能在静态方法中使用。
super不能访问"爷爷"类。

  •  子类的构造方法

下面图中,添加完父类构造函数后,子类发生了报错

因为 在继承关系上,一定先帮助父类进行构造。那么帮助父类构造只有一种路径,那就是在子类调用父类构造方法,子类构造完之前,父类需要构造完。

这样改就会了。

构造子类结束前,通过super显示调用父类构造方法,帮助父类成员进行初始化。

帮助父类构造一定要调用父类构造方法,下面这样赋值是不行的。

 当然,建议下面这样写子类构造函数。这样使用时,构造会更加灵活。

 先构造子类,后调用父类构造函数也不对。

 super在子类调用父类构造方法时一定要放第一层。

super和this在调用构造方法时不能同时出现,因为this里面也要super调用。

 下面例子中我们发现父类中构造函数注释后,子类super调用构造函数不报错,而把父类构造函数写上,子类super调用构造函数就报错了。

因为写上构造函数,父类就不自动生成默认构造方法了。

 当我们写上一个构造函数后,就不报错了。

 当父类和子类没有显示写任何构造方法时,父类会默认生成

Public A(){

}

子类会默认生成

Public B(){

super();

}

构造函数。

  • super和this 
相同点
1. 都是 Java 中的关键字
2. 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
3. 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
不同点
1. this 是当前对象的引用,当前对象即调用实例方法的对象, super 相当于是子类对象中从父类继承下来部分成
员的引用
2. 在非静态成员方法中, this 用来访问本类的方法和属性, super 用来访问父类继承下来的方法和属性
3. 在构造方法中: this(...) 用于调用本类构造方法, super(...) 用于调用父类构造方法,两种调用不能同时在构造
方法中出现
4. 构造方法中一定会存在 super(...) 的调用,用户没有写编译器也会增加,但是 this(...) 用户不写则没有
super是继承下来的部分的引用。this则包含继承下来的和子类原有的属性。


  • 再谈初始化 

 上图中程序,父类优先与子类执行,静态代码块最先执行,静态代码块只执行一次。

对象创建时执行实例代码块。实例代码块执行后,执行构造方法。

private修饰的成员变量或者成员方法只能在当前类中使用,类外不能使用,继承后子类不能调用,

如果什么都不写,那么是包访问权限,指的是只能在当前包中使用。

public修饰意味在哪里都能访问。

这叫一个包。

 下面这个例子是同一个包中的同一个类。

package demo2;

public class test1{
    protected int a;
    public static void main(String[] args) {
        test1 ji=new test1();
        ji.a=1;
        System.out.println(ji.a);
    }
}

 

 我们发现,test2中没有定义a,但能调用test1中的a。

而下面展示的就是不同包的子类,其中a是test1中被protected修饰的成员变量。

而从上面表格中我们看到,被protected修饰的成员变量在不同包的子类中可以被访问,

这里是因为不能通过引用去访问,而想要super去访问。

 下面这样使用就可以了。

package demo;

import demo2.test1;

public class test3 extends test1 {
    public void superp(){
        super.a=1;
        System.out.println(super.a);
    }

    public static void main(String[] args) {
        test1 ji=new test1();
//        super.a=1;
    }
}

然后我们可以通过定义test3对象,来调用superp,不能直接调用superp(),因为需要静态修饰。

注意静态方法中不能使用super

 注意上述例子有一个基本点是test1必须是public修饰的。

那么继承中被 private修饰的成员是否被继承了呢?

答案是被继承了,但是不能访问。

权限大小:private<默认<protected<public 

注意:继承深度最好不要太深。

一个类加上final后,就不能被继承了。此时test1叫密封类。

 被final修饰的变量是个常量。常量一般大写。

成员变量被final修饰一定要赋初值。

 下面例子中第一个是错的,被final修饰的a意味着a的值不能改变,而a存的是对象的地址。

而a[0]是改变这个地址的值,所以可以改变。

  •  组合

 组合是代码的一种实现方式。是一种设计思想。

a part of 或者has a的关系设计为组合。

class Teacher{}

class Student {
    
}
class School{
    public Teacher[] teacher=new Teacher[3];
    public Student[] student=new Student[3];

}
public class 继承 {

    public static void main(String[] args) {
        School school=new School();

    }
}

Teacher和Student的对象不在School对象中,他们是单独的。

School只存了teacher和student这两个引用。

下图中,上面是定义引用了数组,里面存对象地址,没定义对象,而下面才是定义变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南种北李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值