介绍继承,抽象类,接口和泛型

  • Post author:
  • Post category:其他


本文章将主要介绍继承,抽象类,接口和泛型

然而纸上学来终觉浅,最好还是能自己敲敲代码实现一下。



继承

用于解决代码复用

继承示意图:

请添加图片描述

class Dog extneds Animal{
    
}

①子类继承了父类所有属性和方法,但是私有属性和方法不能在子类中直接访问——public可以,protected可以,private不行。

要通过公共的方法去访问——写一个方法”get”

②子类必须调用父类的构造器,完成父类的初始化(默认调用父类的构造器,写不写都会调用)

③当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用

父类



无参构造器

如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过

//如下,super后输入参数
super("tom",30);

④如果希望指定地去调用父类的某个构造器,则显示地去调用一下(什么都不写默认调用无参构造器)

⑤super只能放在构造器中使用,而且要放在第一行

⑥因为this也只能放构造器第一行,因此super,this不能共存。(this是用自己子类里的的构造器)

⑦java所有类都是Object类的子类,Object是所有类的基类

⑧父类构造器的调用

不限于直接父类

,将一直向上追溯直至Object类(顶级父类)。

⑨子类最多只能直接继承一个父类

⑩不能滥用继承,父类子类必须满足 is – a 逻辑关系



继承的本质分析

(1)首先看子类是否有该属性

(2)如果子类有这个属性,若可以访问,则返回;

若不能访问,则报错

