理解:
一个类中又完整的嵌套了另一个类结构,被嵌套的类称为内部类。外面的类称为外部类,和内部类无关的外部类称为外部其他类。
class A{ // B的外部类 String name; public void method(){ for(){ int i; class B{ // A的内部类 String name; } } } } class Other{ // B的外部其他类 }
好处:
可以直接访问外部类中的所有成员,包含私有的!!!
分类:
定义在成员位置上:
成员内部类(没有使用static修饰) √
静态内部类(使用static修饰)
定义在局部位置上:
局部内部类(有类名)
匿名内部类(没有类名) √
1、成员内部类
特点:
① 内部类中可以有五大普通成员,不能有静态成员!(因为静态成员随着外部类的加载而加载,但成员内部类随着外部类的对象创建而加载,静态内部类可以)
② 可以添加任意访问修饰符,遵循访问权限限定!
③ 互访原则:
内部类—>外部类
直接访问,包含任意成员(私有的也可以)
外部类—>内部类
不能直接访问,需要通过创建内部类对象再去访问,包含任意成员(私有的也可以)
语法:new Inner().方法();
外部其他类—>内部类
不能直接访问,需要通过创建内部类对象再去访问,只能访问在权限范围内的成员(私有的不可以!!!)
语法:new Outer().new Inner().方法();
④ 当外部类和内部类成员重名时,默认访问的是内部类的成员,遵循就近原则。如果非要访问外部类的成员,可以通过外部类名.this.成员的方式!
示例:
/** * 此类用于演示内部类:成员内部类的特点和使用 * */ public class TestInner1 { String color; public static void main(String[] args) { Outer o = new Outer(); o.new Inner().show(); // o.new Inner().color=""; } } class Outer{ protected class Inner{ private String name="张无忌"; // public Inner(){ // // } // static{ // // } // class InnerInner{ // class InnerInner2{ // // } // } public void show(){ System.out.println(Outer.this.name); } } private String name = "张翠山"; public void method(){ new Inner().show(); // new Inner().color=""; } }
2、匿名内部类
语法:
new 类名或接口名(参数){ 类体 }
功能:创建了一个匿名内部类 & 创建了一个该类对象(类或接口)
使用示例:
// 创建A的子类&创建A的子类对象 new A(){ //类体 public void method(){} }.method(); // 另一种方法 A a = new A(){ //类体 public void method(){} }; a.method(); interface A{ void method(); }
对比:
//创建A本类的对象 new A();
特点:
① 类中可以有除了构造器之外的其他成员(属性、方法、初始化块、内部类),不可以有静态成员!
② 不能添加访问修饰符和static,作用域:仅仅在定义它的方法或代码块中使用,并且遵循前向引用的特点!
③ 互访原则:
内部类—>外部类的成员
直接访问,包含私有的成员
外部类—>内部类的成员
只能在作用域内,通过匿名内部类的对象去访问,包含私有的成员
语法:
父类或接口名 引用名 = 匿名内部类对象;
引用名.方法();
细节:匿名内部类可以访问外部类的局部变量,但只能读取,不能更新!(只能访问外部类的final修饰的局部变量!)
原因:局部内部类的生命周期>局部变量生命周期,所以不能直接访问一个可能已经消亡的变量。于是将局部变量复制了一个拷贝让局部内部类使用,
但不能更新,因为如果更新,会导致两个变量的值不一致!
jdk7:要求局部内部类中访问的局部变量必须显式的声明final修饰符
jdk8:局部内部类中访问的局部变量不用显式的声明final修饰符
应用场景:
当做接口的实例作为实参传递给方法!
示例:
//代表示例1: TreeSet set = new TreeSet(new Comparator(){ @Override public int compare(Object o1, Object o2) { // TODO Auto-generated method stub return 0; } }); //代表示例2: Thread t= new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub } });