乐趣区

关于后端:Java-的抽象类-接口以及内部类

第一章 抽象类

1.1 概述

1.1.1 抽象类引入

​ 父类中的办法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的办法申明和办法主体,只有申明还有意义,而办法主体则没有存在的意义了 (因为子类对象会调用本人重写的办法)。换句话说,父类可能晓得子类应该有哪个性能,然而性能具体怎么实现父类是不分明的(由子类本人决定),父类只须要提供一个没有办法体的定义即可,具体实现交给子类本人去实现。 咱们把没有办法体的办法称为形象办法。Java 语法规定,蕴含形象办法的类就是抽象类

  • 形象办法:没有办法体的办法。
  • 抽象类:蕴含形象办法的类。

1.2 abstract 应用格局

abstract 是形象的意思,用于润饰办法办法和类,润饰的办法是形象办法,润饰的类是抽象类。

1.2.1 形象办法

应用abstract 关键字润饰办法,该办法就成了形象办法,形象办法只蕴含一个办法名,而没有办法体。

定义格局:

修饰符 abstract 返回值类型 办法名 (参数列表);

代码举例:

public abstract void run();

1.2.2 抽象类

如果一个类蕴含形象办法,那么该类必须是抽象类。留神:抽象类不肯定有形象办法,然而有形象办法的类必须定义成抽象类。

定义格局:

abstract class 类名字 {}

代码举例:

public abstract class Animal {public abstract void run();}

1.2.3 抽象类的应用

要求 :继承抽象类的子类 必须重写父类所有的形象办法。否则,该子类也必须申明为抽象类。

代码举例:

// 父类, 抽象类
abstract class Employee {
    private String id;
    private String name;
    private double salary;
    
    public Employee() {}
    
    public Employee(String id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }
    
    // 形象办法
    // 形象办法必须要放在抽象类中
    abstract public void work();}

// 定义一个子类继承抽象类
class Manager extends Employee {public Manager() { }
    public Manager(String id, String name, double salary) {super(id, name, salary);
    }
    // 2. 重写父类的形象办法
    @Override
    public void work() {System.out.println("治理其他人");
    }
}

// 定义一个子类继承抽象类
class Cook extends Employee {public Cook() { }
    public Cook(String id, String name, double salary) {super(id, name, salary);
    }
    @Override
    public void work() {System.out.println("厨师炒菜多加点盐...");
    }
}

// 测试类
public class Demo10 {public static void main(String[] args) {
        // 创立抽象类, 抽象类不能创建对象
        // 假如抽象类让咱们创建对象, 外面的形象办法没有办法体, 无奈执行. 所以不让咱们创建对象
//        Employee e = new Employee();
//        e.work();
        
        // 3. 创立子类
        Manager m = new Manager();
        m.work();
        
        Cook c = new Cook("ap002", "库克", 1);
        c.work();}
}

此时的办法重写,是子类对父类形象办法的实现实现,咱们将这种办法重写的操作,也叫做 实现办法

1.3 抽象类的特色

抽象类的特色总结起来能够说是 有得有失

有得:抽象类失去了领有形象办法的能力。

有失:抽象类失去了创建对象的能力。

其余成员(构造方法,实例办法,静态方法等)抽象类都是具备的。

1.4 抽象类的细节

不须要背,只有当 idea 报错之后,晓得如何批改即可。

对于抽象类的应用,以下为语法上要留神的细节,尽管条目较多,但若了解了形象的实质,无需死记硬背。

  1. 抽象类 不能创建对象,如果创立,编译无奈通过而报错。只能创立其非形象子类的对象。

    了解:假如创立了抽象类的对象,调用形象的办法,而形象办法没有具体的办法体,没有意义。

  2. 抽象类中,能够有构造方法,是供子类创建对象时,初始化父类成员应用的。

    了解:子类的构造方法中,有默认的 super(),须要拜访父类构造方法。

  3. 抽象类中,不肯定蕴含形象办法,然而有形象办法的类必然是抽象类。

    了解:未蕴含形象办法的抽象类,目标就是不想让调用者创立该类对象,通常用于某些非凡的类结构设计。

  4. 抽象类的子类,必须重写形象父类中 所有的 形象办法,否则子类也必须定义成抽象类,编译无奈通过而报错。

    了解:假如不重写所有形象办法,则类中可能蕴含形象办法。那么创建对象后,调用形象的办法,没有意义。

  5. 抽象类存在的意义是为了被子类继承。

    了解:抽象类中曾经实现的是模板中确定的成员,抽象类不确定如何实现的定义成形象办法,交给具体的子类去实现。

