42-面对对象编程(高级部分)2

42-面对对象编程(高级部分)2

  • 接口
    • 快速入门
    • 基本介绍
    • 接口应用场景
    • 接口注意事项
    • 课堂练习
    • 接口VS继承
    • 实现接口VS继承类
    • 接口的多态特性
    • 课堂练习
  • 内部类
    • 基本介绍
    • 基本语法
    • 内部类的分类
    • 局部内部类
    • 匿名内部类(重点)
    • 匿名内部类实践
    • 成员内部类
    • 静态内部类
  • 枚举
    • 枚举的引出
    • 枚举的两种实现方法
    • 自定义类实现枚举
    • enum关键字实现枚举
    • enum练习
    • enum成员方法
    • enum课堂练习
    • enum实现接口
  • 注解
    • 注解的理解
    • 基本的Annotation案例
      • @Override 注解
      • @Ddeprecated 注解
      • @SuppressWarnings 注解
  • 元注解
    • 基本介绍
    • 元注解的种类
    • @Retention 注解
    • @Target 注解
    • @Documented 注解
    • @Inherited 注解
  • 章节作业
  • 最后

接口

快速入门

package com.hspedu.interface_;

public class Interface01 {
    public static void main(String[] args) {
        //创建手机,相机对象
        //Camera 实现了 UsbInterface
        Camera camera = new Camera();
        //Phone 实现了 UsbInterface
        Phone phone = new Phone();
        //创建计算机
        Computer computer = new Computer();
        computer.work(phone);//把手机接入到计算机
        System.out.println("===============");
        computer.work(camera);//把相机接入到计算机

    }
}
package com.hspedu.interface_;

public class Computer {
    //编写一个方法, 计算机工作
    //解读:
    //1. UsbInterface usbInterface 形参是接口类型 UsbInterface
    //2. 看到 接收 实现了 UsbInterface接口的类的对象实例
    public void work(UsbInterface usbInterface) {
        //通过接口,来调用方法
        usbInterface.start();
        usbInterface.stop();
    }
}

package com.hspedu.interface_;

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

package com.hspedu.interface_;

public class Camera implements UsbInterface{//实现接口,就是把接口方法实现

    @Override
    public void start() {
        System.out.println("相机开始工作...");
    }

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

package com.hspedu.interface_;

public class Computer {
    //编写一个方法, 计算机工作
    //解读:
    //1. UsbInterface usbInterface 形参是接口类型 UsbInterface
    //2. 看到 接收 实现了 UsbInterface接口的类的对象实例
    public void work(UsbInterface usbInterface) {
        //通过接口,来调用方法
        usbInterface.start();
        usbInterface.stop();
    }
}

基本介绍

  • 接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来
  • 语法:
interface 接口名(){
	//属性
	//方法(1,抽象方法,2.默认实现方法(default),3.静态方法)
}

class 类名 implements 接口{
	//自己属性
	//自己方法
	(必须实现的接口的抽象方法)
}
  • 小结:1.在jdk7.0前,接口的所有方法都没有方法体,即都是抽象方法。 2. jdk8.0后可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现
package com.hspedu.interface_;

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

   }
}

//老韩解读
//1.如果一个类 implements实现 接口
//2. 需要将该接口的所有抽象方法都实现
class A implements AInterface {
   @Override
   public void hi() {
       System.out.println("hi()....");
   }
}

package com.hspedu.interface_;

public interface AInterface {
    //写属性
    public int n1 = 10;
    //写方法
    //在接口中,抽象方法,可以省略abstract关键字
    public void hi();

    //在jdk8后,可以有默认实现方法,需要使用default关键字修饰
    default public void ok() {
        System.out.println("ok ...");
    }
    //在jdk8后, 可以有静态方法
    public static void cry() {
        System.out.println("cry ....");
    }
}

接口应用场景

42-面对对象编程(高级部分)2_第1张图片

  • 可以约束命名
  • 调用时向上转型,动态绑定
package com.hspedu.interface_;

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

        MysqlDB mysqlDB = new MysqlDB();
        t(mysqlDB);
        OracleDB oracleDB = new OracleDB();
        t(oracleDB);
    }

    public static void t(DBInterface db) {
        db.connect();
        db.close();
    }
}

package com.hspedu.interface_;

public interface DBInterface { //项目经理

    public void connect();//连接方法
    public void close();//关闭连接
}

package com.hspedu.interface_;
//A程序
public class MysqlDB implements DBInterface {
    @Override
    public void connect() {
        System.out.println("连接mysql");
    }

    @Override
    public void close() {
        System.out.println("关闭mysql");
    }
}

package com.hspedu.interface_;

//B程序员连接Oracle
public class OracleDB implements DBInterface{

    @Override
    public void connect() {
        System.out.println("连接oracle");
    }

    @Override
    public void close() {
        System.out.println("关闭oracle");
    }
}

接口注意事项

  1. 接口不能被实例化
  2. 接口中所有的方法是public方法,接口中抽象方法,可以不用abstract修饰
  3. 一个普通实现接口,就必须将该接口的所有方法都实现
  4. 抽象类实现接口,可以不用实现接口方法
public class InterfaceDetail01 {
    public static void main(String[] args) {
        //new IA();
    }
}

//1.接口不能被实例化
//2.接口中所有的方法是 public方法,  接口中抽象方法,可以不用abstract 修饰
//3.一个普通类实现接口,就必须将该接口的所有方法都实现,可以使用alt+enter来解决
//4.抽象类去实现接口时,可以不实现接口的抽象方法
interface IA {
    void say();//修饰符 public protected 默认 private
    void hi();
}
class Cat implements IA{
    @Override
    public void say() {

    }

