📜  Java内部类

📅  最后修改于: 2020-04-06 04:11:36             🧑  作者: Mango

内部类是指一个类,是另一个类的成员。在Java中,内部类基本上有四种类型。
1)嵌套内部类
2)方法局部内部类
3)匿名内部类
4)静态嵌套类
嵌套的内部类可以访问外部类的任何私有实例变量。像任何其他实例变量一样,我们可以将访问修饰符设置为private,protected,public和default修饰符。
像类一样,接口也可以嵌套并且可以具有访问说明符。
以下示例演示了一个嵌套类。

class Outer {
   // 简单的嵌套内部类
   class Inner {
      public void show() {
           System.out.println("一个嵌套类的方法");
      }
   }
}
class Main {
   public static void main(String[] args) {
       Outer.Inner in = new Outer().new Inner();
       in.show();
   }
}

输出:

一个嵌套类的方法

附带说明一下,我们不能在嵌套的内部类中使用静态方法,因为内部类与它的外部类的对象隐式关联,因此它不能为其自身定义任何静态方法。例如,以下程序无法编译。

class Outer {
   void outerMethod() {
      System.out.println("在outerMethod内");
   }
   class Inner {
      public static void main(String[] args){
         System.out.println("内部类方法");
      }
   }
}

输出:

Error illegal static declaration in inner class
Outer.Inner public static void main(String[] args)
modifier ‘static’ is only allowed in constant
variable declaration

接口也可以是嵌套的,并且嵌套接口具有一些有趣的属性。在下一篇文章中,我们将介绍嵌套接口。

方法局部内部类
内部类可以在外部类的方法中声明。在下面的示例中,Inner是externalMethod()中的内部类。

class Outer {
    void outerMethod() {
        System.out.println("在outerMethod内");
        // 内部类是outerMethod()的
        class Inner {
            void innerMethod() {
                System.out.println("在innerMethod内");
            }
        }
        Inner y = new Inner();
        y.innerMethod();
    }
}
class MethodDemo {
    public static void main(String[] args) {
        Outer x = new Outer();
        x.outerMethod();
    }
}

输出

在outerMethod内
在innerMethod内

方法局部内部类不能使用外部方法的局部变量,除非该局部变量未声明为final。例如,以下代码生成编译器错误(请注意,x在externalMethod()中不是final,而innerMethod()尝试访问它)

class Outer {
   void outerMethod() {
      int x = 98;
      System.out.println("在outerMethod内");
      class Inner {
         void innerMethod() {
            System.out.println("x= "+x);
         }
      }
      Inner y = new Inner();
      y.innerMethod();
   }
}
class MethodLocalVariableDemo {
   public static void main(String[] args) {
      Outer x=new Outer();
      x.outerMethod();
   }
}

输出:

local variable x is accessed from within inner class;
needs to be declared final

注意:局部内部类在JDK 1.7之前不能访问非最终局部变量。从JDK 1.8开始,可以在方法local内部类中访问非最终局部变量。但是下面的代码可以编译并正常运行(请注意,这次x是final的)

class Outer {
   void outerMethod() {
      final int x=98;
      System.out.println("在outerMethod内");
      class Inner {
         void innerMethod() {
            System.out.println("x = "+x);
         }
      }
      Inner y = new Inner();
      y.innerMethod();
   }
}
class MethodLocalVariableDemo {
    public static void main(String[] args){
      Outer x = new Outer();
      x.outerMethod();
    }
}

输出-:

在outerMethod内
X = 98

我们需要将局部变量声明为final的主要原因是,局部变量一直存在于堆栈上,直到方法在堆栈上为止,但是内部类的对象可能仍然存在于堆上。方法本地内部类不能标记为私有,受保护,静态和临时,但可以标记为抽象和最终,但不能同时标记为两者。

静态嵌套类
从技术上讲,静态嵌套类不是内部类。他们就像外部类的静态成员。

class Outer {
   private static void outerMethod() {
     System.out.println("在outerMethod内");
   }
   // 静态内部类
   static class Inner {
     public static void main(String[] args) {
        System.out.println("内部类的方法");
        outerMethod();
     }
   }
}

输出

内部类的方法
在outerMethod内

匿名内部类
声明的匿名内部类根本没有任何名称。它们以两种方式创建。
a)作为指定类型的子类

class Demo {
   void show() {
      System.out.println("父类的show方法");
   }
}
class Flavor1Demo {
   //  An anonymous class with Demo as base class
   static Demo d = new Demo() {
       void show() {
           super.show();
           System.out.println("在Flavor1Demo类内");
       }
   };
   public static void main(String[] args){
       d.show();
   }
}

输出

父类的show方法
在Flavor1Demo类内

在上面的代码中,我们有两个类Demo和Flavor1Demo。在这里,demo充当超类,匿名类充当子类,这两个类都具有show()方法。在匿名类中,show()方法被覆盖。

a)作为指定接口的实现者

class Flavor2Demo {
    // An anonymous class that implements Hello interface
    static Hello h = new Hello() {
        public void show() {
            System.out.println("i am in anonymous class");
        }
    };
    public static void main(String[] args) {
        h.show();
    }
}
interface Hello {
    void show();
}

输出:

i am in anonymous class

在上面的代码中,我们创建了一个匿名内部类的对象,但是这个匿名内部类是接口Hello的实现者。任何匿名内部类一次只能实现一个接口。它可以一次扩展一个类或实现一个接口。