1.5 抽象类存在的意义

​ 抽象类存在的意义是为了被子类继承,否则抽象类将毫无意义。抽象类能够强制让子类,肯定要依照规定的格局进行重写。

第二章 接口

2.1 概述

咱们曾经学完了抽象类,抽象类中能够用形象办法,也能够有一般办法,构造方法,成员变量等。那么什么是接口呢?接口是更加彻底的形象,JDK7 之前,包含 JDK7,接口中全副是形象办法。接口同样是不能创建对象的

2.2 定义格局

// 接口的定义格局:interface 接口名称{// 形象办法}

// 接口的申明:interface
// 接口名称:首字母大写,满足“驼峰模式”

2.3 接口成分的特点

在 JDK7,包含 JDK7 之前,接口中的 只有 蕴含:形象办法和常量

2.3.1. 形象办法

​ 留神:接口中的形象办法默认会主动加上 public abstract 润饰程序员无需本人手写!!
​ 依照标准:当前接口中的形象办法倡议不要写上 public abstract。因为没有必要啊,默认会加上。

2.3.2 常量

在接口中定义的成员变量默认会加上:public static final 润饰。也就是说在接口中定义的成员变量实际上是一个常量。这里是应用 public static final 润饰后,变量值就不可被批改,并且是动态化的变量能够间接用接口名拜访,所以也叫常量。常量必须要给初始值。常量命名标准倡议字母全副大写,多个单词用下划线连贯。

2.3.3 案例演示

public interface InterF {
    // 形象办法!//    public abstract void run();
    void run();

    //    public abstract String getName();
    String getName();

    //    public abstract int add(int a , int b);
    int add(int a , int b);


    // 它的最终写法是:// public static final int AGE = 12 ;
    int AGE  = 12; // 常量
    String SCHOOL_NAME = "黑马程序员";

}

2.4 根本的实现

2.4.1 实现接口的概述

类与接口的关系为实现关系,即 类实现接口 ,该类能够称为接口的实现类,也能够称为接口的子类。实现的动作相似继承,格局相仿,只是关键字不同,实现应用 implements 关键字。

2.4.2 实现接口的格局

/** 接口的实现:在 Java 中接口是被实现的,实现接口的类称为实现类。实现类的格局:*/
class 类名 implements 接口 1, 接口 2, 接口 3...{}

从下面格局能够看出,接口是能够被多实现的。大家能够想一想为什么呢?

2.4.3 类实现接口的要求和意义

  1. 必须重写实现的全副接口中所有形象办法。
  2. 如果一个类实现了接口,然而没有重写齐全部接口的全副形象办法,这个类也必须定义成抽象类。
  3. 意义:接口体现的是一种标准,接口对实现类是一种强制性的束缚,要么全副实现接口申明的性能,要么本人也定义成抽象类。这正是一种强制性的标准。

2.4.4 类与接口根本实现案例

如果咱们定义一个运动员的 接口(标准),代码如下:

/**
   接口:接口体现的是标准。* */
public interface SportMan {void run(); // 形象办法,跑步。void law(); // 形象办法,恪守法律。String compittion(String project);  // 形象办法,较量。}

接下来定义一个乒乓球运动员类,实现接口,实现接口的 实现类 代码如下:

package com.itheima._03 接口的实现;
/**
 * 接口的实现:*    在 Java 中接口是被实现的,实现接口的类称为实现类。*    实现类的格局:
 *      class 类名 implements 接口 1, 接口 2, 接口 3...{
 *
 *
 *      }
 * */
public class PingPongMan  implements SportMan {
    @Override
    public void run() {System.out.println("乒乓球运动员略微跑一下!!");
    }

    @Override
    public void law() {System.out.println("乒乓球运动员违法!");
    }

