抽象与接口、引用类型数组

一、抽象

1.抽象方法

由abstract修饰的方法,我们称为抽象方法,我们需要注意的是抽象方法只有方法的定义没有具体的实现(甚至连{}都没有),如下我们定义一个show()的抽象方法。

public abstract void show();

这就是我们抽象方法的定义。

2.抽象类

同样抽象类就是由abstract修饰的类,我们就称为抽象类,那么抽象方法与抽象类怎么去用?需要注意什么呢?我们接下来说一说。

1、包含抽象方法的类必须是抽象类,但不包含抽象方法的类也可以声明为抽象类。

2、抽象类不能被实例化(new对象)。为什么呢?我们可以理解为抽象类是不完整,就像抽象方法一样,我们知道完整的方法有五要素,即修饰词,数据类型,方法名,方法参数列表,最后一个就是大括号里的方法体,而抽象方法没有大括号,就没有方法体,那么我们就不知道这个方法是用来干什么的,创建就没有意义,同时也不完整,至于为什么要用抽象,下面会说;那么我们能去new一个不完整的对象吗?肯定是不可以的。

           abstract起到模板的作用,可以有属性和方法,并且没有具体的实现方法,无法具体的给它分配内存空间,只分配了在栈中的引用,但抽象类有构造方法,不能用来实例化的,只能用来初始化的,所以无法创建对象,也就是不能用new关键字去产生对象,抽象方法只需声明,不需实现。

3、抽象类是需要被继承的,派生类:

          1、必须重写所有抽象方法------------------变不完整为完整(是所有的抽象方法,注意了!)

          2、子类也声明为抽象类----------------------------一般不这么用(我们把子类声明为抽象类的话,只要同样是抽象类就不能实例化对象(new),那么子类也不能new,无法用,那么把子类声明为抽象类也没有用了,虽然不会编译错误但没用,所以我们一般不这么用)

4、抽象类的意义(也可以理解为为什么要用抽象类,它的好处是什么?)

           1、封装共有的属性和行为------------------代码复用(和继承差不多,减少代码的重复性)

            2、可以包含抽象方法,为所有派生类统一入口(名字统一),强制必须重写(这可能就是抽象类的主要作用,我们在抽象类中定义了抽象方法后,由它的n个子类去继承,我们所有的子类都必须重写我们的抽象方法,不然就会编译错误,那么我们在子类中的这个方法是不是就统一了名称(不知道的了解一下重写是什么就行了))

那么接下来我们来看个小案例:

抽象类Animal父类:

public abstract class Animal {
    String name;
    int age;
    String color;
    Animal(){
    }
    Animal(String name,int age,String color){
        this.name = name;
        this.age = age;
        this.color = color;
    }

    void drink(){
        System.out.println(color+"色的"+age+"岁的"+name+"正在喝水...");
    }
    abstract void eat();
}

Dog子类:(必须重写父类的eat方法,父类eat方法没有东西!不然编译错误)

public class Dog extends Animal{
    Dog(){
    }
    Dog(String name,int age,String color){
        super(name,age,color);
    }

    void lookHome(){
        System.out.println(color+"色的"+age+"岁的狗狗"+name+"正在看家...");
    }
    void eat(){
        System.out.println(color+"色的"+age+"岁的狗狗"+name+"正在吃肯头...");
    }
}

Chick子类:(同样要重写父类eat方法!)

public class Chick extends Animal {
    Chick(){
    }
    Chick(String name,int age,String color){
        super(name,age,color);
    }
    void layEggs(){
        System.out.println(color+"色的"+age+"岁的小鸡"+name+"正在下蛋...");
    }
    void eat(){
        System.out.println(color+"色的"+age+"岁的小鸡"+name+"正在吃小米...");
    }
}

注意:Dog与Chick类中eat()方法必须重写,名称必须统一,这就是抽象类的作用。

二、接口

我们需要知道的是接口是一个引用数据类型,interface定义,只能包含抽象方法(常量、默认方法、静态方法、私有方法)。

我们还需要了解类与接口是并联关系,都是引用数据类型,所以接口的定义和类就大同小异啦,怎么去定义呢?接口定义如下:

interface Inter {
    abstract void show();
    void test(); //接口中的方法默认都是抽象的,前面默认有abstract
    //void say(){} //编译错误,抽象方法不能有方法体
}

我们发现是不是与定义类差不多呀,类的定义是class关键字+类名;我们接口的定义就是interface关键字+接口名。

我们需要注意接口是不能被实例话的,为什么?我们知道接口里是什么,是不是抽象方法哦,抽象的东西都是不完整的,那么我们接口里包含一个不完整的东西,是不是也不完整啦(注意可以这样去理解,但是具体原因是什么?我们接口是没有构造方法的,既然没有构造方法那是不是不能new啦!)

那么接口怎么去用呢?

接口是需要被实现/继承的,实现类/派生类:必须重写接口中的所有抽象方法(通过implements来实现)

            注意:重写接口中的方法时,必须加public(先记住)

