内部类

Posted zachyoung

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内部类相关的知识,希望对你有一定的参考价值。

内部类( Nested Class )

1、概念:

按是否是成员来划分

  • 嵌套类( Nested Class )

    • 静态嵌套类

    • 实例内部类

  • 局部类 ( Local Class )

    • 局部内部类

    • 匿名内部类

 

 package InnerClass;
 // Computer 是个外部类 它对应的 字节码文件是 Computer.class
 public class Computer {
 ?
     // 直接在 外部类 的 类体括号中声明的 类 就是 嵌套类 ( Nested Class )
     // 嵌套类 也被称作 成员内部类
 ?
     // 有 static 修饰的 嵌套类 也被称作 静态嵌套类 或 静态内部类
     static class Brand {
 ?
         // 对应的字节码文件名称 Computer$Brand.class
 ?
    }
 ?
     // 没有 static 修饰的 被称作 非静态嵌套类 或 非静态内部类 或 实例嵌套类 或 实例内部类
     class Mainboard { // 主板
         // 对应的字节码文件名称 Computer$Mainboard.class
    }
 ?
     public void show() {
         // 局部类
         class Printer {
             // 对应的字节码文件名称 Computer$1Printer.class
        }
 ?
         Printer printer = new Printer();
         // ........
 ?
    }
     public void welcome() {
         // 匿名内部类
         Object object = new Object(){
 ?
        };
         System.out.println(object.getClass());
    }
 ?
 }
 ?

 

 

2、声明方式

 

静态内部类

对于嵌套类来说 使用 外部类类名.内部类类名 来 指定变量类型

Computer.Brand = new ComputerBrand();

 

实例内部类

Computer.Mainboard mainboard = new Computer().new Mainboard();

 

对于局部类来说 只能在其作用域内部直接使用其类名来声明

 

 

 

3、字节码文件

嵌套类字节码文件名称 外部类名称$嵌套类名称.class

Computer$Brand.class

 

 

局部类字节码文件名称 外部类$N局部类名称.class

Computer$1Printer.class

 

4、匿名内部类

  • 不能显式指定类名

  • 不能显式声明构造方法

  • 但是创建匿名类时,的确会调用父类指定的构造方法

 

5、匿名内部类的作用

  • 使用匿名类 实现接口 并创建该类的实例 【最常见的应用】

 

 package InnerClass;
 ?
 /**
  * 1、使用匿名类 实现接口 并创建该类的实例 【最常见的应用】
  * */
 public class AnnoymousClassTest {
     public static void main(String[] args) {
 ?
         // 声明 Flyable 类型的引用变量 并赋予 null
         Flyable f = null; // 编译时类型 Flyable
 ?
         // f = new Flyable(); // 接口都没有构造方法 不能实例化
         // 形式上 似乎是通过 new 关键字 创建 Flyable 接口的 实例【尸体】
         // 本质上 创建了一个实现了 Flyable 接口的匿名类的实例 【借尸还魂】
 ?
         f = new Flyable() { // 匿名类开始 【魂】
             @Override
             public void fly() {
                 System.out.println("匿名内部类");
            }
        }; // 匿名类结束
 ?
         f.fly();
         Class<? extends Flyable> c = f.getClass();
         System.out.println(c.getName()); // 全限定名称
         System.out.println(c.getCanonicalName()); // 规范化类名 这里是 null
 ?
         Class<?> superclass = c.getSuperclass();
         System.out.println(superclass); // 父类 Object
         Class<?>[] interfaces = c.getInterfaces();
         for (Class<?> inter : interfaces) {
             System.out.println(inter);
        }
 ?
    }
 }
 ?

 

  • 创建继承了某个抽象类并实现了所有抽象方法的匿名类实例

 

 package InnerClass;
 ?
 /**
  * 1、创建继承了某个抽象类并实现了所有抽象方法的匿名类实例
  * */
 public class AnnoymousClassTest2 {
     public static void main(String[] args) {
 ?
         Human h = null;
 ?
         // h = new Human(); // 抽象类有构造 但不能实例化
 ?
 ?
         h = new Human("张三"){ // 没有无参构造
             @Override
             public void eat(String food) {
                 System.out.println(this.name + "吃" + food);
            }
        };
 ?
         h.eat("西瓜");
 ?
    }
 }
 ?

 

  • 创建继承了某个具体类的匿名类实例

 package InnerClass;
 ?
 /**
  * 1、创建继承了某个具体类的匿名类实例
  * 2、可以在匿名类中重写被继承类中的方法
  * */
 public class AnonymousClassTest3 {
     public static void main(String[] args) {
 ?
         Aircraft a = new Aircraft();
         a.fly();
         a.travel();
 ?
         System.out.println("~~~~~~~~~~~");
 ?
         Aircraft b = new Aircraft(){};
         System.out.println(b.getClass());
 ?
         Aircraft c = new Aircraft(){
             // 在匿名类中声明实例变量
             String name = "航天飞机";
             @Override
             public void fly() {
                 System.out.println("匿名类fly" + this.name);
            }
        };
 ?
         c.fly();
    }
 }
 ?

 

  • 创建继承了某个具体类的匿名类实例

 

 package InnerClass;
 ?
 import java.lang.reflect.Constructor;
 ?
 /**
  * 1、创建继承了某个具体类的匿名类实例
  * 2、可以在匿名类中重写被继承类中的方法
  * */
 public class AnonymousClassTest4 {
     public static void main(String[] args) {
 ?
         Cloneable c = new Cloneable() {
             // 什么都不写
        };
         System.out.println(c);
 ?
         Class<?> clazz = c.getClass();
 ?
         Constructor<?>[] constructors = clazz.getConstructors();
 ?
         for (Constructor<?> constructor : constructors) {
             System.out.println(constructor);
        }
 ?
    }
 }
 ?

 

6、手机类测试内部类

 

在实例内部类中 可以使用 外部类类名.this 来引用 外部类的当前实例

 

 package InnerClass;
 ?
 ?
 public class CellPhone {
 ?
     public String brand = "华为";
 ?
     public class Screen {
 ?
         String brand = "京东方";
         public void show() {
             // 在实例内部类中 使用 this 表示当前类的当前实例 Screen的 实例
             System.out.println("外部:" + CellPhone.this.brand + "内部:" + this.brand);
        }
 ?
         public CellPhone getOuter() {
             // 在 实例内部类中 可以使用 外部类类名.this 来引用 外部类的当前实例
             return CellPhone.this;
        }
 ?
    }
 ?
 }

 

 package InnerClass;
 ?
 public class CellPhoneTest {
     public static void main(String[] args) {
         // 引用 cellphone 指向了 CellPhone 类型的实例
         // CellPhone cellPhone = new CellPhone();
 ?
         // screen 指向 Screen 实例
         // CellPhone.Screen screen = new CellPhone().new Screen();
 ?
         // 创建 实力内部类的实例
         CellPhone.Screen screen = new CellPhone().new Screen();
         System.out.println(screen);
 ?
         screen.show();
 ?
         System.out.println(screen.brand);
 ?
         CellPhone cellPhone = screen.getOuter();
         System.out.println(cellPhone);
 ?
 ?
    }
 }

 

以上是关于内部类的主要内容,如果未能解决你的问题,请参考以下文章

片段 - 全局视图变量与本地和内部类侦听器和内存泄漏

为啥片段类应该是公开的?

ForegroundService没有从片段开始?

在内部片段类中使用ListView

自定义无内存泄漏的Handler内部类

底部导航 如何从片段内部更改片段