前言 最近看《Java编程思想》,看了内部类的讲解,发现自己好多都没听过或者没注意到。
指向外部类的指针 每个内部类都有一个隐藏的外部类的this
指针,可以通过Outer.this
获得
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Main { private String message = "hello" ; public String getMessage () { return message; } class Inner { public Inner () { System.out.println(Main.this .getMessage()); System.out.println(getMessage()); } } public static void main (String[] args) { Main main = new Main(); Main.Inner inner = main.new Inner(); } }
这个例子看其实意义不大,因为函数getMessage()
没有歧义。 如果Inner中也有个getMessage()
,那么调用的就是Inner
中的,这里this
指针就派上用场了。
题外话,在《Java并发编程实战》33页页提到了这个隐藏指针,如果把对象逸出,那么可能出现为构造未完全就调用了方法。比如下面(抱歉写的有点臃肿)。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 interface Escape { void doSome (Some some) ; } class Some { protected Demo demo; public void printI () { demo.printI(); } } class Demo { private int i = 0 ; public Demo (Escape escape) { escape.doSome(new Some() { { this .demo = Demo.this ; } }); i = 1 ; } public void printI () { System.out.println(i); } } public class Main { public static void main (String[] args) { Escape escape = new Escape() { @Override public void doSome (Some some) { some.printI(); } }; Demo demo = new Demo(escape); } }
Demo
构造完应该i = 1
但是这里调用过之后却是输出了0
这就是内部类是对象隐藏指针逸出导致得到了未构造完全的对象。
返回private内部类 正常类的来说,只能是public或者缺省的,不可以是private的。 但是内部类可以是public,priavte, protected或者缺省的。
1 2 3 4 5 6 7 8 9 10 11 12 13 class Demo { private class Innter {} public Innter getInnerInstence () { return new Innter(); } } public class Main { public static void main (String[] args) { Demo demo = new Demo(); } }
作为一种折中的方法,我们可以申明一个接口来解决这个问题
1 2 3 4 5 6 7 8 9 10 11 12 13 interface ForTest {}class Demo { private class Innter implements ForTest {} public Innter getInnerInstence () { return new Innter(); } } public class Main { public static void main (String[] args) { Demo demo = new Demo(); ForTest inner = demo.getInnerInstence(); } }
普通内部类不能有static方法和实例变量 1 2 3 4 5 6 7 public class Main { class Inner { } }
静态内部类 如果你想要内部类可以用static
,那么可以使用静态内部类。 但是静态内部类没有对外部类的引用了。就像是完全的独立的一个类。 创建静态内部类的时候也不需要先创建外部类了。
1 2 3 4 5 6 7 8 9 10 11 12 public class Main { private String name = "hello" ; static class Inner { public static String message = "hello" ; public Inner () { } } }
匿名类的构造 匿名类因为没有类名,所以构造函数没法重新定义,不过可以用{}
包裹起来作为构造函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Main { private String name = "hello" ; public Main (String name) { this .name = name; } public Main getMain (String name) { return new Main(name){ { System.out.println("name is" + name); } }; } }
内部类的构造参数 如果想要在内部类中使用其他的对象,必须是final
的或者effectively final
的,也就是说不允许内部类修改外界的对象。 什么是effectively final
呢,就是如果你在内部类内部没有修改这个参数,那么jvm
就默认这个是final
的,不需要显式的加final
关键词了。 是在Java8
中引入的,有点像语法糖。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Main { private String name = "hello" ; public Main (String name) { this .name = name; } public Main getMain (String name) { return new Main(name){ { name = "lll" ; } }; } }
显然我们想知道为什么呢?stackoverflow的答案
接口中的内部类 接口中定义的方法默认是public
的, 接口中定义的类默认是static
的。
静态内部类作为测试 一般我们会为每个类做一个main方法进行一些简单的测试。 但是这样编译过之后,class文件中还是有main方法的,占用了空间。 我们可以使用静态内部类作为测试,因为编译过后静态内部类会生成一个单独的class文件, 生产环境中可以不把它包含进去。
我觉得没啥用,因为不止静态内部类,普通内部类和匿名类也会单独生成一个class文件。 生产环境中一个一个删除不是傻逼吗。。。
为什么要引入内部类 作为不能多继承的补充 好有道理
继承内部类 因为内部类拥有外部类的引用,所以继承的时候要有点技巧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Demo { class Inner {} } public class Main extends Demo .Inner { public Main (Demo demo) { demo.super (); } public static void main (String[] args) { } }
内部类重写 内部类可以向方法一样重写吗并进行多态吗 不行