interface Inter {
    abstract void show();
    void test(); //接口中的方法默认都是抽象的,前面默认有abstract
    //void say(){} //编译错误,抽象方法不能有方法体
}
class InterImpl implements Inter {
    public void show(){ //重写接口中的抽象方法时,必须加public
    }
    public void test(){
    }
}

那么我们是不是疑惑啦?这不就是一个类吗?我们直接继承不就好啦,但是我们知道继承有一个特性是单继承的,即一个子类只能有一个父类(不可能有两个亲爹吧),而接口就是对单一继承的扩展,一个子类可以实现多个接口(可以有许多个干爹)。

所以接口就有一个特点:一个类可以实现多个接口,用逗号分隔。若又继承又实现时,应先继承后实现(注意顺序)

//演示接口的多实现
interface Inter1{
    void show();
}
interface Inter2{
    void test();
}
abstract class Aoo{
    abstract void say();
}
class Boo extends Aoo implements Inter1,Inter2{
    public void show(){}
    public void test(){}
    void say(){}
}

并且接口可以继承接口,可以发现如果继承了的话,如果类实现的是子类接口就需要重写父类与子类中所有的方法,如果只实现了父类,就不用重写子类的方法,如下如果我们类实现了i3接口,那么我们只需要重写show()方法。

//演示接口继承接口
interface Inter3{
    void show();
}
interface Inter4 extends Inter3{
    void test();
}
class Coo implements Inter4{
    public void test(){}
    public void show(){}
}

 三、引用类型数组

数组是分为两种,一种是基本类型数组,即数组的定义用的是八大基本数据类型中任意一个类型,还有一种就是引用类型数组,即数组中的类型都是引用数据类型(类,接口等等都是引用数据类型)我们需要记住引用类型数组与基本类型数组的区别。

区别1:给引用类型数组的元素赋值时,需要new个对象

区别2:访问引用类型数组的元素的属性/行为时,需要打点访问

public class RefArrayDemo {
    public static void main(String[] args) {
        Dog[] dogs = new Dog[3];
        dogs[0] = new Dog("小黑",2,"黑");
        dogs[1] = new Dog("小白",1,"白");
        dogs[2] = new Dog("小灰",3,"灰");
        System.out.println(dogs[0].name); //输出第1只狗狗的名字
        dogs[1].age = 4; //修改第2只狗狗的年龄为4岁
        dogs[2].swim(); //第3只狗狗在游泳
        for(int i=0;i<dogs.length;i++){ //遍历dogs数组
            System.out.println(dogs[i].name); //输出每只狗狗的名字
            dogs[i].eat(); //每只狗狗吃饭
        }

        Chick[] chicks = new Chick[2];
        chicks[0] = new Chick("小花",1,"花");
        chicks[1] = new Chick("大花",2,"花");
        for(int i=0;i<chicks.length;i++){ //遍历chicks数组
            System.out.println(chicks[i].name);
            chicks[i].layEggs();
        }

        Fish[] fish = new Fish[4];
        fish[0] = new Fish("小金",2,"金");
        fish[1] = new Fish("大金",4,"白");
        fish[2] = new Fish("小绿",1,"绿");
        fish[3] = new Fish("小红",3,"红");
        for(int i=0;i<fish.length;i++){ //遍历fish数组
            System.out.println(fish[i].color);
            fish[i].swim();
        }

        /*
        //声明Dog型数组dogs,包含3个元素,每个元素都是Dog型,默认值为null
        Dog[] dogs = new Dog[3];
        //声明Chick型数组chicks,包含3个元素,每个元素都是Chick型,默认值为null
        Chick[] chicks = new Chick[3];
        //声明Fish型数组fish,包含2个元素,每个元素都是Fish型,默认值为null
        Fish[] fish = new Fish[2];
         */
    }
}

四、补充 

1、设计规则(如何去设计父子类与接口):-----------适合初学者

        1.将所有派生类共有的属性和行为,抽到超类中-------------抽共性

        2.若派生类的行为/代码都一样,设计普通方法

               若派生类的行为/代码不一样,设计抽象方法

        3.将部分派生类共有的行为,抽到接口中

               接口对继承单根性的扩展------------------------实现多继承

               接口是一种标准、规范,若实现了某接口就具备某个功能,若不实现接口就不具备那个

功能 ---------- 后期才能理解得更好,现在不理解就先记住,你以后代码写多了自然就明白了。
2、. 不包含抽象方法的类,也可以声明为抽象类,只要是抽象类就不能被实例化
3、类间关系:
       
            类和类-------------------------------继承
            接口和接口 ------------------------- 继承
             类和接口 ---------------------------- 实现
4、null :表示空,没有指向任何对象。(引用数据类型默认值为nuill)
 
            若引用的值为 null ,则该引用不能再进行任何操作了,若操作则发生 NullPointerException
指针异常。
欧克!今天的学习笔记就到这啦!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值