0
点赞
收藏
分享

微信扫一扫

day14_模板设计模式丶内部类丶引用类型使用小结

盖码范 2022-03-20 阅读 91

模板设计模式

概述:

  • 设计模式就是解决一些问题时的固定思路,也就是代码设计思路经验的总结。模板设计模式概述:针对某些情况,在父类中指定一个模板,然后根据具体情况,在子类中灵活的具体实现该模板
public abstract class Person{
    // 有方法体的方法: 通用模板
    public void sleep(){
        System.out.println("两眼一闭,就睡觉...");
    }
    
    // 没有方法体的方法(抽象方法):  填充模板(要子类重新实现的)
   public abstract void eat();
}

抽象类体现的就是模板设计思想,模板是将通用的东西在抽象类中具体的实现,而模板中不能决定的东西定义成抽象方法,让使用模板(继承抽象类的类)的类去重写抽象方法实现需求

模板模式的实现步骤

  1. 定义抽象父类作为模板
  2. 在父类中定义"模板方法":现方法(通用模板)+抽象方法(填充模板)
  3. 子类继承父类,重写抽象方法(填充父类的模板)
  4. 创建子类对象,通过子类调用父类的“实现的方法”+ “子类重写后的方法” 

案例:假如我现在需要定义新司机和老司机类,新司机和老司机都有开车功能,开车的步骤都一样,只是驾驶时的姿势有点不同,那么这个时候我们就可以将固定流程写到父类中,不同的地方就定义成抽象方法,让不同的子类去重写

代码示例

//父类
abstract class Driver {
    //具体模板,开车方法
    public void driveCar() {
        System.out.println("开车门,点火");
        //填充模板
        posture();
        System.out.println("熄火,下车");
    }

    //填充模板
    protected abstract void posture();
}

//新司机
class NewDriver extends Driver {

    @Override
    protected void posture() {
        System.out.println("小心翼翼的开车");
    }
}

//老司机
class OldDriver extends Driver {

    @Override
    protected void posture() {
        System.out.println("放飞自我的开车");
    }
}

public class Test {
    public static void main(String[] args) {
        // 创建新司机对象,调用开车的方法
        new NewDriver().driveCar();
        // 创建老司机对象,调用开车的方法
        new OldDriver().driveCar();
    }
}

内部类

什么是内部类?

  • 将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类

为什么要声明内部类呢?

  • 当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,不在其他地方单独使用,那么整个内部的完整结构最好使用内部类。而且内部类因为在外部类的里面,因此可以直接访问外部类的私有成员

内部类都有哪些形式

  • 静态成员内部类
  • 非静态成员内部类
  • 有名字的局部内部类
  • 匿名的内部类

静态内部类

静态内部类的特点:

和其他类一样,它只是定义在外部类中的另一个完整的类结构

  • 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
  • 可以在静态内部类中声明属性、方法、构造器等结构,包括静态成员
  • 可以使用abstract修饰,因此它也可以被其他类继承
  • 可以使用final修饰,表示不能被继承
  • 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和$符号。

和外部类不同的是,它可以允许四种权限修饰符:public,protected,缺省,private

  • 外部类只允许public或缺省的
  • 可以在静态内部类中使用外部类的静态成员
  • 在静态内部类中不能使用外部类的非静态成员哦
  • 在外部类的外面不需要通过外部类的对象就可以创建静态内部类的对象
  • 如果在内部类中有变量与外部类的静态成员变量同名,可以使用“外部类名."进行区别

 非静态成员内部类

非静态内部类的特点:

  • 和其他类一样,它只是定义在外部类中的另一个完整的类结构
  • 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
  • 可以在非静态内部类中声明属性、方法、构造器等结构,但是不允许声明静态成员,但是可以继承父类的静态成员,而且可以声明静态常量
  • 可以使用abstract修饰,因此它也可以被其他类继承
  • 可以使用final修饰,表示不能被继承
  • 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和$符号。

和外部类不同的是,它可以允许四种权限修饰符:public,protected,缺省,private

  • 外部类只允许public或缺省的
  • 还可以在非静态内部类中使用外部类的所有成员,哪怕是私有的
  • 在外部类的静态成员中不可以使用非静态内部类哦
  • 就如同静态方法中不能访问本类的非静态成员变量和非静态方法一样
  • 在外部类的外面必须通过外部类的对象才能创建非静态内部类的对象
  • 因此在非静态内部类的方法中有两个this对象,一个是外部类的this对象,一个是内部类的this对象

创建内部类对象格式:

代码示例

package demo08;

 class Body {

    public void methodW1(){
        // 访问内部类的成员
        //Body.Heart bh = new Body().new Heart();
        Heart bh = new Heart();
        System.out.println(bh.numN);// 10
        bh.methodN1();// 内部类的成员方法 methodN1
    }

    // 成员变量
    private int numW = 100;

    // 成员方法
    private void methodW2(){
        System.out.println("外部类的成员方法 methodW2");
    }


    // 内部类
    public class Heart{
        // 成员变量
        int numN = 10;

        // 成员方法
        public void methodN1(){
            System.out.println("内部类的成员方法 methodN1");
        }

        public void methodN2(){
            // 访问外部类的成员
            System.out.println(numW);
            methodW2();
        }
    }


}


public class Test {
    public static void main(String[] args) {
        /*
            - 什么是内部类:将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,外面的那个B类则称为外部类。
            - 成员内部类的格式:
                 public class 外部类{
                     public class 内部类{

                    }
                 }
            - 成员内部类的访问特点:
                在其他类中,访问内部类的成员,得先创建内部类对象:
                    外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
                在外部类中,访问内部类的成员,得先创建内部类对象:
                    外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
                    内部类名 对象名 = new 内部类名();

                在内部类中,可以直接访问外部类的一切成员(包含私有的):

         */
        // 创建内部类的对象
        Body.Heart bh = new Body().new Heart();
        System.out.println(bh.numN);// 10
        bh.methodN1();// 内部类的成员方法 methodN1

        System.out.println("=======================");
        // 创建外部类对象
        Body b = new Body();
        b.methodW1();

        System.out.println("=======================");
        bh.methodN2();// 100    外部类的成员方法 methodW2

    }
}

 局部内部类

局部内部类的特点:

和外部类一样,它只是定义在外部类的某个方法中的另一个完整的类结构

  • 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
  • 可以在局部内部类中声明属性、方法、构造器等结构,但不包括静态成员,除非是从父类继承的静态常量
  • 可以使用abstract修饰,因此它也可以被同一个方法的在它后面的其他内部类继承
  • 可以使用final修饰,表示不能被继承

编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、$符号、编号。

  • 这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类
  • 和成员内部类不同的是,它前面不能有权限修饰符等
  • 局部内部类如同局部变量一样,有作用域
  • 局部内部类中是否能访问外部类的静态还是非静态的成员,取决于所在的方法
  • 局部内部类中还可以使用所在方法的局部常量,即用final声明的局部变量。JDK1.8之后,如果某个局部变量在局部内部类中被使用了,自动加final

 代码示例

class Outer {
    private static int a = 1;
    private int b = 2;

    public static void outMethod() {
        final int c = 3;
        class Inner {
            public void inMethod() {
                System.out.println("out.a = " + a);
//				System.out.println("out.b = " + b);//错误的,因为outMethod是静态的
                System.out.println("out.local.c = " + c);
            }
        }

        Inner in = new Inner();
        in.inMethod();
    }

    public void outTest() {
        final int c = 3;
        class Inner {
            public void inMethod() {
                System.out.println("out.a = " + a);
                System.out.println("out.b = " + b);//可以,因为outTest是非静态的
                System.out.println("method.c = " + c);
            }
        }

        Inner in = new Inner();
        in.inMethod();
    }

}

匿名内部类

当我们在开发过程中,需要用到一个抽象类的子类的对象或一个接口的实现类的对象,而且只创建一个对象,而且逻辑代码也不复杂。那么我们原先怎么做的呢?

  1. 编写类,继承这个父类或实现这个接口
  2. 重写父类或父接口的方法
  3. 创建这个子类或实现类的对象

这里,因为考虑到这个子类或实现类是一次性的,那么我们“费尽心机”的给它取名字,就显得多余。那么我们完全可以使用匿名内部类的方式来实现,避免给类命名的问题。

语法格式

注意事项:

匿名内部类是一种特殊的局部内部类,只不过没有名称而已。所有局部内部类的限制都适用于匿名内部类。例如:

  • 在匿名内部类中是否可以使用外部类的非静态成员变量,看所在方法是否静态
  • 在匿名内部类中如果需要访问当前方法的局部变量,该局部变量需要加final

这个对象能做什么呢?

  • (1)调用某个方法(2)赋值给父类/父接口的变量,通过多态引用使用这个对象(3)作为某个方法调用的实参

 代码示例

package demo09;

interface A {
    public abstract void show();
}

class Imp implements A {
    public void show() {
        System.out.println("实现类实现show方法");
    }
}

public class Test {
    public static void main(String[] args) {
        /*
            匿名内部类:
                概述:本质是一个接口的匿名实现类的对象
                格式:
                    new 接口名(){
                        实现抽象方法
                    };
         */
        // 需求:调用A接口的show方法
        // 1.创建实现类实现A接口
        // 2.在实现类中重写show方法
        // 3.创建实现类对象
        // 4.使用实现类对象调用show方法
        Imp imp = new Imp();// imp就是接口的实现类的对象
        imp.show();

        System.out.println("==============================");
        // 简化: 匿名内部类
        A a = new A() {
            @Override
            public void show() {
                System.out.println("匿名内部类");
            }
        };
        a.show();
    }
}

引用类型使用小结

基本类型可以作为成员变量、作为方法的参数、作为方法的返回值,那么当然引用类型也是可以的。

  • 类名作为方法参数: 可以直接传入该类的对象或者子类对象
  • 类名作为方法返回值:可以直接返回该类的对象或者子类对象
  • 抽象类作为方法参数:表示可以接收任何此抽象类的"子类对象"作为实参
  • 抽象类作为方法返回值:表示此方法可以返回此抽象类的任何子类对象
  • 接口作为方法参数:表示可以接收任何此接口实现类对象作为实参
  • 接口作为方法返回值:表示此方法可以返回此接口任何实现类的对象
  • 类作为成员变量:对它进行赋值的操作,实际上,是赋给它该类的一个对象或者子类对象。
  • 抽象类作为成员变量 :为此成员变量赋值时,可以是任何它的子类对象
  • 接口作为成员变量:为此成员变量赋值时,可以是任何它的实现类对象
举报

相关推荐

0 条评论