JAVA编程核心基础(三)—抽象与接口

文章仅作为JAVA编程复习使用
文章参考博主:<遇见狂神说>、<生命是有光的>

抽象与接口

7-1、抽象类与抽象方法

1)抽象类定义

  1. 父类知道子类一定要完成某个功能,但是每个子类完成的情况是不一样的
  2. 子类以后也只会用自己重写的功能,那么父类的该功能就可以定义成抽象方法,子类重写调用子类自己的就行

2)抽象方法定义

没有方法体{},只有方法名,并且必须用abstract修饰。 注:具有抽象方法的类必须定义成抽象类

public abstract class Action extends B{
    //约束
    //抽象方法: 只有方法名字,没有方法的实现! 即这个方法没有代码体{}
    public abstract void doSomething();   //这里加了{}会报错

    public void a(){
    }

    public abstract void ao();

    public void c(){
        System.out.println("how");
    }

    public abstract int x();


    /**
     * 
     * 思考:
     *
     * 1、既然没法new这个类,那么这个抽象类存在构造器吗?
     *
     * 2、存在的意义?   抽象出来提高开发效率
     *
     */
}


//对于继承了抽象类的子类,这些子类都必须要实现抽象类的方法;
//若这个抽象类的子类也是抽象类,则让他的子子类去实现
public class A extends Action{

    @Override
    public void doSomething() {

    }

    @Override
    public void a() {

    }

    @Override
    public void ao() {

    }

    @Override
    public int x() {
        return 0;
    }

    @Override
    public void con() {
    }
}

public abstract class B {
    public abstract void con();
}

3)抽象类的作用 —>为了被子类继承

  • 一个类继承了抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类

4)抽象类的特征 —>有得有失

  • 得:抽象类得到了具有抽象方法的能力
  • 失:抽象类失去了创建对象的能力(抽象类不能创建对象)

5)总结抽象类

  1. 抽象类不可以被实例化,不能被new来实例化抽象类(即:不能new这个抽象类,只能靠子类去实现它:约束!)

  2. 抽象类里可以有抽象方法/非抽象方法 ,但是 有抽象方法的类 必定是抽象类,但是抽象方法必须是在抽象类中

  3. 抽象类可以包含属性,方法,构造方法,但是构造方法不能用来new实例,只能被子类调用

  4. 抽象类只能用来继承

  5. 父类如果是抽象类,那么父类里的抽象方法,子类里必须都重写, 因为抽象类里的抽象方法是没有代码体的,也就是个空有名字的方法而已;

    若这个子类也是抽象类,那么由它的子子非抽象类去重写 父类,父父类里的所有抽象方法

7-2、接口

接口不是类,可以理解为和类同等级,interface代表接口

1)定义

  1. 接口是更加彻底的抽象
  2. 在JDK1.8之前接口中只能是抽象方法和常量
  3. 接口体现的是规范思想,实现接口的子类必须重写完接口的全部抽象方法
修饰符 interface 接口名称{
    // 在jdk1.8之前接口中只能是抽象方法和常量
}
interface 定义接口的核心关键字
    
public interface TimeService {
    void time();
}

2)组成

  1. 接口中的抽象方法可以省略public abstract不写,默认会加上,所以接口里的方法都是抽象

  2. 接口中的抽象常量也是省略public static final不写,而且一般在接口中不会去定义常量,都是定义方法

    而常量指的是变量值只有一个,且在程序运行过程中不可更改值

  3. 每个接口都需要有实现类(implements)

在这里插入图片描述

3)接口的实现类

子类继承父类,实现类实现接口

格式:见代码

public class UserServiceImpl implements UserService, TimeService {
    public void time() {
    }

    public void add(String name) {
    }

    public void delete(String name) {
    }

    public void update(String name) {
    }

    public void query(String name) {
    }
    
}

理解:

  1. 类与类是继承关系
  2. 类与接口是实现关系,接口是被类实现的
  3. 实现接口的类称为:实现类

注意:

  • 一个类实现接口必须重写完接口中的全部抽象方法,否则这个类要定义成抽象类(一个类继承抽象类,必须重写完抽象类的所有抽象方法,否则这个类要定义成抽象类)

总结 类 与 接口

  • JAVA类与类之间是单继承关系,类与接口是多实现关系,接口与接口是多继承关系
    • 一个类只能继承一个直接父类
    • 一个类可以同时实现多个接口
    • 一个接口可以同时继承多个接口