    @Override
    public String compittion(String project) {return "加入"+project+"得金牌!";}
}

测试代码

public class TestMain {public static void main(String[] args) {
        // 创立实现类对象。PingPongMan zjk = new PingPongMan();
        zjk.run();
        zjk.law();
        System.out.println(zjk.compittion("寰球乒乓球较量"));

    }
}

2.4.5 类与接口的多实现案例

类与接口之间的关系是多实现的,一个类能够同时实现多个接口。

首先咱们先定义两个接口,代码如下:

/** 法律标准:接口 */
public interface Law {void rule();
}

/** 这一个运动员的标准:接口 */
public interface SportMan {void run();
}

而后定义一个实现类:

/**
 * Java 中接口是能够被多实现的:*    一个类能够实现多个接口: Law, SportMan
 *
 * */
public class JumpMan implements Law ,SportMan {
    @Override
    public void rule() {System.out.println("尊长违法");
    }

    @Override
    public void run() {System.out.println("训练跑步!");
    }
}

从下面能够看出类与接口之间是能够多实现的,咱们能够了解成实现多个标准,这是正当的。

2.5 接口与接口的多继承

Java 中,接口与接口之间是能够多继承的:也就是一个接口能够同时继承多个接口。大家肯定要留神:

类与接口是实现关系

接口与接口是继承关系

接口继承接口就是把其余接口的形象办法与本接口进行了合并。

案例演示:

public interface Abc {void go();
    void test();}

/** 法律标准:接口 */
public interface Law {void rule();
    void test();}

 *
 *  总结:*     接口与类之间是多实现的。*     接口与接口之间是多继承的。* */
public interface SportMan extends Law , Abc {void run();
}

2.6 扩大:接口的细节

不须要背,只有当 idea 报错之后,晓得如何批改即可。

对于接口的应用,以下为语法上要留神的细节,尽管条目较多,但若了解了形象的实质,无需死记硬背。

  1. 当两个接口中存在雷同形象办法的时候,该怎么办?

只有重写一次即可。此时重写的办法,既示意重写 1 接口的,也示意重写 2 接口的。

  1. 实现类能不能继承 A 类的时候,同时实现其余接口呢?

继承的父类,就好比是亲爸爸一样
实现的接口,就好比是干爹一样
能够继承一个类的同时,再实现多个接口,只不过,要把接口外面所有的形象办法,全副实现。

  1. 实现类能不能继承一个抽象类的时候,同时实现其余接口呢?

实现类能够继承一个抽象类的同时,再实现其余多个接口,只不过要把外面所有的形象办法全副重写。

  1. 实现类 Zi,实现了一个接口,还继承了一个 Fu 类。假如在接口中有一个办法,父类中也有一个雷同的办法。子类如何操作呢?

解决方法一:如果父类中的办法体,能满足以后业务的需要,在子类中能够不必重写。
解决方法二:如果父类中的办法体,不能满足以后业务的需要,须要在子类中重写。

  1. 如果一个接口中,有 10 个形象办法,然而我在实现类中,只须要用其中一个,该怎么办?

能够在接口跟实现类两头,新建一个两头类(适配器类)
让这个适配器类去实现接口,对接口外面的所有的办法做空重写。
让子类继承这个适配器类,想要用到哪个办法,就重写哪个办法。
因为两头类没有什么理论的意义,所以个别会把两头类定义为形象的,不让外界创建对象

第三章 外部类

3.1 概述

3.1.1 什么是外部类

将一个类 A 定义在另一个类 B 外面,外面的那个类 A 就称为 外部类 ,B 则称为 外部类。能够把外部类了解成寄生,外部类了解成宿主。

3.1.2 什么时候应用外部类

一个事物外部还有一个独立的事物,外部的事物脱离内部的事物无奈独立应用

  1. 人外面有一颗心脏。
  2. 汽车外部有一个发动机。
  3. 为了实现更好的封装性。

3.2 外部类的分类

按定义的地位来分

