跳到主要内容

第15章-内部类【扩展】

概述

  • 在Java中,还引入了一些其他特点的类
  • 内部类,主要是提供一种机制,使得类型封装的耦合度更高、隐藏性更好;比如在某个业务系统中一个HTTP请求的响应中,返回一个与业务响应紧密相关的特定类型的对象,这个类型脱离业务响应不会被使用,就可以定义成业务响应类的内部类
  • 类似人体与手臂的关系,手臂不能脱离于人体单独存在,一般就会在描述人体的地方描述手臂,并且手臂一般也不会应用在别的地方,因为只有人体有,其他的生物都叫四肢;这个手臂就相当于是人体的内部类
  • 这些类,后续课程中适当的场景,会有应用与讲解,先了解其规则即可

成员内部类

  • 定义于类内部,与属性、方法并列

  • 必须依托于外部类对象,才能创建内部类的对象

  • 在内部类中,可通过外部类名.this.xxx访问外部类对象的属性与方法

  • 应用相对较少,了解即可

  • 应用实例

    • 实例1,定义并使用成员内部类

      package com.bjpowernode.demo;

      /**
      * 内部类示例,成员内部类
      */
      public class OuterClass {
      //外部类属性
      public String outerName;

      //定义成员内部类
      public class InnerClass {
      //内部类属性
      public String innerName;

      /**
      * 内部类方法
      */
      public void innerMethod() {
      //访问外部类属性,方式:外部类名.this.属性名
      System.out.println("外部类对象outerName属性值:" + OuterClass.this.outerName);
      //访问内部类属性
      System.out.println("内部类对象innerName属性值:" + this.innerName);
      }
      }

      /**
      * 入口方法
      *
      * @param args
      */
      public static void main(String[] args) {
      //定义外部类对象
      OuterClass outerClass = new OuterClass();
      outerClass.outerName = "外部名称";

      //使用内部类,需要依托外部类对象,才能创建内部类对象
      InnerClass innerClass = outerClass.new InnerClass();
      //设置内部类属性
      innerClass.innerName = "内部名称";
      //调用内部内方法
      innerClass.innerMethod();
      }
      }

静态内部类

  • 定义于类内部,与属性、方法并列

  • 类前加static修饰,类似于静态属性和静态方法

  • 不再依托外部类对象,只依托于外部类的类型,来创建对象

  • 有一些业务场景中,某个类对象会跟随另外一个类对象产生而产生;比如登录类中的登录用户详细信息

  • 比如后续集合中的Map.Entry接口,就是Map接口的一个内部接口

  • 应用实例

    • 实例1,定义并使用静态内部类

      package com.bjpowernode.demo;

      /**
      * 内部类示例,静态内部类
      */
      public class OuterClass {
      //外部类属性
      public String outerName;

      //定义静态内部类
      public static class InnerClass {
      //内部类属性
      String innerName;

      /**
      * 内部类方法
      */
      public void innerMethod() {
      //访问内部类属性,没办法访问外部类普通属性,因为没有外部类对象
      System.out.println("内部类对象innerName属性值:" + this.innerName);
      }
      }

      /**
      * 入口方法
      *
      * @param args
      */
      public static void main(String[] args) {
      //使用静态内部类,需要依托外部类,才能创建内部类对象
      InnerClass innerClass = new OuterClass.InnerClass();
      //设置内部类属性
      innerClass.innerName = "内部名称";
      //调用内部内方法
      innerClass.innerMethod();
      }
      }

【练习】

  1. 练习应用实例内容,完成代码编写;重点练习静态内部类

