Java基础 DAY17

1 抽象类

1.1 抽象类引出

在这里插入图片描述
在这里插入图片描述
当一个类中存在抽象方法时,需要将该类声明为abstract
所谓抽象方法就是没有实现的方法(没有方法体)
一般来说,抽象类会被继承,有其子类来实现抽象方法.

package com.hspedu.abstract_;

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

    }
}

abstract class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
    }

    //思考:这里eat 这里你实现了,其实没有什么意义
    //即: 父类方法不确定性的问题
    //===> 考虑将该方法设计为抽象(abstract)方法
    //===> 所谓抽象方法就是没有实现的方法
    //===> 所谓没有实现就是指,没有方法体
    //===> 当一个类中存在抽象方法时,需要将该类声明为abstract类
    //===> 一般来说,抽象类会被继承,有其子类来实现抽象方法.
//    public void eat() {
//        System.out.println("这是一个动物,但是不知道吃什么..");
//    }
    public abstract void eat()  ;
}

1.2 抽象类使用细节

1.2.1 抽象类使用细节1

在这里插入图片描述
在这里插入图片描述

package Abstract_;

public class AbstractDetail01 {
    public static void main(String[] args) {
        //抽象类,不能被实例化
        //new A();
    }
}
//抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
//,还可以有实现的方法。
abstract class A {
    public void hi() {
        System.out.println("hi");
    }
}
//一旦类包含了abstract方法,则这个类必须声明为abstract,否则编译不会通过
abstract class B {
    public abstract void hi();
}
//abstract 只能修饰类和方法,不能修饰属性和其它的
class C {
    // public abstract int n1 = 1;
}

1.2.2 抽象类使用细节2

在这里插入图片描述

package Abstract_;

public class AbstractDetail02 {
    public static void main(String[] args) {
        System.out.println("hello");
    }
}
//抽象方法不能使用private、final 和 static来修饰,因为这些关键字都是和重写相违背的
abstract class H {
    public   abstract void hi();//抽象方法
}

//如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类
abstract class E {
    public abstract void hi();
}
abstract class F extends E {

}
class G extends E {
    @Override
    public void hi() { //这里相等于G子类实现了父类E的抽象方法,所谓实现方法,就是有方法体
    }
}

//抽象类的本质还是类,所以可以有类的各种成员
abstract class D {
    public int n1 = 10;
    public static  String name = "你好";
    public void hi() {
        System.out.println("hi");
    }
    public abstract void hello();
    public static void ok() {
        System.out.println("ok");
    }
}

1.3 抽象类课堂练习

在这里插入图片描述

package com.hspedu.abstract_;

abstract public class Employee {
    private String name;
    private int id;
    private double salary;

    public Employee(String name, int id, double salary) {
        this.name = name;
        this.id = id;
        this.salary = salary;
    }
    //将work做成一个抽象方法
    public abstract void work();
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}
========================================
package com.hspedu.abstract_;

public class Manager extends Employee {
    private double bonus;
    public Manager(String name, int id, double salary) {
        super(name, id, salary);
    }

    public double getBonus() {
        return bonus;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }

    @Override
    public void work() {
        System.out.println("经理 " + getName() + " 工作中...");
    }
}
======================================================
package com.hspedu.abstract_;

public class AbstractExercise01 {
    public static void main(String[] args) {
        //测试
        Manager jack = new Manager("jack", 999, 50000);
        jack.setBonus(8000);
        jack.work();

        CommonEmployee tom = new CommonEmployee("tom", 888, 20000);
        tom.work();
    }
}

1.4 抽象模板模式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package Abstract_;

public class TestTemplate {
    public static void main(String[] args) {
        AA aa = new AA();
        aa.calculateTime();//这里需要
    }
}
======================================
package Abstract_;

public class AA extends Template{
    //计算任务
    public void job(){//实现父类Template的抽象方法job
        long num = 0;
        for (int i = 1;i <= 1000000;i++){
            num += i;
        }
    }
}
======================================
package Abstract_;

abstract public class Template {//抽象类-模板设计模式

    public abstract void job();//抽象方法

    public void calculateTime(){//实现方法,调用job方法
        //得到开始的时间
        long start = System.currentTimeMillis();
        job();//动态绑定机制
        //得到结束的时间
        long end = System.currentTimeMillis();
        System.out.println("执行时间 " + (end - start));
    }
}

在这里插入图片描述

2 接口

在这里插入图片描述