  1. 成员外部内,类定义在了成员地位 (类中办法外称为成员地位,无 static 润饰的外部类)
  2. 动态外部类,类定义在了成员地位 (类中办法外称为成员地位,有 static 润饰的外部类)
  3. 部分外部类,类定义在办法内
  4. 匿名外部类,没有名字的外部类,能够在办法中,也能够在类中办法外。

3.3 成员外部类

成员外部类特点

  • 无 static 润饰的外部类,属于外部类对象的。
  • 宿主:外部类对象。

外部类的应用格局

 外部类. 外部类。// 拜访外部类的类型都是用 外部类. 外部类

获取成员外部类对象的两种形式

形式一:内部间接创立成员外部类的对象

外部类. 外部类 变量 = new 外部类().new 外部类();

形式二:在外部类中定义一个办法提供外部类的对象

案例演示

形式一:public class Test {public static void main(String[] args) {
        //  宿主:外部类对象。// Outer out = new Outer();
        // 创立外部类对象。Outer.Inner oi = new Outer().new Inner();
        oi.method();}
}

class Outer {
    // 成员外部类,属于外部类对象的。// 拓展:成员外部类不能定义动态成员。public class Inner{
        // 这外面的货色与类是齐全一样的。public void method(){System.out.println("外部类中的办法被调用了");
        }
    }
}


形式二:public class Outer {
    String name;
    private class Inner{static int a = 10;}
    public Inner getInstance(){return new Inner();
    }
}

public class Test {public static void main(String[] args) {Outer o = new Outer();
        System.out.println(o.getInstance());


    }
}

3.4 成员外部类的细节

编写成员外部类的留神点:

  1. 成员外部类能够被一些修饰符所润饰,比方:private,默认,protected,public,static 等
  2. 在成员外部类外面,JDK16 之前不能定义动态变量,JDK16 开始才能够定义动态变量。
  3. 创立外部类对象时,对象中有一个隐含的 Outer.this 记录外部类对象的地址值。(请参见 3.6 节的内存图)

详解:

​ 外部类被 private 润饰,外界无奈间接获取外部类的对象,只能通过 3.3 节中的形式二获取外部类的对象

​ 被其余权限修饰符润饰的外部类个别用 3.3 节中的形式一间接获取外部类的对象

​ 外部类被 static 润饰是成员外部类中的非凡状况,叫做动态外部类上面独自学习。

​ 外部类如果想要拜访外部类的成员变量,外部类的变量必须用 final 润饰,JDK8 以前必须手动写 final,JDK8 之后不须要手动写,JDK 默认加上。

3.5 成员外部类面试题

请在? 中央向上相应代码, 以达到输入的内容

留神:外部类拜访外部类对象的格局是:外部类名.this

public class Test {public static void main(String[] args) {Outer.inner oi = new Outer().new inner();
        oi.method();}
}

class Outer {    // 外部类
    private int a = 30;

    // 在成员地位定义一个类
    class inner {
        private int a = 20;

        public void method() {
            int a = 10;
            System.out.println(???);    // 10   答案:a
            System.out.println(???);    // 20    答案:this.a
            System.out.println(???);    // 30    答案:Outer.this.a
        }
    }
}

3.6 成员外部类内存图

3.7 动态外部类

动态外部类特点

  • 动态外部类是一种非凡的成员外部类。
  • 有 static 润饰,属于外部类自身的。
  • 总结:动态外部类与其余类的用法齐全一样。只是拜访的时候须要加上外部类. 外部类。
  • 拓展 1 : 动态外部类能够间接拜访外部类的动态成员。
  • 拓展 2 : 动态外部类不能够间接拜访外部类的非动态成员,如果要拜访须要创立外部类的对象。
  • 拓展 3 : 动态外部类中没有银行的 Outer.this。

外部类的应用格局

外部类. 外部类。

动态外部类对象的创立格局

外部类. 外部类  变量 = new  外部类. 外部类结构器;

调用办法的格局:

  • 调用非静态方法的格局:先创建对象,用对象调用
  • 调用静态方法的格局:外部类名. 外部类名. 办法名();

案例演示