    @Override
    public void hi() {

    }
}
abstract class Tiger implements  IA {

}

  1. 一个类同时可以实现多个接口
  2. 接口中属性。只能是final的,而且是public static final修饰符,比如:int a = 1; 实际上是public static final int a = 1;(必须初始化)
  3. 接口中属性的访问形式:接口名.属性名
  4. 一个接口不能继承其他的类,但是可以继承多个别的接口
    eg: interface A extends B,C{}
  5. 接口的修饰符只能是public和默认,这点和类的修饰符是一样的
package com.hspedu.interface_;

public class InterfaceDetail02 {
    public static void main(String[] args) {
        //老韩证明 接口中的属性,是 public static final
        System.out.println(IB.n1);//说明n1 就是static
        //IB.n1 = 30; 说明n1 是 final
    }
}
interface IB {
    //接口中的属性,只能是final的,而且是 public static final 修饰符
    int n1 = 10; //等价 public static final int n1 = 10;
    void hi();
}
interface IC {
    void say();
}
//接口不能继承其它的类,但是可以继承多个别的接口
interface ID extends IB,IC {
}
//接口的修饰符 只能是 public 和默认,这点和类的修饰符是一样的
interface IE{}

//一个类同时可以实现多个接口
class Pig implements IB,IC {
    @Override
    public void hi() {
    }
    @Override
    public void say() {
    }
}

课堂练习

42-面对对象编程(高级部分)2_第2张图片

接口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() + " 通过学习,可以像鸟儿一样飞翔...");
    }
}

实现接口VS继承类

  • 接口和继承解决的问题不同
    继承的价值主要在于:解决代码的复用性和可维护性
    接口的价值在于:设计号各种规范(方法),让其他类去实现这些方法,即更加的灵活
  • 接口比继承更加灵活
    接口比继承更加灵活,继承是满足is-a的关系,而接口只需满足like-a关系
  • 接口在一定程度上实现代码解耦【即:接口规范性+动态绑定】

接口的多态特性

  1. 多态参数(前面案例体现)
    在前面的USB接口案例,Usb usb,即可以接受手机对象,又可以接受相机对象,就体现了接口多态(接口引用可以指向实现了接口的类的对象)
package com.hspedu.interface_;

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

        //接口的多态体现
        //接口类型的变量 if01 可以指向 实现了IF接口类的对象实例
        IF if01 = new Monster();
        if01 = new Car();

        //继承体现的多态
        //父类类型的变量 a 可以指向 继承AAA的子类的对象实例
        AAA a = new BBB();
        a = new CCC();
    }
}

interface IF {}
class Monster implements IF{}
class Car implements  IF{}

class AAA {

}
class BBB extends AAA {}
class CCC extends AAA {}

  1. 多态数组
    案例:给Usb数组中,存放Phone和相机对象,Phone类还有一个特有的方法call(),请遍历Usb数组,如果是Phone对象,除了调用Usb接口定义的方法外,还需要调用Phone特有的方法call
package com.hspedu.interface_;

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("手机可以打电话...");
    }

    @Override
    public void work() {
        System.out.println("手机工作中...");
    }
}
class Camera_ implements Usb {

    @Override
    public void work() {
        System.out.println("相机工作中...");
    }
}

  1. 接口存在多态传递现象
package com.hspedu.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 {
    void hi();
}
interface IG extends IH{ }
class Teacher implements IG {
    @Override
    public void hi() {
    }
}

课堂练习

42-面对对象编程(高级部分)2_第3张图片

package com.hspedu.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);
    }

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


内部类

基本介绍

一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class)嵌套其他类的类称为外部类(other class)。是我们类的五大成员(五大成员:属性,方法,构造器,代码块,内部类)内部类最大的特点就是直接访问私有属性,并且可以体现类与类之间的包含关系

基本语法

class Outer{//外部类
	class Inner{//内部类
	}
}
class Other{//外部其他类
}

package com.hspedu.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类的内部

    }
}

内部类的分类

  • 定义在外部局部位置上(比如方法内)
    局部内部类(有类名)
    匿名内部类(没有类名)
  • 定义在外部类的成员位置上
    成员内部类(没有static修饰)
    静态内部类(使用static修饰)

局部内部类

说明:局部内部类是定义在外部类的局部位置,比如方法中,并且没有类名

  1. 可以直接访问外部类的所有成员,包含私有的
  2. 不能添加访问修饰符,因为它的低位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以用法final
  3. 作用域:仅仅在定义它的方法或代码块中
  4. 局部变量——访问——>外部类的成员(访问方式:直接访问)
  5. 外部类——访问——>局部内部类发成员
    访问方式:创建对象,再访问(注:必须在作用域内)

小结:①局部内部类定义再方法/代码块中
②作用域再方法体或者代码块中
③本质仍然是一个类

  1. 外部其他类——不能访问——>局部内部类(因为局部内部类地位是一个局部变量)
  2. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)
package com.hspedu.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();
    }

}

匿名内部类(重点)

注:①本质是类②内部类③该类没有名字④同时是一个实例对象
说明:匿名内部类是定义再外部类的局部位置,比如方法中,并且没有类名

  1. 匿名内部类的基本语法
new 类或接口(参数){
	类体
};
package com.hspedu.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 tiger = new Tiger();
//        tiger.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();
}


