Java内部类

本文章转自:链接

什么是内部类

定义在其他类(outer class)中的类被称作内部类。内部类可以有访问修饰服,甚至可以被标记为 abstract 或 final。 内部类与外部类实例有特殊的关系,这种关系允许内部类访问外部类的成员,也包括私有成员。

内部类分为以下四种:

  • inner class
  • 局部内部类
  • 匿名内部类
  • 静态嵌套类

Inner Class

一个内部类被声明在另外一个类当中:

//Top level class definition
class MyOuterClassDemo {
   private int myVar= 1;

   // inner class definition
   class MyInnerClassDemo {
      public void seeOuter () {
         System.out.println("Value of myVar is :" + myVar);
      }
    } // close inner class definition

} // close Top level class definitio

实例化一个内部类

为了实例化一个内部类的实例,需要一个外部类的实例。内部类的实例只能通过外部类的实例来创建。

//Top level class definition
class MyOuterClassDemo {
 private int myVar= 1;

 // inner class definition
 class MyInnerClassDemo {
    public void seeOuter () {
       System.out.println("Value of myVar is :" + myVar);
    }
  } // close inner class definition

 void innerInstance(){
	MyInnerClassDemo inner = new MyInnerClassDemo();
	inner.seeOuter();
 }
 public static void main(String[] args){
	 MyOuterClassDemo outer = new MyOuterClassDemo();
	 outer.innerInstance();
 }
} // close Top level class definitio

Output: Outer Value of x is :1

上面的例子 mian 方法也可以这样写:

 public static void main(String[] args){
	 MyOuterClassDemo.MyInnerClassDemo inner = new MyOuterClassDemo().new MyInnerClassDemo();
	 inner.seeOuter();
 }

局部内部类

局部内部类被定义在外部类的方法当中。

如果你想使用内部类,必须同一方法中实例化内部类 只有 abstract 和 final 这两个修饰符被允许修饰局部内部类 只有在方法的局部变量被标记为 final 或 局部变量是 effectively final的, 内部类才能使用它们。 什么是 effectively final? “Starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final.” 因此当变量或参数在初始化之后,值再也没有改变过,那么就说明该变量或参数是 effectively final。

//Top level class definition
class MyOuterClassDemo {
 private int x= 1;

 public void doThings(){
    String name ="local variable"; // name is effectively final
    // inner class defined inside a method of outer class
    class MyInnerClassDemo {
      public void seeOuter() {
         System.out.println("Outer Value of x is :" + x);
         System.out.println("Value of name is :" + name);
      } //close inner class method
    } // close inner class definition
    MyInnerClassDemo inner = new MyInnerClassDemo();
    inner.seeOuter();
 } //close Top level class method
 public static void main(String[] args){
	 MyOuterClassDemo outer = new MyOuterClassDemo();
	 outer.doThings();
 }
} // close Top level class

Output:

Outer Value of x is :1
Value of name is :local variable

匿名内部类

匿名内部类有以下特点:

  • 没有名字
  • 只能被实例化一次
  • 通常被声明在方法或代码块的内部,以一个带有分号的花括号结尾
  • 因为没有名字,所以没有构造函数
  • 不能是静态的(static)

为什么要使用匿名类,我们先看一个例子:

abstract class Animal {
	abstract void play();
}

class Dog extends Animal{
	void play(){
		System.out.println("play with human");
	}
}

class Demo{
	public static void main(String[] args){
		Animal d = new Dog();
		d.play();
	}
}

Output:  play with human

如果此处的 Dog 类只使用了一次,那么单独定义一个Dog类是否会显得有点麻烦? 这个时候我们可以引入匿名类:

abstract class Animal {
	abstract void play();
}

class Person{
	public static void main(String[] args){
		Animal d = new Animal(){
			void play(){
				System.out.println("play with human");
			}
		};
		d.play();
	}
}

Output:  play with human

由上面的例子可以看出,匿名类的一个重要作用就是简化代码。

匿名类的常用场景:

事件监听 普通的实现方式:

 public class WindowClosingAdapter extends WindowAdapter {
     public void windowClosing( WindowEvent e ) {
         System.exit(0);
     }
 }

 ...

  addWindowListener( new WindowClosingAdapter() );

匿名内部类的实现方式:

 addWindowListener(
     new WindowAdapter() {
         public void windowClosing( WindowEvent e ) {
             System.exit(0);
         }
     });

Thread 类的匿名内部类实现 public class Demo { public static void main(String[] args) { Thread t = new Thread() { public void run() { for (int i = 1; i <= 5; i++) { System.out.print(i + " "); } } }; t.start(); } } Runnable 接口的匿名内部类实现 public class Demo { public static void main(String[] args) { Runnable r = new Runnable() { public void run() { for (int i = 1; i <= 5; i++) { System.out.print(i + " "); } } }; Thread t = new Thread(r); t.start(); } }

静态嵌套类

一个静态嵌套类是被标记为 static 的内部类。 静态嵌套类无法访问外部类的非静态成员。 嵌套类被分为两类:静态和非静态的。被声明为 static 的被称作静态嵌套类,非静态嵌套类就是内部类

例如:

class Outer{
   static class Nested{}
}
静态嵌套类可以被这样实例化:

class Outer{// outer class
   static class Nested{}// static nested class
}

class Demo{
   public static void main(string[] args){
      // use both class names
      Outer.Nested n= new Outer.Nested();
   }
}