内部类的种类:
在Java中内部类主要分为成员内部类、方法内部类、匿名内部类、静态内部类。
1.成员内部类
成员内部类也是最普通的内部类,它是外部类的一个成员,所以他是可以无限制的访问外围类的所有成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。
在成员内部类中要注意两点:
成员内部类中不能存在任何static的变量(但可以是 static final 变量)和方法;
成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。
2.方法内部类(也可称为 局部内部类)
方法内部类定义在外部类的方法中,方法(局部)内部类和成员内部类基本一致,只是它们的作用域不同,方法内部类只能在该方法中被使用,出了该方法就会失效。 对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类。
3.匿名内部类
匿名内部类其实就是一个没有名字的方法内部类,所以它符合方法内部类的所有约束,除此之外,还有一些地方需要注意:
匿名内部类是没有访问修饰符的。
匿名内部类必须继承一个抽象类或者实现一个接口
匿名内部类中不能存在任何静态成员或方法
匿名内部类是没有构造方法的,因为它没有类名。
为了解决生命周期不同的问题,匿名内部类备份了变量,为了解决备份变量引出的问题,外部变量要被定义成final(java1.8之后可以不定义为final)
我们匿名内部类使用final不是怕修改,是怕不能同步修改。(因为往匿名内部类中传入的变量会被拷贝之后提供给匿名内部类使用, 因此我觉得如果传入成员对象的话则可以同步修改)
一般使用匿名内部类的场景是,要继承或实现的接口只有一个抽象方法,比如添加一个监听器:
public class Button {
public void click(){
//匿名内部类,实现的是ActionListener接口
new ActionListener(){
public void onAction(){
System.out.println("click action...");
}
}.onAction();
}
//匿名内部类必须继承或实现一个已有的接口
public interface ActionListener{
public void onAction();
}
public static void main(String[] args) {
Button button=new Button();
button.click();
}
}
4 静态内部类
关键字static可以修饰成员变量、方法、代码块,其实它还可以修饰内部类,使用static修饰的内部类我们称之为静态内部类。静态内部类与非静态内部类之间存在一个最大的区别,非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。没有这个引用就意味着:静态内部类的创建是不需要依赖于外围类,可以直接创建。
静态内部类不可以使用任何外围类的非static成员变量和方法,而内部类则都可以
public class OuterClass {
private static String outerName;
public int age;
static class InnerClass1{
//在静态内部类中可以存在静态成员
public static String _innerName = "static variable";
public void display(){
/*
* 静态内部类只能访问外部类的静态成员变量和方法
* 不能访问外部类的非静态成员变量和方法
*/
System.out.println("OutClass name :" + outerName);
}
}
class InnerClass2{
//非静态内部类中不能存在静态成员
public String _innerName = "no static variable";
//非静态内部类中可以调用外部类的任何成员,不管是静态的还是非静态的
public void display(){
System.out.println("OuterClass name:" + outerName);
System.out.println("OuterClass age:" + age);
}
}
public void display(){
//外部类能直接访问静态内部类静态元素
System.out.println(InnerClass1._innerName);
// 静态内部类可以直接创建实例不需要依赖于外部类
new InnerClass1().display();
// 非静态内部的创建需要依赖于外部类
OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
//非静态内部类的成员需要使用非静态内部类的实例访问
System.out.println(inner2._innerName);
inner2.display();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.display();
}
}
内部类的使用可以增加封装性