**嵌套类(nested class)的概念:**是指被定义在一个类内部的类,所以也称为内部类,它在java中被广泛的应用,嵌套类有四种:成员内部类、静态内部类、匿名内部类、局部内部类
一、成员内部类
成员内部类又被称为非静态内部类,顾名思义,就是定义在类内部没有被static修饰的普通类,可以将之看成一个类的成员对象,如下:
public class Outer {
public class Inner{
}
}
成员内部类的特点:
1.成员内部类可以被权限修饰符所修饰,eg:private、public、default(不写)、protected
2.成员内部类可以访问外部类的所有成员,包括private成员
3.成员内部类是默认包含了一个指向外部类对象的引用
4.可以继承其他类,或者其他接口
5.除常量(static final)外,不能包含静态变量/方法。
6.当内部类的变量或方法与外部类一样时,可以用Outer.this.name指定访问外部类的成员或方法,设计时应尽量避免这种情况。
7.在第三方类中,不允许单独的普通内部类对象存在,需要先创建外部类的对象,才能创建内部类的对象。
8.编译后名称是:外部类名+$+内部类名
内部类类对象的创建方式
Outer outer= new Outer();
Outer.Inner inner=outer.new Inner();
编译后的格式:
二、静态内部类
静态内部类又被称为静态成员类,顾名思义,就是用static修饰的内部类,如下:
public class Outer {
public static class Inner{
}
}
静态内部类的特点:
1.可以定义静态成员或者非静态成员
2.不能直接访问外部类的非静态成员,可通过外部类的对象访问外部类的非静态成员
3.可以直接访问外部类的静态成员
4.外界(第三方类)可以通过静态内部类的类名访问其静态成员,通过对象访问其非静态成员
5.外界(第三方类)只能通过外部类才可以访问到静态嵌套类,并创建对象,不需要外部类的对象。
6.是四种类中唯一一个不包含对外部类对象引用的内部类
7.可以继承其他类或者实现其他接口
代码示例:
public class Outer {
private String id="007";
static String name="小明";
int number=12;
public static class Inner extends Thread{ //可以继承其他类
public static int a;//可以有静态成员
public int b;//可以有非静态成员
public void innerMethod(){
System.out.println(name);//可以直接访问外部类静态成员
Outer outer=new Outer();
System.out.println(outer.number);//只能通过外部类的对象访问外部类非静态成员
System.out.println(outer.id);//可以访问外部类私有成员
}
}
public static void main(String[] args) {
Inner inner=new Inner();//在外部类中对象创建方式与普通类一致
}
}
/*=====================================================================================*/
class Three{
public static void main(String[] args) {
Outer.Inner inner=new Outer.Inner();//在第三方类中的对象的创建方式
}
}
编译后的文件名与普通内部类一致
三、匿名内部类
匿名内部类是与继承合并在一起没有名字的类
匿名内部类的特点:
1.没有正式的类名
2.没有构造函数,能使用父类或者父接口的构造函数,可以带参数,可以继承,重写,扩展父类、父接口的方法
3.除常量(static final)外,内部不可以定义静态成员,
4.可以访问外部类的成员变量和方法,包括private
5.如果定义在静态方法中,也只能访问外部类的静态成员
6.外部类和第三方类都无法访问匿名内部类
7.编译后的文件名:外部类名+$+数字编号+.class
8.没有类名,也没有引用指向它,所以只能使用一次
实现方式
父类名/接口名 对象名=new 父类名/接口名{
重写或者实现父类中的方法
}
代码实例:
public class Outer {
public static void Method(){
//实现接口
//使用方式1
InterfaceTest it=new InterfaceTest() {
@Override
public void test() {
System.out.println("A");
}
};
it.test();
//使用方式二
new InterfaceTest() {
@Override
public void test() {
System.out.println("B");
}
}.test();
//继承抽象类
AbstractTest at=new AbstractTest() {
};
at.normalMethod();//可以继承父类中的方法
}
public static void main(String[] args) {
Method();
}
}
/*=====================================================================================*/
interface InterfaceTest{
public void test();
}
abstract class AbstractTest{
public void normalMethod(){
System.out.println("C");
}
}
编译后的文件:
匿名类的作用:
1.简单便捷,当我们想使用一个接口或者抽象类定义的方法时,但是并不是重复利用,可能只是使用很少的次数,就可用匿名内部类,这样做的好处是,不用特意构造一个类去继承抽象类/接口,然后创建对象去使用,而是直接创建匿名内部类使用父类中的方法。只针对重写一个方法时使用,需要重写多个方法时不建议用匿名内部类。
2.安全封装,由于外部无法访问到匿名内部类,增强了封装性。
四、局部内部类
局部内部类是定义在方法或者作用域中类。如下
public class Outer {
public static void Method(){
class Inner{
}
}
}
局部内部类的特点
1.局部内部类不能有访问权限符,有构造方法
2.局部内部类不能被定义为static,
3.局部内部类不能含有静态成员
4.局部内部类默认包含了外部类对象的引用
5.如果定义在普通方法中,局部内部类可以使用Outer.this的语法访问外部类成员
6.局部内部类想要使用方法或域中变量。该变量必须是final的,但在java8之后,有了effectively final,变量可以不用final修饰,一个变量定值后没有被修改过
7.可以继承其他类,或者实现接口,但是本身不能是一个接口
8.如果定义在静态方法中,只能访问外部类静态成员
9.编译后名称:外部类名+$+序号+内部类名+.class
编译后文件:
局部内部类的作用
局部内部类的作用其实和匿名内部类的作用差不多,当我们在设计类时,可能一些方法内,需要创建一个类或者需要实现某些接口/抽象类来使用,就可以通过创建局部内部类的方式。因为在实际使用过程中我们可能需要多个内部类对象,由于局部内部类有类名,有构造器,可以创建对象,这是匿名内部类办不到的。
五、内部类究竟有什么作用(静态/成员内部类)
1.解决多继承的问题,当我们设计类时有可能会涉及到需要多继承时,就可以用创建多个内部类来继承我们需要的抽象类供自己使用。
2.隐藏封装,当我们不想内部类轻易被人访问,可以选择private来修饰内部类,只留一个接口供外部使用,隐藏了内部方法的具体实现。
3.可以无条件的访问外部类的成员,可以对外部类的私有成员做处理,这是第三方类无法做到的。
4.解决在同时继承类和实现接口中有同名方法不好区分的问题。
六、为什么匿名/局部内部类只能使用外部被final修饰的变量
这是由于局部变量和局部内部类对象的生命周期不同,局部变量所处的方法在执行结束后就死亡了,但是局部内部类的对象只要有引用指向,它就会一直存在,这样就会出现一种尴尬的现象,内部类的引用指向一个不存在的变量,所以就需要用final修饰,将这个变量变成常量,储存在常量区。但是自从java1.8之后,这个局部变量可以不用被final修饰,实际上底层自动帮忙加上了final,所以说看起来没有被final修饰的变量,当我们试图修改这个变量值时,编译器就会报错,这样的变量只能被使用,而不能被修改。
七、变量遮蔽
总结