Java 内部类 随笔
来源:互联网 发布:类似天蝎的美剧 知乎 编辑:程序博客网 时间:2024/06/18 07:58
最近突然想到把Java基础过一遍, 想到就开始做, 先从内部类走起!
先尝试写了个内部类, 来看编译生成的文件, 生成了两个class 文件Outer.class和Outer$Inner.class.所以内部类的成员变量/方法名可以和外部类的相同。
网上搜了一下资料, 本来想看看官网有没有什么官方的描述, 苦于没找到,只能看别人写的随笔。
网上的说法,内部类分了4类: 常规内部类(又有人叫成员内部类)、静态内部类、局部内部类、匿名内部类。
1. 常规内部类(成员内部类)
就是做为外部类的成员,可以直接使用外部类的所有成员和方法,包括private和静态成员。
当成员内部类访问和外部类同名的方法或成员的时候,实际上访问的是内部类的成员和方法。如果 成员内部类想引用外部类对象,可以用
外部类名.this.方法
外部类名.this.成员变量
要创建内部类对象,可以使用 外部类名.内部类名 变量 = 外部类对象.new 内部类名() 来创建, e.g: Outer.Inner i = o.new Inner();
或通过外部类的方法返回。 如下例:
package javaLearing.InnerClass;public class Outer { public String str1 = "str1"; protected String str2 = "str2"; private String str3 = "str3"; private static String str4 = "str4"; private void print() { System.out.println("Outer str1:" + str1); System.out.println("Outer str2:" + str2); System.out.println("Outer str3:" + str3); System.out.println("Outer str4:" + str4); } public Inner getInnerInstance() { return new Inner(); } public class Inner { public String str3 = "Inner str3"; private String str4 = "Inner Str4"; public void print() { System.out.println("Inner class print"); System.out.println("Outer str1:" + str1); System.out.println("Outer str2:" + str2); System.out.println("Outer str3:" + str3); System.out.println("Outer str4:" + str4); Outer.this.print(); System.out.println("Outer:" + Outer.this); System.out.println("Outer str3 actual should be:" + Outer.this.str3); System.out.println("Outer static str4 actual should be:" + Outer.str4); } } public static void main(String[] args) { Outer o = new Outer(); Outer.Inner i = o.new Inner(); Outer.Inner i2 = o.getInnerInstance(); i.print(); i2.print(); }}
结果:
Inner class printOuter str1:str1Outer str2:str2Outer str3:Inner str3Outer str4:Inner Str4Outer str1:str1Outer str2:str2Outer str3:str3Outer str4:str4Outer:javaLearing.InnerClass.Outer@15db9742Outer str3 actual should be:str3Outer static str4 actual should be:str4Inner class printOuter str1:str1Outer str2:str2Outer str3:Inner str3Outer str4:Inner Str4Outer str1:str1Outer str2:str2Outer str3:str3Outer str4:str4Outer:javaLearing.InnerClass.Outer@15db9742Outer str3 actual should be:str3Outer static str4 actual should be:str4
注意: 成员内部类不能含有static 的变量和方法。
生成的class 文件如下:
反编译看看
(去网上下了一个jd-gui,http://jd.benow.ca/. (我也试了一下jdec(http://jdec.sourceforge.net/), 反编译的代码看的我egg pain. 还有就是java 自带的javap -v命令也是看起头大):
看内部类的购造函数,就了解为什么可以访问外部类的成员变量了。
2. 静态内部类
用static 修饰的内部类。 只能访问外部类的静态成员变量和方法。所以也不能通过this 来访问外部类的实例成员变量和方法。
package javaLearing.InnerClass;public class Outer2 { public static String str1 = "str1"; public static String str2 = "str2"; public Inner getInnerInstance() { return new Inner(); } private static void print() { System.out.println("Outer str1:" + str1); System.out.println("Outer str2:" + str2); } public static class Inner { private String str1 = "Inner str1"; public void print() { System.out.println("Inner class print"); System.out.println("Outer str1:" + Outer2.str1); System.out.println("Outer str2:" + str2); System.out.println("Inner str1:" + str1); Outer2.print(); } } public static void main(String[] args) { Outer2.Inner i = new Outer2.Inner(); i.print(); }}
结果
Inner class printOuter str1:str1Outer str2:str2Inner str1:Inner str1Outer str1:str1Outer str2:str2
生成的class 文件如下:
反编译看看:
静态内部类并没有持有外部类的引用。
3. 局部内部类
定义在方法体或者一个作用域内的内部类。不能带private, public, protected修饰符。可以带final, abstract。类似一个局部变量。 可以访问外部类的成员变量和方法。 可以访问作用域的参数和局部变量。 相应的, static 方法/语句块中定义的内部类,只能访问静态成员。
package javaLearing.InnerClass;interface InnerInterface{ public void print();}public class Outer3 { public String str1 = "str1"; protected String str2 = "str2"; private String str3 = "str3"; private static String str4 = "str4"; public void print() { System.out.println("Outer3 str1:" + str1); System.out.println("Outer3 str2:" + str2); System.out.println("Outer3 str3:" + str3); System.out.println("Outer3 str4:" + str4); } public static void InnerPrint() { class Inner implements InnerInterface{ private String str1 = "Static Method Inner str1"; public void print() { System.out.println("Static Method Inner class print"); System.out.println("Inner str1:" + str1); System.out.println("Outer3 str4:" + Outer3.str4); } } Inner i = new Inner(); i.print(); } public InnerInterface getInnerInstance(boolean b) { int var = 10; Outer3 o = new Outer3(); class Inner implements InnerInterface{ private String str1 = "Inner str1"; public void print() { System.out.println("Inner class print"); System.out.println("Method parameter:" + b); System.out.println("Method variable:" + var); System.out.println("Method o:" + o); System.out.println("Inner str1:" + str1); System.out.println("Outer3 str1:" + Outer3.this.str1); System.out.println("Outer3 str2:" + Outer3.this.str2); System.out.println("Outer3 str3:" + Outer3.this.str3); System.out.println("Outer3 str4:" + Outer3.str4); Outer3.this.print(); } } if(b) { class Inner2 extends Inner{ private String str2 = "Inner2 str2"; public void print() { System.out.println("Method parameter:" + b); System.out.println("Method variable:" + var); System.out.println("Inner2 class print"); System.out.println("Inner str1:" + super.str1); System.out.println("Inner2 str2:" + str2); } } Inner2 i = new Inner2(); i.print(); } return new Inner(); } public static void main(String[] args) { InnerInterface i = new Outer3().getInnerInstance(true); i.print(); Outer3.InnerPrint(); }}结果
Method parameter:trueMethod variable:10Inner2 class printInner str1:Inner str1Inner2 str2:Inner2 str2Inner class printMethod parameter:trueMethod variable:10Method o:javaLearing.InnerClass.Outer3@15db9742Inner str1:Inner str1Outer3 str1:str1Outer3 str2:str2Outer3 str3:str3Outer3 str4:str4Outer3 str1:str1Outer3 str2:str2Outer3 str3:str3Outer3 str4:str4Static Method Inner class printInner str1:Static Method Inner str1Outer3 str4:str4
注意: 在局部内部类中访问方法的参数和局部变量,是可以访问得到的,如上面的例子,但是如果做修改, 不管是在内部类内还是在方法中,会报编译时错误:
网上的贴子说要把参数和局部变量声明成final.至于为什么要声明成final, 我们知道被声明成final的变量是不能被改变的,显示声明成final就是让其不能被改变。 那变了又会怎么样呢?
首先, 我们看,上面的代码
生成的class文件如下:
(这里看到,在内部类名前有一个数字。 很明显,在不同作用域中是可以存在同名的内部类的,生成的class文件以数字编号来区分。)
我们来反编译看看,
从代码看,大概意思是内部类自己拷贝了一份参数和局部变量的引用。 为什么要这样做, 是因为局部变量的生命周期和局部内部类实例的不一样的,比如方法块完了,把内部类实例返回了,局部变量在方法块结束的时候就去释放去了。
即然有了拷贝,就有可能有不一致。 所以用final. 这是网上的原话, 我很好奇对象是怎么做的拷贝,按引用计数原理,只要有引用就不会被释放,对象是不是就直接在内部类内部用成员变量保存一份引用? 那这个一致性针对对象似乎不太说得通, 不过换一想,如果外部让局部变量指向别的对象引用,也算是一种修改,但这个却无法反应到内部类里面,也算是造成了不一致。
4. 匿名内部类
new ClassOrInterfaceName(){/*类体*/}
<pre name="code" class="java">package javaLearing.InnerClass;interface NiMinInterface { public void print();}abstract class NiMinClass { public NiMinClass(String name, String city) { System.out.println(city); city = "change city"; System.out.println(city); } abstract public void print();}public class Outer4 { public NiMinInterface getInnerInstance(String param) { Outer4 o = new Outer4(); return new NiMinInterface() { @Override public void print() { System.out.println("NiMin Inner class"); System.out.println(param); System.out.println(o); } }; } public NiMinClass getNiMinClass(String name, String city) { return new NiMinClass(name, city) { private String nameStr = name; private String cityStr = city; @Override public void print() { System.out.println("NiMin Inner class"); System.out.println(nameStr); System.out.println(cityStr); } }; } public static void main(String[] args) { NiMinInterface i = new Outer4().getInnerInstance("param"); i.print(); NiMinClass j = new Outer4().getNiMinClass("name", "city"); j.print(); }}
结果
<pre name="code" class="java"><pre name="code" class="java">NiMin Inner classparamjavaLearing.InnerClass.Outer4@15db9742citychange cityNiMin Inner classnamecity
生成的class文件如下:
1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
3.方便编写事件驱动程序
4.方便编写线程代码
最后补充一点知识:关于成员内部类的继承问题。一般来说,内部类是很少用来作为继承用的。但是当用来继承的话,要注意两点:
1)成员内部类的引用方式必须为 Outter.Inner.
2)构造器中必须有指向外部类对象的引用,并通过这个引用调用super()。这段代码摘自《Java编程思想》
class
WithInner {
class
Inner{
}
}
class
InheritInner
extends
WithInner.Inner {
// InheritInner() 是不能通过编译的,一定要加上形参
InheritInner(WithInner wi) {
wi.
super
();
//必须有这句调用
}
public
static
void
main(String[] args) {
WithInner wi =
new
WithInner();
InheritInner obj =
new
InheritInner(wi);
}
}
- Java 内部类 随笔
- #随笔之java匿名内部类
- 随笔记-内部类
- Java复习笔记---小随笔---匿名内部类
- think in java第十章内部类 总结随笔
- 《Java编程思想》——内部类,随笔
- 【Java】【内部类】Java 内部类简介
- (java随笔)关于java的内部函数和内部类
- [Java] Java 内部类
- Java 内部类(成员内部类、局部内部类、静态内部类和匿名内部类)
- Java内部类(成员内部类、静态内部类、局部内部类、匿名内部类)小结
- Java内部类(成员内部类、静态内部类、局部内部类、匿名内部类)小结
- Java内部类(成员内部类、局部内部类、静态内部类、匿名内部类)
- Java内部类(成员内部类、静态内部类、局部内部类、匿名内部类)小结
- Java内部类(成员内部类、静态内部类、局部内部类、匿名内部类)小结
- Java内部类(成员内部类、静态内部类、局部内部类、匿名内部类)小结
- java的内部类、匿名内部类、局部内部类
- java内部类之成员内部类、静态内部类
- 欢迎使用CSDN-markdown编辑器
- linux RAW SOCKET加Packet af定制2层报文
- swift基础学习传值[属性传值、代理、block代码块、等]
- 强大的分布式消息中间件——kafka
- 代码覆盖率 (Code Coverage)从简到繁 (一)
- Java 内部类 随笔
- poj 3013 Big Christmas Tree (最短路)
- Java 数组的四种排序方法 代码
- 几个靠谱的maven仓库镜像地址
- python -u predict.py --gpus 1 --img 1.jpg and python -u predict.py --gpus 0 --img 1.jpg
- raptor程序:三色球
- WEUI应用,用JS封装常用信息提示的弹层—Msg
- scrollView 与autolayout
- 标准文件I/O操作