局部内部类

  • 定义于方法中,只在方法所在作用域中有效

  • 应用相对较少,了解即可

  • 应用实例

    • 实例1,定义并使用局部内部类

      package com.bjpowernode.demo;

      /**
      * 内部类示例,局部内部类
      */
      public class OuterClass{
      /**
      * 生成数据
      */
      public void generateData() {
      //定义局部内部内,辅助生成数据,该类只在当前方法有效,且不能有访问修饰符
      class GenerateUtil {
      //URL前缀
      String urlPrefix;

      public String getUrlPrefix() {
      return urlPrefix;
      }

      public void setUrlPrefix(String urlPrefix) {
      this.urlPrefix = urlPrefix;
      }

      //获取完整URL
      public String getFullURL(String path) {
      return this.urlPrefix + path;
      }
      }

      //使用局部内部类
      GenerateUtil generateUtil = new GenerateUtil();
      generateUtil.urlPrefix = "http://www.bjpowernode.com";
      String fullUrl = generateUtil.getFullURL("/api/account/login");

      System.out.println("完整URL:" + fullUrl);
      }

      /**
      * 入口方法
      *
      * @param args
      */
      public static void main(String[] args) {
      //使用具有局部内部类的方法
      OuterClass outerClass = new OuterClass();
      outerClass.generateData();
      }
      }

匿名内部类

  • 当某个类的定义时,具备如下两个特点,可使用匿名内部类

    • 该类只在某个业务点使用,后续无需重复使用
    • 该类将从已有的类、接口派生(继承),即具备父类
  • 应用广泛,在后续课程的函数式编程、项目应用中,都会使用

  • 应用实例

    • 应用实例1,使用抽象类定义匿名类;如:生物学家发现了一个新的动物物种,需要描述一次其特性并使用一次,可基于抽象类(普通类也一样)定义匿名类

      • 抽象类

        package com.bjpowernode.demo;

        /**
        * 动物类,【抽象类】
        */
        public abstract class Animal {
        //名称
        private String name;

        //getter/setter,同时也是【普通方法】(非抽象方法),有具体实现
        public String getName() {
        return name;
        }
        public void setName(String name) {
        this.name = name;
        }

        /**
        * 吃东西,【抽象方法】,没有具体实现
        * @param foodName 食物名称
        */
        public abstract void eatFood(String foodName);

        /**
        * 发声,【抽象方法】,没有具体实现
        */
        public abstract void sound();
        }
      • 匿名类

        package com.bjpowernode.demo;

        /**
        * 动物测试类
        */
        public class AnimalTest {
        /**
        * 入口方法
        * @param args
        */
        public static void main(String[] args) {
        //定义匿名类,定义一个未知动物
        Animal anonymous = new Animal() {
        @Override
        public void eatFood(String foodName) {
        System.out.println("未知动物" + this.getName() + "吃了" + foodName);
        }

        @Override
        public void sound() {
        System.out.println("未知动物" + this.getName() + "在叫,シ王;忹...");
        }
        };

        //使用匿名类
        anonymous.setName("火星二号");
        anonymous.eatFood("料-->炓");
        anonymous.sound();
        }
        }
    • 应用实例2,使用接口定义匿名类

      • 接口

        package com.bjpowernode.demo;

        /**
        * 工具
        */
        public interface ITool {
        /**
        * 使用工具
        * @param toolName 工具名称
        */
        void userTool(String toolName);
        }
      • 匿名类

        package com.bjpowernode.demo;

        /**
        * 工具测试类
        */
        public class ToolDemo {
        /**
        * 入口方法
        *
        * @param args
        */
        public static void main(String[] args) {
        //定义匿名类,定义一个未知工具使用
        ITool anonymous = new ITool() {
        @Override
        public void userTool(String toolName) {
        System.out.println("某人使用了工具:" + toolName + ",他眼里都是钉子...");
        }
        };

        //使用匿名类
        anonymous.userTool("锤子");
        }
        }

【练习】

  1. 练习应用实例内容,完成代码编写;重点练习匿名类

实战和作业

  1. 【扩展】重构程序,使用第13章重构后的Animal项目,做如下重构
    1. 使用工具类接口ITool,定义匿名工具类,并测试使用工具方法
    2. 使用动物类Animal,定义匿名类未知动物类,并测试吃东西、发声方法
    3. 使用鸟类Bird,定义匿名类未知鸟类,并测试吃东西、发声方法