这里注意底层有继承和实现

  1. 匿名内部类的语法比较奇特,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析就可以看出这个特点,因此可以调用匿名内部类方法
  2. 可以直接访问外部类的所有成员,包含私有的
  3. 不能添加访问修饰符,因为它的地位就是一个局部变量
  4. 作用域:仅仅在定义它的方法或代码块中
  5. 匿名内部类——访问——>外部类成员(直接访问)
  6. 外部其他类——不能访问——>匿名内部类(因为他是局部变量)
  7. 如果外部其他类和匿名内部类的成员重名时,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类.this.成员)去访问
package com.hspedu.innerclass;

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

        Outer05 outer05 = new Outer05();
        outer05.f1();
        //外部其他类---不能访问----->匿名内部类
        System.out.println("main outer05 hashcode=" + outer05);
    }
}

class Outer05 {
    private int n1 = 99;
    public void f1() {
        //创建一个基于类的匿名内部类
        //不能添加访问修饰符,因为它的地位就是一个局部变量
        //作用域 : 仅仅在定义它的方法或代码块中
        Person p = new Person(){
            private int n1 = 88;
            @Override
            public void hi() {
                //可以直接访问外部类的所有成员,包含私有的
                //如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,
                //默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问
                System.out.println("匿名内部类重写了 hi方法 n1=" + n1 +
                        " 外部内的n1=" + Outer05.this.n1 );
                //Outer05.this 就是调用 f1的 对象
                System.out.println("Outer05.this hashcode=" + Outer05.this);
            }
        };
        p.hi();//动态绑定, 运行类型是 Outer05$1

        //也可以直接调用, 匿名内部类本身也是返回对象
        // class 匿名内部类 extends Person {}
//        new Person(){
//            @Override
//            public void hi() {
//                System.out.println("匿名内部类重写了 hi方法,哈哈...");
//            }
//            @Override
//            public void ok(String str) {
//                super.ok(str);
//            }
//        }.ok("jack");


    }
}

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

匿名内部类实践

42-面对对象编程(高级部分)2_第4张图片

package com.hspedu.innerclass;

public class InnerClassExercise02 {
    public static void main(String[] args) {
        /*
        1.有一个铃声接口Bell,里面有个ring方法。(右图)
        2.有一个手机类Cellphone,具有闹钟功能alarmClock,参数是Bell类型(右图)
        3.测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
        4.再传入另一个匿名内部类(对象),打印:小伙伴上课了
         */
        CellPhone cellPhone = new CellPhone();
        //老韩解读
        //1. 传递的是实现了 Bell接口的匿名内部类 InnerClassExercise02$1
        //2. 重写了 ring
        //3. Bell bell = new Bell() {
        //            @Override
        //            public void ring() {
        //                System.out.println("懒猪起床了");
        //            }
        //        }
        cellPhone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("懒猪起床了");
            }
        });

        cellPhone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("小伙伴上课了");
            }
        });
    }
}
interface Bell{ //接口
    void ring();//方法
}
class CellPhone{//类
    public void alarmClock(Bell bell){//形参是Bell接口类型
        System.out.println(bell.getClass());
        bell.ring();//动态绑定
    }
}

成员内部类

说明:成员内部类是定义在外部类的成员位置,并且没有static修饰

  1. 可以直接访问外部类的所有成员,包含私有的
  2. 可以添加任意访问修饰符(public protected,默认,private),因为它的地位就是一个成员
  3. 作用域:和外部类的其他成员一样,为整个类体比如前面案例,在外部类的成员方法中创建成员内部对象,再调方法
  4. 成员内部类——访问——>外部类(比如:属性)[访问方式:直接访问]
  5. 外部类——访问——>内部类【访问方式:创建对象,再访问】
  6. 外部其他类——访问——>成员内部类(两种方式)
package com.hspedu.innerclass;

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

        //外部其他类,使用成员内部类的三种方式
        //老韩解读
        // 第一种方式
        // outer08.new Inner08(); 相当于把 new Inner08()当做是outer08成员
        // 这就是一个语法,不要特别的纠结.
        Outer08.Inner08 inner08 = outer08.new Inner08();
        inner08.say();
        // 第二方式 在外部类中,编写一个方法,可以返回 Inner08对象
        Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
        inner08Instance.say();


    }
}

class Outer08 { //外部类
    private int n1 = 10;
    public String name = "张三";

    private void hi() {
        System.out.println("hi()方法...");
    }

    //1.注意: 成员内部类,是定义在外部内的成员位置上
    //2.可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
    public class Inner08 {//成员内部类
        private double sal = 99.8;
        private int n1 = 66;
        public void say() {
            //可以直接访问外部类的所有成员,包含私有的
            //如果成员内部类的成员和外部类的成员重名,会遵守就近原则.
            //,可以通过  外部类名.this.属性 来访问外部类的成员
            System.out.println("n1 = " + n1 + " name = " + name + " 外部类的n1=" + Outer08.this.n1);
            hi();
        }
    }
    //方法,返回一个Inner08实例
    public Inner08 getInner08Instance(){
        return new Inner08();
    }


    //写方法
    public void t1() {
        //使用成员内部类
        //创建成员内部类的对象,然后使用相关的方法
        Inner08 inner08 = new Inner08();
        inner08.say();
        System.out.println(inner08.sal);
    }
}


静态内部类