2.1 接口快速入门

在这里插入图片描述
在这里插入图片描述

package interface_;

public class Camera implements UsbInterface{//实现接口,实际上就是把接口的方法实现
    @Override
    public void start() {
        System.out.println("相机开始工作");
    }

    @Override
    public void stop() {
        System.out.println("相机停止工作");
    }
}
=====================================================================
package interface_;
//Phone类实现UsbInterface
//解释:①Phone类需要实现UsbInterface接口 规定/声明的方法
public class Phone implements UsbInterface{
    @Override
    public void start() {
        System.out.println("手机开始工作");
    }

    @Override
    public void stop() {
        System.out.println("手机停止工作");
    }
}
======================================================================
package interface_;

public class Computer {
    //编写一个方法,计算机工作
    public void work(UsbInterface usbInterface){
        //通过接口调用方法
        usbInterface.start();
        usbInterface.stop();
    }
}
====================================================
package interface_;

public interface UsbInterface {//接口
    //规定接口的相关方法,教师规定的,规范
    public void start();
    public void stop();

}
======================================================
package interface_;

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

        //创建手机,相机对象
        Camera camera = new Camera();
        Phone phone = new Phone();

        //创建计算机
        Computer computer = new Computer();
        computer.work(phone);//把手机接入到计算机
        System.out.println("==============");

        computer.work(camera);//把相机接入到计算机
    }
}

在这里插入图片描述

2.2 接口基本介绍

在这里插入图片描述

2.3 接口应用场景

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.4 接口使用细节

2.4.1 接口使用细节1

在这里插入图片描述

2.4.2 接口使用细节2

在这里插入图片描述

2.5 接口vs继承

在这里插入图片描述

package com.hspedu.interface_;

public class ExtendsVsInterface {
    public static void main(String[] args) {
        LittleMonkey wuKong = new LittleMonkey("悟空");
        wuKong.climbing();
        wuKong.swimming();
        wuKong.flying();
    }
}

//猴子
class Monkey {
    private String name;

    public Monkey(String name) {
        this.name = name;
    }
    public void climbing() {
        System.out.println(name + " 会爬树...");
    }

    public String getName() {
        return name;
    }
}

//接口
interface Fishable {
    void swimming();
}
interface Birdable {
    void flying();
}

//继承
//小结:  当子类继承了父类,就自动的拥有父类的功能
//      如果子类需要扩展功能,可以通过实现接口的方式扩展.
//      可以理解 实现接口 是 对java 单继承机制的一种补充.
class LittleMonkey extends Monkey implements Fishable,Birdable {

    public LittleMonkey(String name) {
        super(name);
    }

    @Override
    public void swimming() {
        System.out.println(getName() + " 通过学习,可以像鱼儿一样游泳...");
    }

    @Override
    public void flying() {
        System.out.println(getName() + " 通过学习,可以像鸟儿一样飞翔...");
    }
}

==小结: == 当子类继承了父类,就自动的拥有父类的功能
如果子类需要扩展功能,可以通过实现接口的方式扩展.
可以理解 实现接口 是 对java 单继承机制的一种补充.
在这里插入图片描述

2.6 接口多态传递

package interface_;

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{ }
interface IG extends IH{ }
//实现了IG接口的类
class Teacher implements IG{ }

2.7 接口课堂练习

在这里插入图片描述
在这里插入图片描述

package interface_;

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

interface A {  // 1min 看看
    int x = 0;
}  //想到 等价 public static final int x = 0;

class B {
    int x = 1;//普通属性
}

class C extends B implements A {
    public void pX() {
        //System.out.println(x); //错误,原因不明确x
        //可以明确的指定x
        //访问接口的 x 就使用 A.x
        //访问父类的 x 就使用 super.x
        System.out.println(A.x + " " + super.x);//输出 0 1
    }

    public static void main(String[] args) {
        new C().pX();
    }
}

3 四种内部类

内部类:一个类的内部又完整地嵌套了另一个结构,被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class).是我们类的第五大成员(属性、方法、构造器、代码块、内部类),内部类最大的特点是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
底层源码,有大量的内部类
在这里插入图片描述
基本语法:
在这里插入图片描述

package innerclass;

public class InnerClass01 { //外部其他类
    public static void main(String[] args) {
    }
}
class Outer { //外部类
    private int n1 = 100;//属性
    public Outer(int n1) {//构造器
        this.n1 = n1;
    }
    public void m1() {//方法
        System.out.println("m1()");
    }
    {//代码块
        System.out.println("代码块...");
    }
    class Inner { //内部类, 在Outer类的内部
    }
}

