概念
内部类,其意义是为事物中还包含另一种事物时使用的表达方式;
如其字面含义,是在一个类里面创建另一个类;
由其位置不同以及修饰符不同有不同的意义和访问方法;
其本质是创建一个和外部类联系紧密的类;
内部类可以随意访问外部类的属性和方法,即使是私有private修饰也可访问;
外部类
外部类是包含内部类的类。
外部类访问内部类必须创建内部类的对象,再访问其方法和属性;
内部类分类
静态成员内部类
在外部类的成员位置的类,且被static 修饰;
public static class Outer{
String outer;
public void outerMethod(){}
String access$0(){
return inner;
}
static class Inner{
String inner;
public void innerMethod(){}
}
}
被static修饰,所以随类加载而加载,和外部类的关系,相比而言其他内部类而言,不算紧密;
内部访问外部:
静态内部类,仅能访问外部静态的方法和静态的属性;
外部访问内部:
内部私有修饰符private修饰的变量,是不能被类外部访问的,Java的解决方法是:自动为Outer生成一个 非私有访问方法access$0,它返回这个私有静态变量inner。
访问静态内部类方式:
外部类名.内部类名 对象名=new外部类名.内部类名();
(由于静态内部类视作外部类的一个静态成员,访问由外部类名+" . "+内部类类名)
当内部属性被静态修饰符static修饰:
外部类名.内部类名.内部属性名;
成员内部类
成员内部类不可以有静态修饰符修饰的属性和方法,因为静态属性和方法和类直接相关,与内部类的加载不同步;
(被final修饰的变量除外,被fianal修饰等于常量,常量在常量池里加载,可被static修饰)
内部访问外部
在外部类的成员属性位置,且不被任何修饰符修饰的普通类
成员内部类可以访问外部类的任意方法和属性,如果有重名的方法和属性,可以用
this.外部类名.属性/方法();
进行声明和访问
外部访问内部
访问内部类的方式:
外部类名.内部类名 对象名=new 外部类名().new内部类名();
访问内部类的属性方法方式:
由上面生成对象+" . "访问;
对象名.内部类方法() / 内部类属性;
当内部属性被私有修饰符pirvate修饰:
外部类名 对象名 =new 外部类名();
对象名.内部方法名()/属性名;
或者
new 外部类名.内部类方法名() / 属性名;
成员内部类有哪些应用场景呢?如果内部类与外部类关系密切,需要访问外部类的实例变量或方法,则可以考虑定义为成员内部类。外部类的一些方法的返回值可能是某个接口,为了返回这个接口,外部类方法可能使用内部类实现这个接口,这个内部类可以被设为private,对外 完全隐藏
ArrayList多层继承自AbstractCollection继承的方法iterator,返回值是接口Iterator的实现对象new Itr,其内部类Itr就是对Iterator接口的实现(重写),该内部类以及其内部属性被pirvate修饰对外隐藏;
局部内部类
在外部类的成员方法里出现的类;
方法内部类只能在定义的方法内被使用
不能被private,static,protected,public修饰,
内部访问外部
局部内部类所在的成员方法非静态时,可以直接访问外部类的成员实例属性和实例方法,
局部类所在的成员方法静态时,只能访问外部类的静态成员方法和属性;
访问所在成员方法的的属性和方法,必须把所在方法的局部变量用final修饰;
原因:因为方法局部变量a随成员方法的调用完毕而消失,而内部类的对象inner在内存中并没有消失,当需要调用该变量时,就会出现异常了;java内部一般会判定该值在编译时期是否为定值,否则通过构造传参器拷贝并初始化赋值;
如果的确需要修改外部的变量,那么可以将变量改为只含该变量的 数组,修改数组中的值;
外部访问内部
访问局部内部类方式
内部类名 对象名=new 内部类名();
对象名.内部方法()/属性;
或者
new内部类名.内部方法()/属性; 使用了匿名对象
匿名内部类
匿名内部类没有单独的类定义,它在创建对象的同时定义类;
匿名内部类能做的,方法内部类都能做。但如果对象只会创建一 次,且不需要构造方法来接受参数,则可以使用匿名内部类,这样代码 书写上更为简洁。
格式
new 父类名/接口(){ 重写内容实现父类方法 }
匿名内部类的本质就是继承了该抽象类或者实现了该接口的子类对象
如Flie对象调用listFile时需要传入接口对象FilenameFilter ff,可在接口后直接重写方法,new FlienameFilter (){ 重写方法 }(传递接口对象ff此时匿名处理),可以外部重写接口创建对象的一步,可以减少代码冗余;
若接口对象仅在方法内调用一次,就可用匿名内部类进行操作。