说明:静态内部类是定义在外部类成员位置,并且有static修饰

  1. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
  2. 可以添加任意访问修饰符(public protected,默认,private),因为它的地位就是一个成员
  3. 作用域:同其他的成员,为整个类体
  4. 静态内部类——访问——>外部类(比如:静态属性)[访问方式:直接访问所有静态成员]
  5. 外部类——访问——>静态内部类(访问方式:创建对象,再访问)
  6. 外部其他类——访问——>静态内部类(三种方式)
  7. 如果外部类和静态内部类的成员重名时,静态内部类访问时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
package com.hspedu.innerclass;

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

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

        Outer10.Inner10 inner10_ = Outer10.getInner10_();
        System.out.println("************");
        inner10_.say();
    }
}

class Outer10 { //外部类
    private int n1 = 10;
    private static String name = "张三";
    private static void cry() {}
    //Inner10就是静态内部类
    //1. 放在外部类的成员位置
    //2. 使用static 修饰
    //3. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
    //4. 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
    //5. 作用域 :同其他的成员,为整个类体
    static class Inner10 {
        private static String name = "韩顺平教育";
        public void say() {
            //如果外部类和静态内部类的成员重名时,静态内部类访问的时,
            //默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.成员)
            System.out.println(name + " 外部类name= " + Outer10.name);
            cry();
        }
    }

    public void m1() { //外部类---访问------>静态内部类 访问方式:创建对象,再访问
        Inner10 inner10 = new Inner10();
        inner10.say();
    }

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

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


枚举

枚举的引出

42-面对对象编程(高级部分)2_第5张图片
42-面对对象编程(高级部分)2_第6张图片

package com.hspedu.enum_;


public class Enumeration01 {
   public static void main(String[] args) {
       //使用
       Season spring = new Season("春天", "温暖");
       Season winter = new Season("冬天", "寒冷");
       Season summer = new Season("夏天", "炎热");
       Season autumn = new Season("秋天", "凉爽");
//        autumn.setName("XXX");
//        autumn.setDesc("非常的热..");
       //因为对于季节而已,他的对象(具体值),是固定的四个,不会有更多
       //安老师的这个设计类的思路,不能体现季节是固定的四个对象
       //因此,这样的设计不好===> 枚举类[枚: 一个一个 举: 例举 , 
       //即把具体的对象一个一个例举出来的类
       // 就称为枚举类]
       Season other = new Season("红天", "~~~");
   }
}
class Season{//类
   private String name;
   private String desc;//描述

   public Season(String name, String desc) {
       this.name = name;
       this.desc = desc;
   }

   public String getName() {
       return name;
   }

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

   public String getDesc() {
       return desc;
   }

   public void setDesc(String desc) {
       this.desc = desc;
   }
}

42-面对对象编程(高级部分)2_第7张图片

枚举的两种实现方法

  1. 自定义类实现枚举
  2. 使用enum关键字实现枚举

自定义类实现枚举

  1. 不需要提供setXxx方法,因为枚举对象值通常为只读
  2. 对枚举对象/属性使用final + static 共同修饰,实现底层优化
  3. 枚举对象名通常使用全部大写,常量的命名规范
  4. 枚举对象根据需要,也可以有多个属性
package com.hspedu.enum_;


public class Enumeration02 {
    public static void main(String[] args) {
        System.out.println(Season.AUTUMN);
        System.out.println(Season.SPRING);
    }
}

//演示字定义枚举实现
class Season {//类
    private String name;
    private String desc;//描述

    //定义了四个对象, 固定.
    public static final Season SPRING = new Season("春天", "温暖");
    public static final Season WINTER = new Season("冬天", "寒冷");
    public static final Season AUTUMN = new Season("秋天", "凉爽");
    public static final Season SUMMER = new Season("夏天", "炎热");