3.1 局部内部类

局部内部类是定义在外部类的局部位置,比如方法中(代码块中),并且有类名
1.可以直接访问外部类的所有成员,包括私有的;
2.不能添加访问修饰符,因为它的地位就是一个局部变量,局部变量是不能使用修饰符的,但是可以用final修饰,因为局部变量也可以使用final
3.作用域:仅仅定义在它的方法或者代码块中。
4.局部内部类–访问–》外部类的成员[访问方式:直接访问]
5.外部类–访问–》局部内部类的成员
访问方式:创建对象,再访问(必须在作用域中)

package innerclass;
/**
 * 演示局部内部类的使用
 */
public class LocalInnerClass {//
    public static void main(String[] args) {
        //演示一遍
        Outer02 outer02 = new Outer02();
        outer02.m1();
        System.out.println("outer02的hashcode=" + outer02);
    }
}
class Outer02 {//外部类
    private int n1 = 100;
    private void m2() {
        System.out.println("Outer02 m2()");
    }//私有方法
    public void m1() {//方法
        //1.局部内部类是定义在外部类的局部位置,通常在方法
        //3.不能添加访问修饰符,但是可以使用final 修饰
        //4.作用域 : 仅仅在定义它的方法或代码块中
        final class Inner02 {//局部内部类(本质仍然是一个类)
            //2.可以直接访问外部类的所有成员,包含私有的
            private int n1 = 800;
            public void f1() {
                //5. 局部内部类可以直接访问外部类的成员,比如下面 外部类n1 和 m2()
                //7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,
                //   使用 (外部类名.this.成员)去访问
                //   Outer02.this 本质就是外部类的对象, 即哪个对象调用了m1, Outer02.this就是哪个对象
                System.out.println("n1=" + n1 + " 外部类的n1=" + Outer02.this.n1);
                System.out.println("Outer02.this hashcode=" + Outer02.this);
                m2();
            }
        }
        //6. 外部类在方法中,可以创建Inner02对象,然后调用方法即可
        Inner02 inner02 = new Inner02();
        inner02.f1();
    }
}

3.2 匿名内部类

(最重要!)
匿名内部类:
1.本质是类
2.内部类
3.该类没有名字(但其实它是有名字的,是系统给分配的,底层可以查,我们看不到)
4.同时它还是一个对象
**说明:**匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名

3.2.1匿名内部类的基本语法

在这里插入图片描述

package innerclass;
/**
 * 演示匿名内部类的使用
 */
public class AnonymousInnerClass {//外部其他类
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}
class Outer04 { //外部类
    private int n1 = 10;//属性
    public void method() {//方法
        //基于接口的匿名内部类
        //1.需求: 想使用IA接口,并创建对象
        //2.传统方式:写一个类,实现该接口,并创建对象
        //3.需求是 Tiger/Dog 类只是使用一次,后面再不使用
        //4. 可以使用匿名内部类来简化开发
        //5. tiger的编译类型 ? IA
        //6. tiger的运行类型 ? 是匿名内部类  Outer04$1
        /*
            我们看底层 会分配 类名 Outer04$1
            class Outer04$1 implements IA {
                @Override
                public void cry() {
                    System.out.println("老虎叫唤...");
                }
            }
         */
        //7. jdk底层在创建匿名内部类 Outer04$1,立即就创建了 Outer04$1实例,
        // 并且把地址返回给tiger
        //8. 匿名内部类使用一次,就不能再使用
        IA tiger = new IA() {
            @Override
            public void cry() {
                System.out.println("老虎叫唤...");
            }
        };
        System.out.println("tiger的运行类型=" + tiger.getClass());
        tiger.cry();
        tiger.cry();
        tiger.cry();

//        IA tiger1 = new Tiger();//传统方式,接口类型可以指向实现了该接口的类的对象实例
//        tiger1.cry();




        //演示基于类的匿名内部类
        //分析
        //1. father编译类型 Father
        //2. father运行类型 Outer04$2
        //3. 底层会创建匿名内部类
        /*
            class Outer04$2 extends Father{
                @Override
                public void test() {
                    System.out.println("匿名内部类重写了test方法");
                }
            }
         */
        //4. 同时也直接返回了匿名内部类 Outer04$2的对象
        //5. 注意("jack") 参数列表会传递给 构造器
        Father father = new Father("jack"){
            @Override
            public void test() {
                System.out.println("匿名内部类重写了test方法");
            }
        };
        System.out.println("father对象的运行类型=" + father.getClass());//Outer04$2
        father.test();


        //基于抽象类的匿名内部类
        Animal animal = new Animal(){
            @Override
            void eat() {
                System.out.println("小狗吃骨头...");
            }//必须重写实现
        };
        animal.eat();
    }
}
interface IA {//接口
    public void cry();
}
class Tiger implements IA {
   @Override
    public void cry() {
        System.out.println("老虎叫唤...");
    }
}
//class Dog implements  IA{
//    @Override
//    public void cry() {
//        System.out.println("小狗汪汪...");
//    }
//}

