一.内部类
- 类中定义的成员:
字段,方法,内部类 - 内部类:定义在类结构中的另一个类:
- 增强封装,把内部类隐藏在外部类之内,不许其他类访问内部类
- 内部类能提高代码的可读性和可维护性,把小型类嵌入到外部类中结构上代码更靠近
- 内部类可以直接访问外部类的成员。
- 内部类根据使用不同的修饰符分类
- 实例内部类:内部类没有使用static修饰
- 静态内部类:内部类使用了static修饰
- 局部内部类:在方法中定义的内部类
- 匿名内部类适合于仅使用一次的类:属于局部内部类的特殊情况
- 对于内部类来说:Java编译器会生成独立的.class文件
- 成员内部类:外部类$内部类名字
- 局部内部类:外部类$数字内部类名称
- 匿名内部类:外部类名$数字
二.实例内部类
- 没有使用static修饰内部类,说明内部类属于外部类的对象,不属于外部类本身。
特点:- 创建实例内部类前,必须存在外部类对象,通过外部类对象创建内部类对象(当存在内部类对象
时,一定存在外部类) - 实例内部类的实例自动持有外部类的实例的引用,内部类可以直接访问外部类成员
- 外部类中不能直接访问内部类的成员,必须通过内部类实例去访问。
- 实例内部类中不能定义静态成员,只能定义实例成员。
- 如果实例内部类和外部类存在同名的字段或方法abc,那么在内部类中:
- 创建实例内部类前,必须存在外部类对象,通过外部类对象创建内部类对象(当存在内部类对象
- this.abc表示访问内部类成员。
外部类.this.abc表示访问外部类成员。
新建InstenceInnerClassDemo.java
//外部类
class Outter
{
String name = "Outter.name";
public void ooxx(){
System.out.println("Outter.ooxx");
System.out.println( new Inner().name);
}
//内部类
class Inner
{
String name = "Inner.name";
int age = 16;
public void ooxx(){
String name = "Local.name";
System.out.println("--------");
System.out.println( name);
System.out.println( this.name);
System.out.println( Outter.this.name);
System.out.println("--------");
System.out.println("Inner.ooxx");
}
}
}
class InstenceInnerClassDemo
{
public static void main(String[] args)
{
Outter o = new Outter();
o.ooxx();
System.out.println(o.name);
Outter.Inner i = o.new Inner();
i.ooxx();
System.out.println(i.name);
new Outter().new Inner();
}
}
三.静态内部类
- 使用static修饰
特点:- 静态内部类的实例不会自动持有外部类的特定实例的引用,在创建内部类的实例时,
不必创建外部类的实例 - 静态内部类可以直接访问外部类的静态成员,可以通过外部类的实例访问外部类非静态成员。
- 在静态内部类中可以定义静态成员和实例成员
- 测试类可以通过完整的类名直接访问静态内部类的静态成员
- 静态内部类的实例不会自动持有外部类的特定实例的引用,在创建内部类的实例时,
新建StaticInnerClassDemo.java
//外部类
class Outter
{
String name = "Outter.name";
static String name2 = "Outter.name2";
//静态内部类
static class Inner
{
static int age = 17;
public void test(){
System.out.println(name2);
}
}
}
class StaticInnerClassDemo
{
public static void main(String[] args)
{
Outter.Inner i = new Outter.Inner();
i.test();
System.out.println(Outter.Inner.age);
}
}
四.局部内部类
- 在方法中定义的内部类,其可见范围是当前方法和局部变量是同一个级别。
- 不能使用public,private,protected,static修饰符
- 局部内部类只能在当前方法中使用
- 局部内部类和实例内部类一样,不能包含静态成员
- 局部内部类和实例内部类一样,可以访问外部类所有成员
- 局部内部类访问的局部变量必须使用final修饰(Java8中会隐式加上final,不能改变值)
- 原因:如果当前方法不是main方法,那么当前方法调用完毕后,当前方法的栈帧被销毁,方法内
部的局部变量的空间全部销毁,然后局部内部类是定义在方法中,而且在方法中会创建局部内部
类对象,而局部内部类会访问局部变量,当当前方法被销毁的时候,对象还在堆内存,依然持有
对局部变量的引用,但是方法被销毁的时候局部变量已经被销毁了。 - 此时出现:在堆内存中,一个对象引用着一个不存在的数据,为了避免该问题,我们使用final修
饰局部变量,从而变成常量,永驻内存空间,即使方法销毁之后,该局部变量也在内存中,对象
可以继续持有。
新建LocalInnerClassDemo.java
class LocalInnerClassDemo
{
static int ooxx = 5;
public static void main(String[] args)
{
final int age = 12;
System.out.println("Hello World!");
class Local
{
void doWork(){
System.out.println(age);
}
}
new Local().doWork();
}
}
五.匿名内部类(Anonymous)
- 没有名称的局部内部类,只使用一次的类。
- 匿名内部类本身没有构造器,但是会调用父类构造器
- 匿名内部类尽管没有构造器,但是可以在匿名内部类中提供一段实例初始化代码快
JVM在调用父类构造器后,会执行该段代码 - 内部类处理可以继承类之外,还可以实现接口
- 格式:
new 父类构造器(实参列表)或接口(){
//匿名内部类的类体部分
}
注意:匿名内部类必须继承一个父类或者实现一个接口,但最多只能一个父类或实现接口。