public class A extends B{xxx}    //类之间是单继承关系

public class UserServiceImpl implements UserService, TimeService{xxx}   //类与接口之间是多实现关系

public interface AA extends Demo08.TimeService, Demo08.UserService {xxx}   //接口与接口之间是多继承关系

若仍不理解,可参考以下例子解释:

​ 接口就像一道数学大题,这个接口里的方法就是大题中的各个小题,实现类里 重写的方法 就类似于人对这个题目的解法
,一个接口可以被很多类去继承,然后这些实现类需要重写所有接口里的方法,其实一一对应了每个人对这个题目的不同解法

,所以,一般公司会先定义好接口,然后再一一去实现接口里的抽象方法。

4)实现多个接口的使用注意事项

  1. 如果实现了多个接口,多个接口中存在同名的静态方法并不会冲突

    —> 原因是只能通过各自接口名访问静态方法

  2. 当一个类,既继承了一个父类,又实现了若干个接口时,父类中成员方法和接口中的默认方法重名,子类就近选择执行父类的成员方法

  3. 当一个类实现多个接口时,多个接口中存在同名的默认方法,实现类必须重写这个方法

  4. 接口不是类,所以接口也没有构造器,更不能创建对象

    构造器:初始化一个类的对象并返回引用

7-3、抽象类与接口的区别

  1. 接口的方法默认是 public abstract,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),而抽象类可以有非抽象的方法。
  2. 接口中除了 staticfinal 变量,不能有其他变量,而抽象类中则不一定。
  3. 一个类可以实现多个接口,但只能实现一个抽象类。接口自己本身可以通过 extends 关键字扩展多个接口。
  4. 接口方法默认修饰符是 public,抽象方法可以有 publicprotecteddefault 这些修饰符(抽象方法就是为了被重写所以不能使用 private 关键字修饰!)。
  5. 从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范。

7-4、代码块

代码块按照有无static修饰分为:静态代码块,实例代码块

  • 静态代码块

    • 必须用static修饰,属于类,会与类一起优先加载,而且自动触发执行一次!
    • 静态代码块可以用于执行类的方法之前进行静态资源的初始化操作
    static{  
    }
    
  • 实例代码块

    • static修饰,属于类的每个对象,会与类的每个对象一起加载,每次创建对象的时候,实例代码块就会触发执行一次
    • 实例代码块可以用于初始化实例资源
    • 实例代码块的代码实际上是提取到每个构造器中去执行的(扩展和了解)

7-5、final关键字

  1. final修饰类: 类不能被继承了
  2. final修饰方法:方法不能被重写
  3. final修饰变量:变量有且仅能被赋值一次
  • 回顾:成员变量和局部变量
  • 静态成员变量:
    • static修饰,属于类,只加载一份
    • final修饰静态成员变量,变量变成了常量
  • 实例成员变量:
    • static修饰,属于每个对象,与对象一起加载
  • 局部变量:
    • 在方法中,构造器中,代码块中,for循环中的变量,用完作用范围就消失了
    • final修饰局部变量:让值被固定或者说保护起来,执行过程中防止被修改
// 1.final修饰类
final class Animal{
    
}
// 2.final修饰局部变量
{
    final int age = 10;
}

7-6、单例(重点!!)

定义:单例的意思是一个类永远只存在一个对象,不能创建多个对象

使用原由:开发中很多类的对象我们只需要一个,对象越多占内存越多

实现方式:(两种)

  1. 饿汉单例设计模式:通过类获取单例对象的时候,对象已经提前做好了
  2. 懒汉单例设计模式:通过类获取单例对象的时候发现没有对象才会去创建一个对象

7-7、枚举类

  1. 枚举类的作用: 枚举用于做信息标志和信息分类
  2. 枚举类的特点
    1. 枚举类是final修饰的,不能被继承
    2. 枚举类的第一行罗列的是枚举类的对象,而且使用常量存储的
    3. 所以枚举类的第一行写的都是常量名称,默认存储了枚举对象
    4. 枚举类的构造器默认是私有的
    5. 枚举类相当于是多例设计对象
public class EnumDemo01 {
    public static void main(String[] args) {
        Sex s1 = Sex.BOY;
        Sex s2 = Sex.GIRL;
    }
}
enum Sex{
    BOY,GIRL;
}

7-8、一些关于抽象与接口的面试题

7-8-1、抽象类

  • 面试题:抽象类是否有构造器,抽象类是否可以创建对象?

    1. 抽象类作为类一定有构造器,而且抽象类必须有构造器,是提供给子类创建对象调用父类构造器使用的,除此之外,类中有的成分,抽象类都具备(成员变量,成员方法,构造器,内部类,代码块)
    2. 抽象类虽然有构造器但是抽象类不能创建对象
  • 面试题:抽象类中的构造器可以私有吗?

    答:从代码编译角度,抽象类中的构造器可以私有,但是子类继承默认调用父类构造器会报错

    因为私有只能在本类中使用,所以抽象类中构造器私有没有意义。

// 反证法:假如抽象类可以创建对象!

public class AbstractDemo {
    public static void main(String[] args){
        // Animal a = new Animal(); // 报错
        // a.run();抽象方法不能执行,因为它没有方法体,所以抽象类不能创建对象
    }
}


abstract class Animal{
    private String name;
    //默认无参构造器
    public Animal(){

    }
    //抽象方法
    public abstract  void run();

    //实例方法
    public void test(){

    }
    //静态方法
    public static void Addr(){

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  • 抽象类存在的意义

    答: 1. 抽象类就是为了被子类继承(就是为了派生子类),否则抽象类毫无意义

    2.抽象类体现的是模板思想,部分实现,部分抽象,可以设计模板设计模式

    理解:抽象类中已经实现的是模板中确定的成员,抽象类不确定如何实现的定义成抽象方法,交给具体的子类去实现

7-8-2、代码块

——静态代码块和实例代码块的作用?

答:静态代码块有static修饰,属于类,会与类一起优先加载,而且自动触发执行一次!静态代码块可以用于执行类的方法之前进行静态资源的初始化操作

实例代码块无static修饰,属于类的对象,会与类的每个对象一起加载,每次创建对象的时候,实例代码块就会触发执行一次,实例代码块可以用于初始化实例资源

7-8-3、final与abstract关键字

请问abstractfinal的关系是什么? 答:互斥关系,不能同时出现修饰成员!

abstract 修饰类,类是抽象类,必须被继承

final 修饰类,类不能被继承

abstract 修饰方法,方法必须被重写

final 修饰方法,方法不能被重写

7-8-4、变量

**变量有几种? ** 答:成员变量和局部变量

  1. 静态成员变量: 有static修饰,属于类,只加载一份
  2. 实例成员变量: 无static修饰,属于每个对象,与对象一起加载
  3. 局部变量: 只在方法中,构造器中,代码块中,for循环中,用完作用范围就消失了
  4. final修饰局部变量:让值被固定或者说保护起来,执行过程中防止被修改

7-8-5、写一个饿汉单例设计模式

饿汉单例设计模式:通过类获取单例对象的时候,对象已经提前做好了

步骤:

  1. 定义一个单例类
  2. 把类的构造器私有
  3. 定义一个静态成员变量用于存储一个对象!(饿汉单例在返回对象的时候,对象要已经做好)
  4. 定义一个方法返回单例对象
// 定义一个单例类
class SingleInstance01{
    // 2.定义一个静态成员变量用于存储一个对象
    public static SingleInstance01 ins = new SingleInstance01();
    // 1.把类的构造器私有,构造器只能在本类中访问
    // 私有的无参构造器
    private SingleInstance01(){
    }
    // 3.提供一个方法返回单例对象
    public static SingleInstance01 getInstance(){
        return ins;
    }
}

7-8-6、写一个懒汉单例设计模式

懒汉单例模式:通过类获取单例对象的时候发现没有对象才回去创建一个对象

步骤:

  1. 定义一个单例类
  2. 把类的构造器私有
  3. 定义一个静态成员变量用于存储一个对象(懒汉单例不能直接创建对象,必须需要的时候才去创建)
  4. 定义一个方法返回单例对象,判断对象不存在才创建一次,存在直接返回
// 定义一个单例类
class SingleInstance2{
    //定义一个静态成员变量用于存储一个对象!
    public static SingleInstance2 ins;
    // 1.把类的构造器私有
    private SingleInstance2(){

    }
    // 3.通过方法返回一个对象,第一次不存在对象才创建一个返回
    public static SingleInstance2 getInstance(){
        if(ins == null){
            //第一次来取对象,创建一个对象
            ins = new SingleInstance2();
        }
        return ins;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值