class Father {//类
    public Father(String name) {//构造器
        System.out.println("接收到name=" + name);
    }
    public void test() {//方法
    }
}
abstract class Animal { //抽象类
    abstract void eat();//抽象方法
}

3.2.2 匿名内部类的使用

匿名内部类的语法比较奇特,匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上来看,它既有定义类的特征,也有创建对象的特征,对前面的代码分析可以看出这个特点,因此可以调用匿名内部类方法。

package innerclass;
//匿名内部类的语法比较特别,匿名内部类既是
public class AnonymousInnerClassDetail {
    public static void main(String[] args) {
        Outer05 outer05 = new Outer05();
        outer05.f1();
    }
}
class Outer05{
    private int n1 = 99;
    public void f1(){
        //创建一个基于类的匿名内部类
         Person p= new Person(){
            @Override
            public void hi() {
                System.out.println("匿名内部类重写了hi方法");
            }
        };
         p.hi();//编译类型是Person,所以能调用hi();
        // 根据动态绑定,
        // 因为真正的运行类型是Outer05$1,所以运行时输出的是’ 匿名内部类重写了hi方法‘
        
        
        //也可以直接调用
        //class 匿名内部类 extends Person{}
        new Person(){
            @Override
            public void hi() {
                System.out.println("匿名内部类重写了hi()方法。。。");
            }

            @Override
            public void ok(String str) {
                super.ok(str);//父类是Person,即super会调Person
            }
        }.ok("jack");
    }
}

class Person{//类
    public void hi(){
        System.out.println("Person hi()");
    }
    public void ok(String str){
        System.out.println("Person ok() + str");
    }
}

1.可以直接访问外部类的所有成员,包括私有的;
2.不能添加访问修饰符,因为它的地位就是一个局部变量
3.作用域:仅仅定义在它的方法或者代码块中。
4.外部其他类——>不能访问——>匿名内部类(因为 匿名内部类地位是一个局部变量)
5.如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认就近原则;
如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问。

package innerclass;
//匿名内部类的语法比较特别,匿名内部类既是
public class AnonymousInnerClassDetail {
    public static void main(String[] args) {
        Outer05 outer05 = new Outer05();
        outer05.f1();

        System.out.println("main 方法中Outer05.this hashcode=" + outer05);
    }
}
class Outer05{
    private int n1 = 99;
    public void f1(){
        //创建一个基于类的匿名内部类
         Person p= new Person(){
             private int n1 = 88;
            @Override
            public void hi() {
                System.out.println("匿名内部类重写了hi方法;");
                System.out.println("n1=" + n1 + " 外部类的n1=" + Outer05.this.n1);
                //Outer05.this 就是调用f1的对象
                System.out.println("Outer05.this hashcode=" + Outer05.this);
            }
        };
         p.hi();//编译类型是Person,所以能调用hi();
        // 根据动态绑定,
        // 因为真正的运行类型是Outer05$1,所以运行时输出的是’ 匿名内部类重写了hi方法‘


        //也可以直接调用
        //class 匿名内部类 extends Person{}
        new Person(){
            @Override
            public void hi() {
                System.out.println("匿名内部类重写了hi()方法。。。");
            }

            @Override
            public void ok(String str) {
                super.ok(str);//父类是Person,即super会调Person
            }
        }.ok("jack");
    }
}

class Person{//类
    public void hi(){
        System.out.println("Person hi()");
    }
    public void ok(String str){
        System.out.println("Person ok() + str");
    }
}

3.2.3匿名内部类实践

最佳实践:当作实参直接传递,简洁高效。

package innerclass;