(3)如果没有这个属性,就看父类有没有这个属性(若有且可以访问,则返回;

若有但是不能访问,则报错

(4)如果父类没有,则按照(3)的规则,继续找上级父类,直到Object

下图为继承的内存布局:

请添加图片描述



抽象类

在这里插入图片描述

当父类的某些方法,需要声明,但又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类

子类可以重写父类方法,如果没有抽象类,也行(子类再去重写),但是浪费空间,且没必要

public abstract void eat();

且当一个类中存在抽象方法时,需要将该类声明为abstract类

①抽象类不能被实例化

②抽象类不一定要有抽象方法

③一旦有抽象方法,必须声明为抽象类

④abstract只能修饰类和方法,不能修饰其他部分

⑤抽象类还是类

⑥抽象方法不能有主体

⑦如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类

⑧抽象方法不能用private , final 和 static来修饰,因为这些和重写相冲突



接口



接口基本介绍

下示为接口,在接口中,抽象方法可以省略abstract关键字

public interface UsbInterface{
    //规定接口相关方法,即规范
    public void start();
    public void stop();
    
    //jdk8及以后,可以有方法体:
    //1.默认实现方法
    default public void ok(){
        
    }
    // 2.静态方法
    public static void ko(){
        
    }
}

想要用这个接口,就去实现它,这是手机

public class Phone implements UsbInterface{//实现接口
    public void start(){
        System.out.println("手机开始工作...");
    }
     public void stop(){
        System.out.println("手机停止工作...");
    }
}

这是相机

public class Camera implements UsbInterface{//实现接口
    public void start(){
        System.out.println("相机开始工作...");
    }
     public void stop(){
        System.out.println("相机停止工作...");
    }
}

电脑类用接口接手机或者相机即可

public class Computer{
    //编写一个方法,计算机工作
    public void work(UsbInterface usbInterface){
        usbInterface.start();
        usbInterface.stop();
    }
}

主函数实现时

public class Interface01{
    public static void main(String[] args){
        Camera camera = new Camera();
        Phone phone = new Phone();
        
        Computer computer = new Computer();
        
        computer.work(phone);
        computer.work(camera);
    }
}


接口细节

①接口不能实例化

②接口中所有方法都是public方法,接口中的抽象方法可以不用abstract修饰

③一个普通的类实现接口,就必须把该接口的所有方法都实现

④抽象类实现接口,可以不用实现接口的方法

⑤一个类可以同时实现多个接口(逗号 ’ , ’ 连接即可)

⑥接口中的属性,必须是final的,而且是public static final

//如
int a =1;
//实际上为
public static final int a =1;

⑦接口中属性的访问形式是:接口名.属性名

⑧一个接口不能继承其他的类,但是可以继承多个别的接口

⑨接口的修饰符只能是public和默认,这点和类修饰符是一样的



接口vs继承

当子类继承了父类,就自动拥有了父类的功能

如果子类需要拓展功能,可以通过实现接口的方式进行拓展

可以认为,实现接口 是对java 单继承 机制的补充

➢接口和继承解决的问题不同

继承的价值主要在于:解决代码的

复用性和可维护性

接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这些方法。

➢接口比继承更加灵活

接口比继承更加灵活,继承是满足is – a的关系,

而接口只需满足like – a的关系。

➢ 接口在一定程度上实现代码解耦 [即:接口规范性 + 动态绑定]



接口的多态特性

①接口类型的变量,可以指向实现了此接口类的对象实例

public class InterfacePloyParameter{
    public static void main (String[] args){
        //if01是接口类型的变量 可以指向实现了IF接口的对象实例
        IF if01 =new Monster();
        if01 = new Car();
    }
}
interface IF{}
class Monster implements IF{}
class Car implements IF{}

②多态数组(这太细节了,我都不想写)

public class InterfacePolyArr {
    public static void main(String[] args) {

        //多态数组 -> 接口类型数组
        Usb[] usbs = new Usb[2];
        usbs[0] = new Phone_();
        usbs[1] = new Camera_();
        /*
        给Usb数组中,存放 Phone  和  相机对象,Phone类还有一个特有的方法call(),
        请遍历Usb数组,如果是Phone对象,除了调用Usb 接口定义的方法外,
        还需要调用Phone 特有方法 call
         */
        for(int i = 0; i < usbs.length; i++) {
            usbs[i].work();//动态绑定..
            //和前面一样,我们仍然需要进行类型的向下转型
            if(usbs[i] instanceof Phone_) {//判断他的运行类型是 Phone_
                ((Phone_) usbs[i]).call();
            }
        }

    }
}

interface Usb{
    void work();
}
class Phone_ implements Usb {
    public void call() {
        System.out.println("手机可以打电话...");
    }
    public void work() {
        System.out.println("手机工作中...");
    }
}
class Camera_ implements Usb {
    public void work() {
        System.out.println("相机工作中...");
    }
}

③接口存在多态传递现象

public class InterfacePolyPass {
    public static void main(String[] args) {
        //接口类型的变量可以指向,实现了该接口的类的对象实例
        IG ig = new Teacher();
        //如果IG 继承了 IH 接口,而Teacher 类实现了 IG接口
        //那么,实际上就相当于 Teacher 类也实现了 IH接口.
        //这就是所谓的 接口多态传递现象.
        IH ih = new Teacher();
    }
}

interface IH {
    void hi();
}
interface IG extends IH{ }
class Teacher implements IG {
    public void hi() {
    }
}



泛型

泛型含有的知识点如下:

在这里插入图片描述

//如
ArrayList<E>
//中的<E>,就代表要指定一个类型给他
ArrayList<Dog> arrayList = new ArrayList<Dog>();
//遍历的时候也能直接取出Dog了
for(Dog tempDog:arrayList){
    System.out.println(tempDog.getName());
}

这个< Dog >就是泛型的使用,


看来我之前用过这种写法,但是我当时不知道它是泛型


,现在我对泛型有了个基本的了解。

标识类中某个属性的类型,或者是某个方法返回值的类型,或者参数类型

class Person<E>{//任意字母都可以,一般用T(type)
    //标识属性类型
    E val;
    //E是参数类型
    public Person(E s){
        this.s =s;
    }
    //E是返回值类型
    public E f(){
        return s;
    }
}

在事例化的时候,的数据类型就需要得到确定。



泛型使用细节

①< T >的只能是引用类型,如< integer >,< int >是不行的

②在给泛型指定具体类型后,可以传入该类型或者其子类类型,其他不行

③泛型使用形式:

List<Integer> list1 = new ArrayList <Integer>();
//或者简写为
List<Integer> list2 = new ArrayList<>();

ArrayList<Integer> list3 = new ArrayList <Integer>();
//或者简写为
ArrayList<Integer> list4 = new ArrayList<>();

//推荐使用简写形式

如果不写< T >,默认给他的泛型是< Object >



自定义泛型类
class 类名 <T,R...>{
	成员
}

①普通成员可以使用泛型(属性、方法)

②使用泛型的数组,不能初始化(因为不知道要初始化成多大的)

③静态方法中不能使用类的泛型(因为静态是和类相关的,但是类加载时,还不知道是什么类型)

④泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)

⑤如果在创建对象时,没有指定类型,

默认为Object

(但是不指定,会warning)



自定义泛型接口
interface 接口名<T,R...>{
    
}

①接口中,静态成员也不能使用泛型(和泛型类规定③一样);然而我们知道——接口中的属性,必须是public static final的

②泛型接口的类型,在

继承接口

或者

实现接口

时确定

③没有指定类型,默认为Object

OKOK,结束,😄( : D连着写就会变成 😄,非常的神奇)



版权声明:本文为N1824717102原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。