    //1. 将构造器私有化,目的防止 直接 new
    //2. 去掉setXxx方法, 防止属性被修改
    //3. 在Season 内部,直接创建固定的对象
    //4. 优化,可以加入 final 修饰符
    private Season(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    @Override
    public String toString() {
        return "Season{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}

enum关键字实现枚举

  1. 当我们使用enum关键字开发一个枚举类时,默认会继承Enum类,而且时一个final类(用javap证明)
    42-面对对象编程(高级部分)2_第8张图片
  2. 传统的public static final Season SPRING = new Season(“春天”, “温暖”); 简化成SPRING(“春天”,“温暖”),这里必须知道,它调用的是哪个构造器
  3. 如果使用无参构造器创建枚举对象,则实参表和小括号可以省略
  4. 当有多个枚举对象时,使用,间隔,最后有一个分号结尾
  5. 枚举对象必须放在枚举类的首行
package com.hspedu.enum_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Enumeration03 {
    public static void main(String[] args) {
        System.out.println(Season2.AUTUMN);
        System.out.println(Season2.SUMMER);
    }
}
//演示使用enum关键字来实现枚举类
enum  Season2 {//类


    //定义了四个对象, 固定.
//    public static final Season SPRING = new Season("春天", "温暖");
//    public static final Season WINTER = new Season("冬天", "寒冷");
//    public static final Season AUTUMN = new Season("秋天", "凉爽");
//    public static final Season SUMMER = new Season("夏天", "炎热");
    //如果使用了enum 来实现枚举类
    //1. 使用关键字 enum 替代 class
    //2. public static final Season SPRING = new Season("春天", "温暖") 直接使用
    //   SPRING("春天", "温暖") 解读 常量名(实参列表)
    //3. 如果有多个常量(对象), 使用 ,号间隔即可
    //4. 如果使用enum 来实现枚举,要求将定义常量对象,写在前面
    //5. 如果我们使用的是无参构造器,创建常量对象,则可以省略 ()
    SPRING("春天", "温暖"), WINTER("冬天", "寒冷"), AUTUMN("秋天", "凉爽"),
    SUMMER("夏天", "炎热")/*, What()*/;

    private String name;
    private String desc;//描述

    private Season2() {//无参构造器

    }

    private Season2(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    @Override
    public String toString() {
        return "Season{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}


enum练习

42-面对对象编程(高级部分)2_第9张图片

42-面对对象编程(高级部分)2_第10张图片

enum成员方法

说明:使用关键字enum时,会隐式继承Enum类,这样我们就可以使用Enum类相关的方法

  1. toString : Enum类已经重写过了,返回的是当前对象名,子类可以重写该方法,用于返回对象的属性信息
  2. name : 返回当前对象名(常量名),子类中不能重写
  3. ordinal : 返回当前对象的位置号,默认从0开始
  4. values: 返回当前枚举类中所有的常量
  5. valuesOf : 将字符串转成枚举对象,要求字符串必须为已有的常量名,否则报异常
  6. compareTo : 比较两个枚举常量,比较的就是位置号
package com.hspedu.enum_;

/**
 * @author 韩顺平
 * @version 1.0
 * 演示Enum类的各种方法的使用
 */
public class EnumMethod {
    public static void main(String[] args) {
        //使用Season2 枚举类,来演示各种方法
        Season2 autumn = Season2.AUTUMN;

        //输出枚举对象的名字
        System.out.println(autumn.name());
        //ordinal() 输出的是该枚举对象的次序/编号,从0开始编号
        //AUTUMN 枚举对象是第三个,因此输出 2
        System.out.println(autumn.ordinal());
        //从反编译可以看出 values方法,返回 Season2[]
        //含有定义的所有枚举对象
        Season2[] values = Season2.values();
        System.out.println("===遍历取出枚举对象(增强for)====");
        for (Season2 season: values) {//增强for循环
            System.out.println(season);
        }

        //valueOf:将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常
        //执行流程
        //1. 根据你输入的 "AUTUMN" 到 Season2的枚举对象去查找
        //2. 如果找到了,就返回,如果没有找到,就报错
        Season2 autumn1 = Season2.valueOf("AUTUMN");
        System.out.println("autumn1=" + autumn1);
        System.out.println(autumn == autumn1);

        //compareTo:比较两个枚举常量,比较的就是编号
        //老韩解读
        //1. 就是把 Season2.AUTUMN 枚举对象的编号 和 Season2.SUMMER枚举对象的编号比较
        //2. 看看结果
        /*
        public final int compareTo(E o) {

            return self.ordinal - other.ordinal;
        }
        Season2.AUTUMN的编号[2] - Season2.SUMMER的编号[3]
         */
        System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER));

        //补充了一个增强for
//        int[] nums = {1, 2, 9};
//        //普通的for循环
//        System.out.println("=====普通的for=====");
//        for (int i = 0; i < nums.length; i++) {
//            System.out.println(nums[i]);
//        }
//        System.out.println("=====增强的for=====");
//        //执行流程是 依次从nums数组中取出数据,赋给i, 如果取出完毕,则退出for
//        for(int i : nums) {
//            System.out.println("i=" + i);
//        }
    }
}

enum课堂练习

42-面对对象编程(高级部分)2_第11张图片

package com.hspedu.enum_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class EnumExercise02 {
    public static void main(String[] args) {
        //获取到所有的枚举对象, 即数组
        Week[] weeks = Week.values();
        //遍历,使用增强for
        System.out.println("===所有星期的信息如下===");
        for (Week week : weeks) {
            System.out.println(week);
        }
    }
}

/*
声明Week枚举类,其中包含星期一至星期日的定义;
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
使用values 返回所有的枚举数组, 并遍历 , 输出左图效果

 */

enum Week   {
    //定义Week的枚举对象
    MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"), THURSDAY("星期四"),
    FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日");
    private String name;

    private Week(String name) {//构造器
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}

enum实现接口

  1. 使用enum关键字后,就不能再继续继承其他类了,因为enum会隐式继承Enum,而java是单继承机制
  2. 枚举类和普通类一样,可以实现接口,如下形式。
    enum 类名 implements 接口1,接口2{}
package com.hspedu.enum_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class EnumDetail {
    public static void main(String[] args) {
        Music.CLASSICMUSIC.playing();
    }
}
class A {

}

//1.使用enum关键字后,就不能再继承其它类了,因为enum会隐式继承Enum,而Java是单继承机制
//enum Season3 extends A {
//
//}
//2.enum实现的枚举类,仍然是一个类,所以还是可以实现接口的.
interface IPlaying {
    public void playing();
}
enum Music implements IPlaying {
    CLASSICMUSIC;
    @Override
    public void playing() {
        System.out.println("播放好听的音乐...");
    }
}

注解

注解的理解

  1. 注解(Annotation)也被称为元数据(Metadate)用于修饰解释包,类,方法,属性,构造器,局部变量等数据信息
  2. 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入再代码中的补充信息
  3. 再javaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。再javaEE中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替javaEE旧版中所遗留的繁冗代码和XML配置等

基本的Annotation案例

@Override 注解

  • @Override:限定某个方法,是重写父类方法,该注解中能用于方法
    补充:@interface 不是interface,是注解类,是jdk5.0以后加入的
package com.hspedu.annotation_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Override_ {
    public static void main(String[] args) {

    }
}
class Father{//父类

    public void fly(){
        int i = 0;
        System.out.println("Father fly...");
    }
    public void say(){}

}

class Son extends Father {//子类
    //老韩解读
    //1. @Override 注解放在fly方法上,表示子类的fly方法时重写了父类的fly
    //2. 这里如果没有写 @Override 还是重写了父类fly
    //3. 如果你写了@Override注解,编译器就会去检查该方法是否真的重写了父类的
    //   方法,如果的确重写了,则编译通过,如果没有构成重写,则编译错误
    //4. 看看 @Override的定义
    //   解读: 如果发现 @interface 表示一个 注解类
    /*
        @Target(ElementType.METHOD)
        @Retention(RetentionPolicy.SOURCE)
        public @interface Override {
        }
     */
    @Override   //说明
    public void fly() {
        System.out.println("Son fly....");
    }
    @Override
    public void say() {}
}


  • @Override 使用说明
  1. @Override表示指定重写父类方法(从编译层面验证)如果父类没有fly方法,则会报错
  2. 如果不写@Override注解,而父类仍有public void fly(){},仍然构成重写
  3. @Override只能修饰方法,不能修饰其他类,包,属性等
  4. 查看@Override注解源码为@Target(ElementType METHOD),说明只能修饰方法
  5. @Target是修饰注解的注解,称为元注解

@Ddeprecated 注解

  1. @Ddeprecated :用于表示某个程序元素(类,方法)已过时
  2. 可以修饰方法,类,字段,包,参数等等
  3. @Target(value = {CONSTRUCTOR,FLELD,LOCK_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE})
  4. @Ddeprecated 的作用可以做到新旧版本的兼容和过度
package com.hspedu.annotation_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Deprecated_ {
    public static void main(String[] args) {
        A a = new A();
        a.hi();
        System.out.println(a.n1);
    }
}

//老韩解读
//1. @Deprecated 修饰某个元素, 表示该元素已经过时
//2. 即不在推荐使用,但是仍然可以使用
//3. 查看 @Deprecated 注解类的源码
//4. 可以修饰方法,类,字段, 包, 参数  等等
//5. @Deprecated 可以做版本升级过渡使用
/*
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
 */
@Deprecated
class A {
    @Deprecated
    public int n1 = 10;
    @Deprecated
    public void hi(){

    }
}

@SuppressWarnings 注解

@SuppressWarnings:抑制编译器警告

  1. unchecked是忽略没有检查的警告
  2. rawtypes是忽略没有指定泛型的警告(传参是没有指定泛型的错误警告)
  3. unused是忽略没有使用某个变量的警告错误
  4. @SuppressWarnings,可以修饰的程序元素,查看@Target
  5. 生成@SuppressWarnings时,不用背直接点击左侧的黄色提示,就可以选择
package com.hspedu.annotation_;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 韩顺平
 * @version 1.0
 */
@SuppressWarnings({"rawtypes", "unchecked", "unused"})
public class SuppressWarnings_ {

    //老韩解读
    //1. 当我们不希望看到这些警告的时候,可以使用 SuppressWarnings注解来抑制警告信息
    //2. 在{""} 中,可以写入你希望抑制(不显示)警告信息
    //3. 可以指定的警告类型有
    //          all,抑制所有警告
    //          boxing,抑制与封装/拆装作业相关的警告
    //        //cast,抑制与强制转型作业相关的警告
    //        //dep-ann,抑制与淘汰注释相关的警告
    //        //deprecation,抑制与淘汰的相关警告
    //        //fallthrough,抑制与switch陈述式中遗漏break相关的警告
    //        //finally,抑制与未传回finally区块相关的警告
    //        //hiding,抑制与隐藏变数的区域变数相关的警告
    //        //incomplete-switch,抑制与switch陈述式(enum case)中遗漏项目相关的警告
    //        //javadoc,抑制与javadoc相关的警告
    //        //nls,抑制与非nls字串文字相关的警告
    //        //null,抑制与空值分析相关的警告
    //        //rawtypes,抑制与使用raw类型相关的警告
    //        //resource,抑制与使用Closeable类型的资源相关的警告
    //        //restriction,抑制与使用不建议或禁止参照相关的警告
    //        //serial,抑制与可序列化的类别遗漏serialVersionUID栏位相关的警告
    //        //static-access,抑制与静态存取不正确相关的警告
    //        //static-method,抑制与可能宣告为static的方法相关的警告
    //        //super,抑制与置换方法相关但不含super呼叫的警告
    //        //synthetic-access,抑制与内部类别的存取未最佳化相关的警告
    //        //sync-override,抑制因为置换同步方法而遗漏同步化的警告
    //        //unchecked,抑制与未检查的作业相关的警告
    //        //unqualified-field-access,抑制与栏位存取不合格相关的警告
    //        //unused,抑制与未用的程式码及停用的程式码相关的警告
    //4. 关于SuppressWarnings 作用范围是和你放置的位置相关
    //   比如 @SuppressWarnings放置在 main方法,那么抑制警告的范围就是 main
    //   通常我们可以放置具体的语句, 方法, 类.
    //5.  看看 @SuppressWarnings 源码
    //(1) 放置的位置就是 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE
    //(2) 该注解类有数组 String[] values() 设置一个数组比如 {"rawtypes", "unchecked", "unused"}
    /*
        @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
            @Retention(RetentionPolicy.SOURCE)
            public @interface SuppressWarnings {

                String[] value();
        }
     */
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("jack");
        list.add("tom");
        list.add("mary");
        int i;
        System.out.println(list.get(1));

    }

    public void f1() {
//        @SuppressWarnings({"rawtypes"})
        List list = new ArrayList();


        list.add("jack");
        list.add("tom");
        list.add("mary");
//        @SuppressWarnings({"unused"})
        int i;
        System.out.println(list.get(1));
    }
}

元注解

基本介绍

JDK的元Annotation用于修饰其他Annotation

元注解的种类

  1. Retention //指定注解的作用范围,三种:SOURCE(源文件编译),CLASS(类),RUNTIME(运行)
  2. Target //指定注解可以在那些地方使用
  3. Documented //指定该注解是否会在javadoc体现
  4. Inherited //子类会继承父类注解

@Retention 注解


42-面对对象编程(高级部分)2_第12张图片
注:Override的作用域在SOURCE,当编译器编译时生效,不会写入到.class文件,也不会在runtime(运行)时生效

@Target 注解

  • 基本说明:用于修饰Annotation定义,用于指定被修饰的Annotation能用于修饰那些程序元素@Target也包含一个名为value的成员变量

@Documented 注解

  • 基本说明:@Documented:用于指定被该元注解修饰的注解类将被javadoc工具提取生成文档时,可以看到该注解
  • 注:定义为Documented的注解必须设置Retention的值为RUNTIME

@Inherited 注解

被它修饰的Annotation将具有继承性。如果某个父类使用了被@Inherited修饰的注解,则其子类将自动拥有该注解

章节作业

在这里插入图片描述

package com.hspedu.homework;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Homework04 {
    public static void main(String[] args) {
        Cellphone cellphone = new Cellphone();
        //老韩解读
        //1. 匿名内部类是
        /*
            new ICalculate() {
                @Override
                public double work(double n1, double n2) {
                    return n1 + n2;
                }
            }, 同时也是一个对象
            他的编译类型 ICalculate, 他的运行类型就是 匿名内部类
         */
        cellphone.testWork(new ICalculate() {
            @Override
            public double work(double n1, double n2) {
                return n1 + n2;
            }
        }, 10, 8);//18.0

        cellphone.testWork(new ICalculate() {
            @Override
            public double work(double n1, double n2) {
                return n1 * n2;
            }
        }, 10, 8);

    }
}
/*
1.计算器接口具有work方法,功能是运算,有一个手机类Cellphone,
   定义方法testWork测试计算功能,调用计算接口的work方法,
2.要求调用CellPhone对象 的testWork方法,使用上 匿名内部类

 */
//编写接口
interface ICalculate {
    //work方法 是完成计算,但是题没有具体要求,所以自己设计
    //至于该方法完成怎样的计算,我们交给匿名内部类完成
    public double work(double n1, double n2) ;
}
class Cellphone {
    //老韩解读,当我们调用testWork方法时,直接传入一个实现了ICalculate接口的匿名内部类即可
    //该匿名内部类,可以灵活的实现work,完成不同的计算任务
    public void testWork(ICalculate iCalculate, double n1, double n2) {
        double result = iCalculate.work(n1, n2);//动态绑定
        System.out.println("计算后的结果是=" + result);
    }
}

注:这种匿名内部类情况属于work的计算方法,可以在调用时改变

42-面对对象编程(高级部分)2_第13张图片

package com.hspedu.homework;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Homework06 {
    public static void main(String[] args) {
        Person tang = new Person("唐僧", new Horse());
        tang.common();//一般情况下
        tang.passRiver();//过河
        tang.common();//一般情况下
        tang.passRiver();//过河
        tang.passRiver();//过河
        tang.passRiver();//过河
        //过火焰山
        tang.passFireHill();

    }
}
/*
1.有一个交通工具接口类Vehicles,有work接口
2.有Horse类和Boat类分别实现Vehicles
3.创建交通工具工厂类,有两个方法分别获得交通工具Horse和Boat
4.有Person类,有name和Vehicles属性,在构造器中为两个属性赋值
5.实例化Person对象“唐僧”,要求一般情况下用Horse作为交通工具,遇到大河时用Boat作为交通工具
6.增加一个情况,如果唐僧过火焰山, 使用 飞机 ==> 程序扩展性, 我们前面的程序结构就非常好扩展 10min
使用代码实现上面的要求
编程 需求---->理解---->代码-->优化
 */


interface Vehicles {
    //有一个交通工具接口类Vehicles,有work接口
    public void work();
}

class Boat implements Vehicles {
    @Override
    public void work() {
        System.out.println(" 过河的时候,使用小船.. ");
    }
}

class Horse implements Vehicles {
    @Override
    public void work() {
        System.out.println(" 一般情况下,使用马儿前进...");
    }
}

class Plane implements Vehicles {
    @Override
    public void work() {
        System.out.println("过火焰山,使用飞机...");
    }
}

class VehiclesFactory {
    //马儿始终是同一匹
    private static Horse horse = new Horse(); //饿汉式

    private VehiclesFactory(){}
    //创建交通工具工厂类,有两个方法分别获得交通工具Horse和Boat
    //这里,我们将方法做成static
    public static Horse getHorse() {
//        return new Horse();
        return horse;
    }
    public static Boat getBoat() {
        return new Boat();
    }
    public static Plane getPlane() {
        return new Plane();
    }
}


class Person {
    private String name;
    private Vehicles vehicles;

    //在创建人对象时,事先给他分配一个交通工具
    public Person(String name, Vehicles vehicles) {
        this.name = name;
        this.vehicles = vehicles;
    }

    //实例化Person对象“唐僧”,要求一般情况下用Horse作为交通工具,遇到大河时用Boat作为交通工具
    //这里涉及到一个编程思路,就是可以把具体的要求,封装成方法-> 这里就是编程思想
    //思考一个问题,如何不浪费,在构建对象时,传入的交通工具对象->动脑筋
    public void passRiver() {
        //先得到船
        //判断一下,当前的 vehicles 属性是null, 就获取一艘船
//        Boat boat = VehiclesFactory.getBoat();
//        boat.work();
        //如何防止始终使用的是传入的马 instanceOf
        //if (vehicles == null) {
        //vehicles instanceof Boat 是判断 当前的 vehicles是不是Boat
        //(1) vehicles = null  : vehicles instanceof Boat  => false
        //(2) vehicles = 马对象 :vehicles instanceof Boat  => false
        //(3) vehicles = 船对象 :vehicles instanceof Boat  => true
        if (!(vehicles instanceof Boat)) {
            vehicles = VehiclesFactory.getBoat();
        }
        vehicles.work();
    }

    public void common() {
        //得到马儿
        //判断一下,当前的 vehicles 属性是null, 就获取一匹马
        //if (vehicles == null) {
        if (!(vehicles instanceof Horse)) {
            //这里使用的是多态
            vehicles = VehiclesFactory.getHorse();
        }
        //这里体现使用接口调用
        vehicles.work();
    }
    //过火焰山
    public void passFireHill() {
        if (!(vehicles instanceof Plane)) {
            //这里使用的是多态
            vehicles = VehiclesFactory.getPlane();
        }
        //这里体现使用接口调用
        vehicles.work();

    }
}

//有Person类,有name和Vehicles属性,在构造器中为两个属性赋值

注:这里通过一个类来获取不同的对象实例,在函数中调用该方法获得具体实现接口的实例,并赋给了接口类型引用(vehicles)在主函数调用时来实现动态绑定
并且这里有单例设计(饿汉式):由于马匹用的时同一对象,故用单例设计来实现这一功能,而船和飞机则调用一次创建一个新对象

42-面对对象编程(高级部分)2_第14张图片

package com.hspedu.homework;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Homework07 {
    public static void main(String[] args) {
        //实例化不同的car对象
        Car2 car2 = new Car2(60);
        car2.getAir().flow();
        Car2 car21 = new Car2(-1);
        car21.getAir().flow();
        Car2 car22 = new Car2(20);
        car22.getAir().flow();
    }
}
/*
有一个Car2类,有属性temperature(温度),车内有Air(空调)类,有吹风的功能flow,
Air会监视车内的温度,如果温度超过40度则吹冷气。如果温度低于0度则吹暖气,
如果在这之间则关掉空调。实例化具有不同温度的Car对象,调用空调的flow方法,
测试空调吹的风是否正确 . //体现 类与类的包含关系的案例 类(内部类【成员内部类】)

 */
class Car2 {

   private double temperature;

    public Car2(double temperature) {
        this.temperature = temperature;
    }

    //Air 成员内部类
   class Air {
       public void flow() {
           if(temperature > 40) {
               System.out.println("温度大于40 空调吹冷气..");
           } else if(temperature < 0) {
               System.out.println("温度小于0 空调吹暖气..");
           } else {
               System.out.println("温度正常,关闭空调..");
           }
       }
   }
   //返回一个Air对象
    public Air getAir() {
       return new Air();
    }
}

注:这里体现了类与内部类之间的联系:内部类通过外部类的属性(温度)来决定功能

42-面对对象编程(高级部分)2_第15张图片

package com.hspedu.homework;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Homework08 {
    public static void main(String[] args) {
        //演示一下枚举值得switch使用
        Color green = Color.GREEN;
        green.show();
        //比较一下
        //switch () 中,放入枚举对象
        //在每个case 后,直接写上在枚举类中,定义的枚举对象即可
        switch (green) {
            case YELLOW:
                System.out.println("匹配到黄色");
                break;
            case BLACK:
                System.out.println("匹配到黑色");
                break;
            default:
                System.out.println("没有匹配到..");
        }
    }
}

/*
枚举类
创建一个Color枚举类
1.有 RED,BLUE,BLACK,YELLOW,GREEN这个五个枚举值/对象;
2.Color有三个属性redValue,greenValue,blueValue,
3.创建构造方法,参数包括这三个属性,
4.每个枚举值都要给这三个属性赋值,三个属性对应的值分别是
red:255,0,0  blue:0,0,255  black:0,0,0  yellow:255,255,0  green:0,255,0
5.定义接口,里面有方法show,要求Color实现该接口
6.show方法中显示三属性的值
7. 将枚举对象在switch语句中匹配使用

 */
interface IMyInterface {
    public void show();
}

enum Color implements IMyInterface {
    RED(255, 0, 0), BLUE(0, 0, 255), BLACK(0, 0, 0), YELLOW(255, 255, 0), GREEN(0, 255, 0);
    private int redValue;
    private int greenValue;
    private int blueValue;

    Color(int redValue, int greenValue, int blueValue) {
        this.redValue = redValue;
        this.greenValue = greenValue;
        this.blueValue = blueValue;
    }

    @Override
    public void show() {
        System.out.println("属性值为" + redValue + "," + greenValue + "," + blueValue);
    }
}

注:这里注意以枚举对象为返回类型的switch-case的使用

最后

附上韩顺平老师这节内容的章节总结原视频有助于知识梳理

进度443/910 ,学习永无止境!!!

你可能感兴趣的:(java基础的学习,java,学习,接口)