public class InnerClassExercise01 {
    public static void main(String[] args) {
        
        //当作实参直接传递,简洁高效
        f1(new IL() {
            @Override
            public void show() {
                System.out.println("这是一幅名画...");
            }
        });
        //传统方法
        f1(new Picture());
    }
    
    //静态方法,形参时接口类型
    public static void f1(IL il){
        il.show();
    }
}
//接口
interface IL{
    void show();
}
//类->实现IL=》编程领域,称作硬编码
class Picture implements IL{
    @Override
    public void show() {
        System.out.println("这是一幅名画...");
    }
}

3.3 成员内部类

在这里插入图片描述

package innerclass;

public class InnerClass01 {
    public static void main(String[] args) {
        Outer08 outer08 = new Outer08();
        outer08.t1();
    }
}

class Outer08{
    private int n1 = 10;
    public String name = "张三";

    //成员内部类是定义在外部类的成员位置上
    protected class Inner08{//成员内部类
        public void say(){
            //可以直接访问外部类的所有成员,包含私有的
            System.out.println("Outer01的 n1 =" + n1 + "outer01的name=" + name);
        }
    }
    //写方法
    public void t1(){
        //使用了成员内部类
        Inner08 inner08 = new Inner08();
        inner08.say();
    }
}

在这里插入图片描述
外部其他类—>访问---->成员内部类

package innerclass;

public class InnerClass01 {
    public static void main(String[] args) {
        Outer08 outer08 = new Outer08();
       

        //外部其他类,使用成员内部类的两种方式
        //方法一:
        //outer08.new Inner08();就相当于把new Inner08()当作是outer08成员
        // 就是一个语法,不用纠结
        Outer08.Inner08 inner08 = outer08.new Inner08();

        //方法二:
        //在外部类中,编写一个方法,可以返回Inner08对象
        Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
        inner08Instance.say();
    }
}



class Outer08{
    private int n1 = 10;
    public String name = "张三";

    //成员内部类是定义在外部类的成员位置上
    protected class Inner08{//成员内部类
        public void say(){
            //可以直接访问外部类的所有成员,包含私有的
            System.out.println("Outer01的 n1 =" + n1 + "outer01的name=" + name);
        }
    }

    public Inner08 getInner08Instance(){//该方法返回Inner08的实例
        return new Inner08();
    }
}

在这里插入图片描述
外部类和内部类成员重名,内部类访问,默认遵循就近原则;
如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

3.4 静态内部类

在这里插入图片描述
在这里插入图片描述

package innerclass;

public class StaticInnerClass01 {
    public static void main(String[] args) {
        Outer10 outer10 = new Outer10();
        outer10.m1();
    }
}
class Outer10{
    private int n1 = 10;
    private static String name = "jungle";
    //Inner10就是静态内部类
    //1.放在外部类的成员位置
    //2.使用static修饰
    //3.可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
    //4.可以添加任意访问修饰符(public/protected/默认/private),因为它的地位就是一个成员
    //5.作用域:同其他成员,为整个类体
    private static class Inner10{
        public void say(){
            System.out.println(name);
        }
    }
    public void m1(){
        Inner10 inner10 = new Inner10();
        inner10.say();
    }

}

在这里插入图片描述
外部其他类访问静态内部类:

package innerclass;

public class StaticInnerClass01 {
    public static void main(String[] args) {
        Outer10 outer10 = new Outer10();

        //外部其他类访问静态内部类
        //方式一:
        //因为静态内部类,是可以通过类名直接访问,前提是满足访问权限
        Outer10.Inner10 inner10 = new Outer10.Inner10();
        inner10.say();
        //方式二;
        //编写一个方法,可以返回静态内部类的对象实例
        Outer10.Inner10 inner101 = outer10.getInner10();

        //方法三:
        //写一个静态方法,可以用类名直接引用
        Outer10.Inner10 inner10_ = Outer10.getInner10_();
        inner10_.say();

    }
}
class Outer10{
    private static String name = "jungle";

    static class Inner10{
        public void say(){
            System.out.println(name);
        }
    }

    public Inner10 getInner10(){
        return new Inner10();
    }
    public static Inner10 getInner10_(){
        return new Inner10();
    }

}

在这里插入图片描述
静态不用加this

4 小结

①内部类有四种,局部内部类,匿名内部类,成员内部类,静态内部类
②重点是匿名内部类的使用
new 类/接口(参数列表){
//…
}
③成员内部类、静态内部类是放在外部类的成员位置,本质就是一个成员

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值