1. 什么是内部类?
定义在类内部的类, 称之为内部类
- public class Out {class In { //此时In就是内部类 } }
2. 为什么要使用内部类?
1), 增强封装, 把内部类隐藏在外部类中, 不允许其他类来访问内部类
2), 内部类能提高代码的可读性和可维护性
3. 内部类的分类
对于内部类的分类, 可以对比于成员变量的分类.
我们可以根据不同的修饰符或者定义的不同位置把成员变量, 可以细分为: 类成员变量, 实例成员变量, 局部变量.
内部类看做是外部类的一个成员, 那么内部类可以使用 public / 缺省 / protected/private 修饰. 还可以是 static 修饰.
同理, 内部类也根据使用不同的修饰符或者定义的不同位置, 将其分成 4 类:
1), 实例内部类: 内部类没有使用 static 修饰
2), 静态内部类: 内部类使用 static 修饰
3), 局部内部类: 在方法中定义的内部类
4), 匿名内部类: 只能使用一次, 属于内部类的一种特殊情况
3.1 实例内部类:
1) 定义: 实例内部类, 即没有使用 static 修饰的内部类. 这说明, 实例内部类属于外部类的对象, 不属于外部类本身 (类比字段).
2) 创建实例内部类
- //外部类class Outter { // 实例内部类:没有使用static修饰 class Inner { }}public class InnerDemo1 { public static void main(String[] args) { // 创建实例内部类,没有使用static修饰,属于外部类的对象,因此,创建实例内部类前,必须存在外部类对象 Outter out = new Outter(); // 通过外部类对象创建内部类对象 Outter.Inner in = out.new Inner(); }}
3) 特点:
a. 由创建实例内部类的过程可知, 当存在内部类对象时, 一定存在外部类对象.
b. 实例内部类的实例自动持有外部类的实例的引用, 实例内部类可以无条件访问外部类的所有字段和方法
注意: 当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象
c. 外部类中不能直接访问内部类的成员, 必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问
- //外部类class Outter { private String name = "out"; private Integer age = 17; // 实例内部类:没有使用static修饰 class Inner { private Integer age = 18; // 隐藏现象,隐藏了外部类的age Inner() { // 特点:1.实例内部类能直接访问外部类成员 // 2.当实例内部类和外部类有同名的字段或者方法时,会发生隐藏现象 System.out.println(name + this.age);// 输出out18 // 此时若需要使用外部类的age,语法:外部类.this.age System.out.println(Outter.this.age);// 输出17 } }}
总结: 简单来说, 就是看变量的作用域, 外部类成员变量的作用域是整个外部类, 而内部类在外部类中 (可以看做外部类的字段), 内部类自然就可以访问外部类. 而外部类要去访问内部类的成员, 可以这样理解: 内部类的成员属于内部类, 在内部类中有效, 内部类都不存在, 其中的成员变量也不会存在, 所以, 外部类中不能直接访问内部类的成员, 必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问.
3.2 静态内部类
1) 定义: 使用 static 修饰的内部类. 所以, 该内部类属于外部类本身, 而不属于外部类的对象
2) 创建静态内部类
- //外部类class Outter { // 静态内部类:使用static修饰 static class Inner { }}public class InnerDemo2 { public static void main(String[] args) { // 因为静态内部类属于外部类本身,可以直接通过外部类类名来访问(类比字段) Outter.Inner in = new Outter.Inner(); }}
3) 特点:
a. 在创建内部类的实例时, 不必创建外部类的实例.
b. 静态内部类可以直接访问外部类的静态成员, 如果访问外部类的实例成员, 必须通过外部类的实例去访问.
简单理解: 静态成员属于类, 非静态成员属于对象, 如果要访问外部类的实例成员 (非静态成员), 当然要先存着外部类对象的. 而静态内部类的创建是不需要外部类的对象, 因此, 如果访问外部类的实例成员, 必须通过外部类的实例去访问.
c. 在静态内部类中可以定义静态成员和实例成员.
d. 测试类可以通过完整的类名直接访问静态内部类的静态成员.
- //外部类class Outter { static String name = "outter"; public Integer age = 17; // 静态内部类:使用static修饰 static class Inner { Inner() { // 静态内部类能直接访问外部类的静态成员 System.out.println(name);// 输出 outter // 访问外部类的实例成员,必须通过外部类的实例去访问. System.out.println(new Outter().age);// 输出 17 } }}
3.3 局部内部类 (几乎用不到)
1) 定义: 在方法中定义的内部类, 其可见范围是当前方法, 和局部变量是同一个级别, 所以局部内部类只能在方法中使用.
注意,局部内部类和方法里面的局部变量一样,是不能有 public、protected、private 以及 static 修饰符的。
- public class InnerDemo3 {
- public static void main(String[] args) { // 局部内部类 class Inner { } }}
2) 特点:
a. 局部内部类和实例内部类一样, 不能包含静态成员.(局部内部类属于方法, 而静态成员属于类)
b. 局部内部类和实例内部类, 可以访问外部类的所有成员.
c. 局部内部类访问的局部变量必须使用 final 修饰, 在 Java8 中是自动隐式加上 final(语法糖).
原因: 当方法被调用运行完毕之后, 当前方法的栈帧被销毁, 方法内部的局部变量的空间全部销毁. 但内部类对象可能还在堆内存中, 要直到没有被引用时才会消亡. 此时就会出现一种情况: 内部类要访问一个不存在的局部变量. 为了避免该问题, 我们使用 final 修饰局部变量, 从而变成常量, 永驻内存空间, 即使方法销毁之后, 该局部变量也在内存中, 对象可以继续持有.
- public class InnerDemo3 {
- public static void main(String[] args) {
- int age = 17;
- final int num = 15; // 局部内部类 class Inner { public void test() { // 报错:Cannot refer to a non-final variable age inside an inner class defined in a different method System.out.println(age); System.out.println(num);// 正确 } } }}
3.4 匿名内部类 (使用最频繁)
1): 定义: 匿名内部类是一个没有名称的局部内部类, 适合于只使用一次的类.
2) 创建匿名内部类:
匿名内部类本身没有构造器, 但是会调用父类构造器. 一般来说, 匿名内部类用于继承其他类或是实现接口, 并不需要增加额外的方法, 只是对继承方法的实现或是重写.
注意:匿名内部类必须继承一个父类或者实现一个接口, 但最多只能一个父类或实现一个接口.
- //定义一个接口interfacePerson {publicvoideat();}publicclassAnonymousDemo {publicstaticvoidmain(String[] args) {//使用匿名内部类Person p =newPerson() {publicvoideat() {System.out.println("eat something");}};p.eat();}}
5. 面试题
- publicclassOuter {
- publicvoidsomeOuterMethod() { //Line 3}publicclassInner {}publicstaticvoidmain(String[] argv) {Outer o=newOuter();//Line 8}}/** Which instantiates an instance of Inner?A. new Inner(); // At line 3B. new Inner(); // At line 8C. new o.Inner(); // At line 8D. new Outer.Inner(); // At line 8*/
答案 A.new Inner(); 等价于 this.new Inner(); 已经存在一个 Outer 类对象了.
line 8 正确写法, 应为: o.new Inner();
就爱阅读 www.92to.com 网友整理上传, 为您提供最全的知识大全, 期待您的分享,转载请注明出处。
来源: http://www.92to.com/bangong/2017/02-27/17743587.html