zoukankan      html  css  js  c++  java
  • java 内部类

    1. 简介

    在 Java 中可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:

    成员内部类、局部内部类、匿名内部类和静态内部类。

    2. 优点

    在程序设计中有时会存在一些使用接口很难解决的问题,此时可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决。

    可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。

    使用内部类可以使程序拥有以下特性:

    1)内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立;

    2)在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类;

    3)创建内部类对象的时刻并不依赖于外部类对象的创建;

    4)内部类并没有令人迷惑的“is-a”关系,它就是一个独立的实体;

    5)内部类提供了更好的封装,除了该外部类,其他类都不能访问;

    3. 示例

    3.1 成员内部类

    3.1.1 成员内部类的修饰符和实例化

    成员内部类可以看作是外部类的一个成员,它有以下注意点:

    1)成员内部类不能使用static关键字;

    2)成员内部类的实例化:成员内部类依赖于外部类,因此必须在外部类实例化后内部类才能实例化。

    注:上述条件说明在外部类的非静态方法中可以实例化内部类(要访问外部类的实例方法,先要有外部类对象,满足上述条件);

    或者在外部类的静态方法中先实例化外部类,再实例化内部类。

     1 public class OuterClass1 {
     2 
     3     class InnerClass{
     4         //private static int innerVar = 1;         // 成员内部类不能使用静态成员变量
     5         //private static void innerMethod(){ }     // 成员内部类不能使用静态方法
     6     }
     7 
     8     public void outMethod(){
     9         InnerClass in = new InnerClass();      // 在外部类的非静态方法中直接实例化内部类
    10     }
    11 
    12     public static void main(String[] args){
    13         //InnerClass in = new InnerClass();       // 在外部类的静态方法中不能直接实例化内部类
    14 
    15         // 先创建外部类对象后才能创建内部类对象
    16         OuterClass1 out = new OuterClass1();
    17         OuterClass1.InnerClass in = out.new InnerClass();
    18         // 外部类的非静态方法之所以可以创建内部类对象,是由于要访问外部类的非静态方法,必须通过外部类的对象访问,
    19         // 此时已经创建了外部类对象,满足了先外部对象,再内部对象的条件
    20         out.outMethod();
    21     }
    22 }

    3.1.2 成员内部类访问外部类

     成员内部类在访问外部类时,它有以下注意事项:

    1)成员内部类访问外部类的非同名成员变量和方法:直接调用即可;

    2)成员内部类访问外部类的同名成员变量和方法:外部类.this.成员变量 / 外部类.this.成员方法;

    注:无论外部类的成员变量和方法是否使用private修饰皆可访问。

     1 public class OuterClass2 {
     2     private String outVar1 = "outVar1";
     3     private static String outVar2 = "outVar2";
     4     private String outVar3 = "outVar3";
     5 
     6     private void outerMethod(){
     7         System.out.println("outerMethod with same name of OuterClass");
     8     }
     9 
    10     private void outerMethod1(){
    11         System.out.println("outerMethod of OuterClass");
    12     }
    13 
    14     private static void outerMethod2(){
    15         System.out.println("static outerMethod of OuterClass");
    16     }
    17 
    18     class InnerClass{
    19         private String outVar3 = "innerVar3";
    20 
    21         private void outerMethod(){
    22             System.out.println("outerMethod with same name of InnerClass");
    23             System.out.println(outVar1);                      // 访问外部类成员变量
    24             System.out.println(outVar2);                      // 访问外部类静态成员变量
    25             System.out.println(OuterClass2.this.outVar3);     // 访问外部类同名成员变量
    26         }
    27 
    28         public void innerMethod(){
    29             outerMethod();                       // 访问自身的同名方法
    30             OuterClass2.this.outerMethod();      // 访问外部类的同名方法
    31             outerMethod1();                      // 访问外部类的实例方法
    32             outerMethod2();                      // 访问外部类的静态方法
    33         }
    34     }
    35 
    36     public static void main(String[] args){
    37         OuterClass2 out = new OuterClass2();
    38         OuterClass2.InnerClass in = out.new InnerClass();
    39         in.innerMethod();
    40     }
    41 }

    运行结果如下:

    1 outerMethod with same name of InnerClass
    2 outVar1
    3 outVar2
    4 outVar3
    5 outerMethod with same name of OuterClass
    6 outerMethod of OuterClass
    7 static outerMethod of OuterClass

    3.1.3 外部类访问成员内部类

    外部类在访问成员内部类时,它有以下注意事项:

    1)外部类访问成员内部类时必须通过内部类的对象访问;

     1 public class OuterClass3 {
     2 
     3     class InnerClass{
     4         private String innerVar1 = "innerVar1";
     5 
     6         private void outerMethod1(){
     7             System.out.println("outerMethod with same name of InnerClass");
     8         }
     9     }
    10 
    11     private void outerMethod1(){
    12         System.out.println("outerMethod with same name of OuterClass");
    13         InnerClass in = new InnerClass();      // 通过内部类对象访问内部类的成员变量和方法
    14         System.out.println(in.innerVar1);
    15         in.outerMethod1();
    16     }
    17 
    18     private static void outerMethod2(){
    19         System.out.println("static method with same name of OuterClass");
    20        // InnerClass in = new InnerClass();      // error
    21         OuterClass3 out = new OuterClass3();     // 通过内部类对象访问内部类的成员变量和方法
    22         OuterClass3.InnerClass in = out.new InnerClass();
    23         in.outerMethod1();
    24     }
    25 
    26     public static void main(String[] args){
    27         OuterClass3 out = new OuterClass3();
    28         out.outerMethod1();
    29         outerMethod2();
    30     }
    31 }

    运行结果如下:

    1 outerMethod with same name of OuterClass
    2 innerVar1
    3 outerMethod with same name of InnerClass
    4 static method with same name of OuterClass
    5 outerMethod with same name of InnerClass

    3.2 静态内部类

    3.2.1 静态内部类的说明和使用

    静态内部类指使用static关键字修饰的内部类。非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外部类,

    静态内部类却没有该引用,这是因为静态内部类是类级别的属性,不需要对象的引用(this)来调用。

    它的特点如下:

    0)加载外部类时不会直接加载静态内部类,当且仅当静态内部类的静态成员(静态域、构造器、静态方法等)被调用时才会加载;

    1)静态内部类的对象创建不依赖于外部类;

    2)静态内部类不能使用外部类的任何非静态成员变量和方法,只能访问静态成员变量和方法;

    3)外部类可以通过类名.xx直接访问静态内部类的静态方法;

     1 public class OuterClass4 {
     2     private String outVar1 = "outVar1";
     3     private static String outVar2 = "outVar2";
     4     private static String outVar3 = "outVar3";
     5 
     6     public void outMethod1(){
     7         InnerClass in = new InnerClass();
     8         System.out.println(in.outVar3);
     9     }
    10 
    11     private static void outMethod2(){
    12     }
    13 
    14     private static void outMethod3(){
    15         System.out.println(InnerClass.outVar4);          // 可以直接访问静态内部类的静态变量和方法
    16         InnerClass in = new InnerClass();
    17         in.innerMethod();
    18         System.out.println(in.outVar3);                  // 可以通过内部类对象访问实例变量和方法
    19     }
    20 
    21     static class InnerClass {
    22         private String outVar3 = "innerVar3";
    23         private static String outVar4 = "innerVar4";
    24 
    25         public InnerClass(){
    26 //            System.out.println(outVar1);              // 不能访问外部类的非静态变量
    27             System.out.println(outVar2);                // 可以访问外部类的静态变量
    28             System.out.println(OuterClass4.outVar3);   //  可以访问外部类的同名静态变量
    29 
    30             //outMethod1();            // 不能访问外部类的非静态方法
    31             outMethod2();              // 可以访问外部类的静态方法
    32         }
    33 
    34         public void innerMethod(){
    35         }
    36     }
    37 
    38     public static void main(String[] args){
    39         InnerClass in = new InnerClass();       // 可以直接创建内部类对象
    40         System.out.println(in.outVar3);
    41 
    42         OuterClass4 out = new OuterClass4();
    43         out.outMethod1();
    44         outMethod3();
    45     }
    46 }

     运行结果如下:

     1 outVar2
     2 outVar3
     3 innerVar3
     4 outVar2
     5 outVar3
     6 innerVar3
     7 innerVar4
     8 outVar2
     9 outVar3
    10 innerVar3

    3.3 局部内部类

    3.3.1局部内部类的说明和使用

    局部内部类是定义在一个方法或者作用域中的类,它的使用仅限于其方法或者作用域内,出了方法和作用域就会失效,类似于局部变量。其特点如下:

    1)局部内部类是定义在一个方法或者作用域中的类,它的访问权限仅限于其方法或者作用域内;

    2)局部内部类类似方法和作用域中的局部变量,不能使用权限访问修饰符和static关键字修饰;

     1 class Animal{ }
     2 
     3 public class OuterClass5 {
     4 
     5     // 在方法中使用局部内部类
     6     private Animal getDog(){
     7         class Dog extends Animal{
     8         }
     9         return new Dog();
    10     }
    11 
    12     // 在作用域中使用局部内部类
    13     private Animal getCat(boolean flag){
    14         if(flag){
    15             class Cat extends Animal{
    16             }
    17             return new Cat();
    18         }
    19         return null;
    20     }
    21 
    22     public static void main(String[] args){
    23         OuterClass5 out = new OuterClass5();
    24         Animal a1 = out.getDog();
    25         Animal a2 = out.getCat(true);
    26         System.out.println(a1);
    27         System.out.println(a2);
    28     }
    29 }

    运行结果如下:

    1 InnerClass.OuterClass5$1Dog@6d6f6e28
    2 InnerClass.OuterClass5$1Cat@135fbaa4

    3.4 匿名内部类

    3.4.1 匿名内部类的说明

    匿名内部类即是没有名称的内部类它的使用前提和特点如下:

    1)使用匿名内部类需要继承父类或者实现一个接口;

    2)匿名内部类不能使用访问修饰符修饰;

    3)匿名内部类不能是抽象类,因为在使用它时会直接创建该类的对象;

    4)匿名内部类不能定义构造器因为该类没有类名;

    3.4.2 未在抽象类和接口上使用匿名内部类

    对于一个抽象类和接口,通常需要使用一个类继承或实现它们,然后再实现其内部的方法,最后使用它。例如:

     1 abstract class Parent{
     2     abstract int getNumber(int n);
     3 }
     4 
     5 class Child extends Parent{
     6     @Override
     7     int getNumber(int n) {
     8         return n;
     9     }
    10 }
    11 
    12 public class Demo {
    13     public static void main(String[] args){
    14         Parent p = new Child();
    15         System.out.println(p.getNumber(2));
    16     }
    17 }

    3.4.3 抽象类上使用匿名内部类

    对于上述抽象类Parent,我们显示地定义了一个Child类继承它并且重写了其方法,有什么方法可以不写这个Child类呢?

    这里引入匿名内部类即可,例如以下示例:

     1 abstract class Parent {
     2     abstract int getNumber(int n);
     3 }
     4 
     5 public class Demo1 {
     6     public static void main(String[] args){
     7         Parent p = new Parent() {           // 注意,这里使用了匿名内部类 
     8             @Override
     9             public int getNumber(int n) {
    10                 return n;
    11             }
    12         };
    13         System.out.println(p.getNumber(2));
    14     }
    15 }

    3.4.4 在接口上使用匿名内部类

     1 interface Parent {
     2     int getNumber(int n);
     3 }
     4 
     5 public class Demo2 {
     6     public static void main(String[] args){
     7         // 直接使用
     8         Parent p1 = new Parent() {     // 没有出现类名
     9             @Override
    10             public int getNumber(int n) {
    11                 return n;
    12             }
    13         };
    14         System.out.println(p1.getNumber(2));
    15 
    16         // 使用Lambda表达式
    17         Parent1 p2 = n -> n;
    18         System.out.println(p2.getNumber(2));
    19     }
    20 }

    4. 参考文献

    https://www.runoob.com/w3cnote/java-inner-class-intro.html

    https://www.cnblogs.com/nerxious/archive/2013/01/25/2876489.html

    https://blog.csdn.net/guyuealian/article/details/51981163

    https://www.cnblogs.com/chenssy/p/3388487.html

    !!!

  • 相关阅读:
    Java排序算法之堆排序
    servlet学习总结(一)——HttpServletRequest(转载)
    servlet学习总结(一)——初识Servlet
    Java排序算法之快速排序
    Java排序算法之直接选择排序
    第八课、泛型编程简介
    第六课、算法效率的度量
    第四课、程序灵魂的审判
    第三课、初识程序的灵魂------------------------狄泰软件学院
    用solidity语言开发代币智能合约
  • 原文地址:https://www.cnblogs.com/jfl-xx/p/11599759.html
Copyright © 2011-2022 走看看