java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称。
本文主要介绍了 java 内部类使用总结。具有很好的参考价值,下面跟着小编一起来看下吧
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) 创建匿名内部类:
匿名内部类本身没有构造器, 但是会调用父类构造器. 一般来说, 匿名内部类用于继承其他类或是实现接口, 并不需要增加额外的方法, 只是对继承方法的实现或是重写.
注意:匿名内部类必须继承一个父类或者实现一个接口, 但最多只能一个父类或实现一个接口.
- //定义一个接口
- interface Person {
- public void eat();
- }
- public class AnonymousDemo {
- public static void main(String[] args) {
- // 使用匿名内部类
- Person p = new Person() {
- public void eat() {
- System.out.println("eat something");
- }
- };
- p.eat();
- }
- }
4. 总结
5. 面试题
- public class Outer {
- public void someOuterMethod() {
- // Line 3
- }
- public class Inner {}
- public static void main(String[] argv) {
- Outer o = new Outer();
- // Line 8
- }
- }
- /*
- * Which instantiates an instance of Inner?
- A. new Inner(); // At line 3
- B. new Inner(); // At line 8
- C. new o.Inner(); // At line 8
- D. new Outer.Inner(); // At line 8
- */
答案 A.new Inner(); 等价于 this.new Inner(); 已经存在一个 Outer 类对象了.
line 8 正确写法, 应为: o.new Inner();
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持 PHPERZ!
来源: http://www.phperz.com/article/17/1223/358402.html