Java内部类探讨

来源:互联网 发布:商城二次开发 php 编辑:程序博客网 时间:2024/06/14 04:10

默认的访问修饰符

最初的发现是遇到了一个疑问,Java中类、接口、内部类、抽象类中属性方法的默认访问修饰符是什么?
稍微查了查资料
- 普通类默认的访问修饰符是:default,也即包内友好
- 接口中的属性的默认是public static final ,方法是public abstract
- 内部类默认的访问修饰符是:public,只是要依附与外围类
- 抽象类默认的访问修饰符是:default

注意

Java中外围类、接口、抽象类的访问修饰符只能是public和default

成员内部类访问修饰权限的测试

这里还可以看一看如何实例化成员内部类,(滑稽

前期准备

  • InPackage中有一个OutClass,里面有一个内部类InClass作为成员变量
  • 同一个包下有一个测试类InPackage_OutClass
  • 不在同一个包下有一个测试类OutPackage_OutClass

成员内部类的实例化方法

OutClass.InClass in = new OutClass.InClass(); //只有在内部类中的外围类中可以使用// 1.通用OutClass.InClass in2 = new OutClass().new InClass();// 2.通用OutClass out = new OutClass();OutClass.InClass in3 = out.new InClass(); 

实验

测试的方法就是看能否实例化成员内部类对象
- 首先是直接在外围类中测试

/** * public > protected > default > private * private 不能修饰外部类 * protected 不能修饰外部类 */public class OutClass {    // 作为成员内部类,内部类拥有其外围类的所有成员的访问权    // 不加修饰符的情况下,其修饰符是 default        public class InClass{        //public static int id; // static变量违法        // 内部类不能有static方法,因为内部类必须依赖与外部类存在        public void print(){            System.out.println("this inner class");        }    }    @Test    public void testInClass(){        // 1.成员内部类的一种初始化方法        InClass in = new InClass();        in.print();        // 2.成员内部类的另一种初始化方法        OutClass.InClass in2 = new OutClass().new InClass();        in2.print();        // 3.使用外部类绑定来初始化        OutClass out = new OutClass();        OutClass.InClass in3 = out.new InClass();        // 4.当内部类是static修饰时可以使用这个初始化方式        //InClass in4 = new OutClass.InClass();    }}
  • 接着是“同包不同类”中实验
/** * 该类旨在测试同一个包下,是否可以访问内部类 *  * 所以访问权限是,只有依附与外部类,内部类是可以访问的;但无法直接访问,即便是public也不行 */public class InPackage_OutClass {    @Test    public void testInClass(){        OutClass out = new OutClass();        // 1.同一个包的情况下,可以访问内部类        OutClass.InClass in = new OutClass().new InClass();        // 不使用.new便无法初始化对象        //      OutClass.InClass in2 = new OutClass.InClass(); // 在内部类的外围类中可以使用该初始化方法        // 2.使用外部类对象绑定初始化内部类        OutClass.InClass in3 = out.new InClass();        // 在同一个包的情况下,可以直接导入,但原理还是与上面一致        InClass in4 = out.new InClass();    }}
  • 接着是“不同包不同类”
/** * 本例旨在测试不在同一个包的情况下,默认修饰的内部类的访问权限 *  * 所以访问权限是,只有依附与外部类,内部类是可以访问的;但无法直接访问 */public class OutPackage_OutClass {    public void testInClass(){        OutClass out = new OutClass();        // 1.该方法继承或不继承都可以使用         OutClass.InClass in = new OutClass().new InClass();        // 2.外围类对象绑定的方法可以初始化        OutClass.InClass in2 = out.new InClass();        // 该方法与上述原理一样        InClass in3 = out.new InClass(); // 不行    }}

结论

从上面的实验可以看出,成员内部类的默认访问修饰符是public,这个public其实是指在依赖于外部类的情况下来看这个内部类其实是public的(其实一开始认为是default,直到发现没有继承时也可通过外围类进行实例化…….)

有疑问的地方

其实上述的结论是不敢确定的,因为还看到了这个:Java内部类与访问修饰符
所以,真相究竟是什么? (ㄒoㄒ)

成员内部类的用途

其实一旦观察到了这个知识点,总是很容易会想到用途这个实际的东西(…….),看了看《Think In Java》,里面有这么一个例子:

interface Context{    public void print();}/** * 内部类的主要用途是在类向上转型(接口)时隐藏实现细节 */public class InnerClassApplication {    class InClass implements Context{        @Override        public void print(){            System.out.println("我是实现接口的成员内部类");        }    }    public Context getContext(){        return new InClass();    }    @Test    public void testInClassApplication(){        InnerClassApplication icap = new InnerClassApplication();        icap.getContext().print();    }}

解释一下就是,使用内部类实现一个接口或者继承一个基类,然后向上转型可以隐藏实现的细节

再来看看其它的内部类

局部内部类

首先来看为什么要这样用,无非是有这样的需求:
- 实现了某类型的接口,然后隐藏实现返回接口的实例化对象
- 希望有一个非公共的类来完成某些特殊的任务

普通局部内部类

定义在一个方法中,作用域就是该方法,相较于成员内部类,就是直接把类放入了方法体中

匿名内部类

这个就有说头了,匿名就是类没有名字,由JVM自动分配一个特殊助记名

public class Test{    public Context getContextFromNoNameClass(){        return new Context(){            @Override            public void print(){                System.out.println("我是隐式实现了接口的匿名内部类");            }        };    }    @Test    public void testNoNameInClass(){        // 可以看到的是尽管没有显式的实现Context接口,但还是重写了print()方法        this.getContextFromNoNameClass().print();        System.out.println(this.getContextFromNoNameClass().getClass());    }}

这个内部类的类名是class InnerClass.InnerClassApplication$1,重点是$1,这个就是JVM给匿名内部类分配的助记符

匿名内部类的一些注意

匿名类不可以改变外围类中的属性,所以当在匿名内部类中使用外部类对象时,会要求这个外围类对象加上final修饰符

嵌套类

说白了就是给成员内部类加上了static的修饰符,这意味着
- 要创建嵌套类的对象并不需要依附与外围类(长能耐了)
- 不能从嵌套类的对象中访问到非静态的外围类对象
- 同时可以使用InClass in = new OutClass.InClass();这种实例化方法

为什么要有内部类

神说要有光,于是便有了光。那为什么会需要内部类呢?

“每个内部类都能独立的继承自一个(接口的)是实现,所以无论外围类是否已经继承了(接口的)实现,对内部类都没有影响” ——《Think in Java》

除此之外,私以为还有上述提到的隐藏实现细节这个原因,所以掌握熟练也是很有必要的,工业界应该少不了这个要求吧?!

1 0
原创粉丝点击