本文章转自:链接
什么是内部类
定义在其他类(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();
}
}