// 外部类:Outer01
class Outer01{
    private static  String sc_name = "黑马程序";
    // 外部类: Inner01
    public static class Inner01{
        // 这外面的货色与类是齐全一样的。private String name;
        public Inner01(String name) {this.name = name;}
        public void showName(){System.out.println(this.name);
            // 拓展: 动态外部类能够间接拜访外部类的动态成员。System.out.println(sc_name);
        }
    }
}

public class InnerClassDemo01 {public static void main(String[] args) {
        // 创立动态外部类对象。// 外部类. 外部类  变量 = new  外部类. 外部类结构器;
        Outer01.Inner01 in  = new Outer01.Inner01("张三");
        in.showName();}
}

3.8 部分外部类

  • 部分外部类 :定义在 办法中 的类。

定义格局:

class 外部类名 {
    数据类型 变量名;
    
    修饰符 返回值类型 办法名(参数列表) {
        // …
        class 外部类 {
            // 成员变量
            // 成员办法
        }
    }
}

3.9 匿名外部类【重点】

3.9.1 概述

匿名外部类:是外部类的简化写法。他是一个隐含了名字的外部类。开发中,最罕用到的外部类就是匿名外部类了。

3.9.2 格局

new 类名或者接口名() {重写办法;};

蕴含了:

  • 继承或者实现关系
  • 办法重写
  • 创建对象

所以从语法上来讲,这个整体其实是匿名外部类对象

3.9.2 什么时候用到匿名外部类

实际上,如果咱们心愿定义一个只有应用一次的类,就可思考应用匿名外部类。匿名外部类的实质作用

是为了简化代码

之前咱们应用接口时,仿佛得做如下几步操作:

  1. 定义子类
  2. 重写接口中的办法
  3. 创立子类对象
  4. 调用重写后的办法
interface Swim {public abstract void swimming();
}

// 1. 定义接口的实现类
class Student implements Swim {
    // 2. 重写形象办法
    @Override
    public void swimming() {System.out.println("狗刨式...");
    }
}

public class Test {public static void main(String[] args) {
        // 3. 创立实现类对象
        Student s = new Student();
        // 4. 调用办法
        s.swimming();}
}

咱们的目标,最终只是为了调用办法,那么能不能简化一下,把以上四步合成一步呢?匿名外部类就是做这样的快捷方式。

3.9.3 匿名外部类前提和格局

匿名外部类必须 继承一个父类 或者 实现一个父接口

匿名外部类格局

new 父类名或者接口名(){
    // 办法重写
    @Override 
    public void method() {// 执行语句}
};

3.9.4 应用形式

以接口为例,匿名外部类的应用,代码如下:

interface Swim {public abstract void swimming();
}

public class Demo07 {public static void main(String[] args) {
        // 应用匿名外部类
        new Swim() {
            @Override
            public void swimming() {System.out.println("自由泳...");
            }
        }.swimming();

        // 接口 变量 = new 实现类(); // 多态, 走子类的重写办法
        Swim s2 = new Swim() {
            @Override
            public void swimming() {System.out.println("蛙泳...");
            }
        };

        s2.swimming();
        s2.swimming();}
}

3.9.5 匿名外部类的特点

  1. 定义一个没有名字的外部类
  2. 这个类实现了父类,或者父类接口
  3. 匿名外部类会创立这个没有名字的类的对象

3.9.6 匿名外部类的应用场景

通常在办法的形式参数是接口或者抽象类时,也能够将匿名外部类作为参数传递。代码如下:

interface Swim {public abstract void swimming();
}

public class Demo07 {public static void main(String[] args) {
        // 一般形式传入对象
        // 创立实现类对象
        Student s = new Student();
        
        goSwimming(s);
        // 匿名外部类应用场景: 作为办法参数传递
        Swim s3 = new Swim() {
            @Override
            public void swimming() {System.out.println("蝶泳...");
            }
        };
        // 传入匿名外部类
        goSwimming(s3);

        // 完满计划: 一步到位
        goSwimming(new Swim() {public void swimming() {System.out.println("大学生, 蛙泳...");
            }
        });

        goSwimming(new Swim() {public void swimming() {System.out.println("小学生, 自由泳...");
            }
        });
    }

    // 定义一个办法, 模仿请一些人去游泳
    public static void goSwimming(Swim s) {s.swimming();
    }
}
退出移动版