java内部类
来源:互联网 发布:vc6.0 socket编程 编辑:程序博客网 时间:2024/06/11 21:06
java内部类特征
我们看如下代码:
@SuppressWarnings("all")public class OuterClass {public String name;private int age;public OuterClass(String name, int age) {super();this.name = name;this.age = age;}class InnerClass {private String phone;public void say() {System.out.println("hello, I am is innerClass!");}}public static void main(String[] args) {OuterClass outerClass = new OuterClass("xiaotang", 23);//在外部类的静态方法中实例内部类,需要通过外部对象 .new运算符 来实例化InnerClass innerClass = outerClass.new InnerClass();innerClass.say();}}
这是一个最简单的内部类使用,可以看到 在外部类的main方法中 实例化内部类需要用 .new运算符,但是在外部类的 非静态方法中则不需要,代码如下:
@SuppressWarnings("all")public class OuterClass {public String name;private int age;public OuterClass(String name, int age) {super();this.name = name;this.age = age;}class InnerClass {private String phone;public void say() {System.out.println("hello, I am is innerClass!");}}/** * @return 在外部类通过此方法获取内部类实例,只需通过普通的new即可 */public InnerClass InstantInnerClass() {return new InnerClass();}public static void main(String[] args) {OuterClass outerClass = new OuterClass("xiaotang", 23); //实例化外部类中的内部类InnerClass innerClass = outerClass.InstantInnerClass();innerClass.say();}}对比上面两种代码的写法,是不是能够发现:
在外部类中静态方法中实例化内部类,需要使用 .new运算符,显得麻烦些,在非静态方法中实例化内部类,则与普通类的实例没什么区别,所以,我们一般要使用内部类的实例都是采取第二种方案操作的,大家通过看java集合的源码(比如说 List中 Iterator的实现),里面的迭代器的操作,大量使用了这种方法!
内部类原理透析
在这里我首先需要补充说明:内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。对于一个名为 OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class 和OuterClass$InnerClass.class。对于java虚拟机来说,它们就是两个普通的java类,并没有什么不同!
好学的你可能要问了,内部类和外部类最终会被编译器编译成两个不同的类啊,对于虚拟机来说,加载这两个类就是加载两个普通的类,一点关系都没有,那么内部类还有什么意义呢?不就是写两个类,谁不会啊?是的,我们先来看看 OuterClass$InnerClass的编译后的结构:
查看内部类编译后的结构,我们有三种方式:
(1)直接查看编译后的内部类class文件
(1)直接查看编译后的内部类class文件
(2)通过反射去读取内部类信息
(3)通过 javap -private ClassName
在这里,我提一下第三种方式的操作吧!截图如下:
咱通过javap查看 内部类结构如下:
Compiled from "OuterClass.java"class OuterClass$InnerClass extends java.lang.Object{ private java.lang.String phone; final OuterClass this$0; OuterClass$InnerClass(OuterClass); public void say();}
可以看到,内部类中 有一个外部类的实例 this$0,实例的名称可能因为不同的编译器可能不同, 并且会生成一个 形参为外部类实例的的构造方法,构造方法的作用是赋值 this$0,这些都是编译器做的事。看到这,你可能要问了:这不就是类的组合使用吗?在类B中定义 A a属性,然后a就可以调用A中的属性和方法了,为啥还要搞个内部类啊,这么麻烦咧!别急,且听我慢慢道来。
我们再来看看另外一个代码:
@SuppressWarnings("all")public class OuterClass {public String name;private int age;public OuterClass(String name, int age) {super();this.name = name;this.age = age;}class InnerClass {private String phone;//内部类直接调用外部类的私有属性和公有属性public void say() {System.out.println("hello,my name is " + name + ", age is " + age);}}}
可以看到:内部类直接调用外部类的私有属性了,这也印证了内部类的一个重要特点:
内部类可以调用外部类任意修饰符修饰的属型和方法,当然也就包括了私有属性,但是,如果使用类的组合结构能做到吗?答案肯定是做不到的!刚才已经说了,虚拟机加载的就是两个普通的类,那么只能是编译做的特殊处理了,接下来我们就一起看看编译器在这里面都做了哪些努力吧!
还是上面代码,我们通过查看 编译后的OuterClass$InnerClass.class文件可以看到:
import java.io.PrintStream;class OuterClass$InnerClass{ private String phone; OuterClass$InnerClass(OuterClass paramOuterClass) { } public void say() { System.out.println("hello,my name is " + this.this$0.name + ", age is " + OuterClass.access$0(this.this$0)); }}
当内部类调用外部类(OuterClass)的私有属性时,会调用OuterClass的静态方法 access$0得到OuterClass的私有属性,大家有没有发现,OuterClass我们没有定义access$0方法啊,这就是编译器所做的努力!我们 javap OuterClass,查看access$0的指令集:
static int access$0(OuterClass);Code: Stack=1, Locals=1, Args_size=1 0:aload_0 1:getfield#17; //Field age:I 4:ireturn LineNumberTable: line 4: 0
通过指令集还原代码为:
static int access$0(OutClass outerClass){ return outerClass.age;
}看到这大家是不是应该明白了,当我们在 内部类引用外部类的私有属性时,编译器就会在外部类中添加 access$0静态方法,返回对应的属性,如果引用了多个私有属性,则是access$00,acess$000方法,这个不同的编译器取的名字不一样的。好了,讲到这终于,把内部类的原理大概给说清楚了,欢迎大家和我一起讨论,一起学习提高!
0 0
- 【Java】【内部类】Java 内部类简介
- [Java] Java 内部类
- Java 内部类(成员内部类、局部内部类、静态内部类和匿名内部类)
- Java内部类(成员内部类、静态内部类、局部内部类、匿名内部类)小结
- Java内部类(成员内部类、静态内部类、局部内部类、匿名内部类)小结
- Java内部类(成员内部类、局部内部类、静态内部类、匿名内部类)
- Java内部类(成员内部类、静态内部类、局部内部类、匿名内部类)小结
- Java内部类(成员内部类、静态内部类、局部内部类、匿名内部类)小结
- Java内部类(成员内部类、静态内部类、局部内部类、匿名内部类)小结
- java的内部类、匿名内部类、局部内部类
- java内部类之成员内部类、静态内部类
- java 成员内部类 局部内部类,匿名内部类
- Java 静态内部类/内部类
- java内部类、静态内部类 小结
- Java内部类,静态内部类
- JAVA 内部类与静态内部类
- java内部类--局部内部类
- Java 内部类以及匿名内部类
- VectorDrawable:适应不同分辨率的drawable资源
- 【record】10.2..10.9
- Spark Streanming模式的一个完整例子
- GirlFriendNotFoundException异常是怎样处理的?
- armeabi armeabi-v7a mips x86 理解
- java内部类
- Jsp中 table 使用<c:forEach>实现各行3个,之后自动换行
- javax.persistence.JoinColumn.foreignKey()Ljavax/persistence/ForeignKey
- 常用的js正则
- 抓取动态网页
- eventbus 配置
- spring+dubbo+java8 Component-scan异常记录
- Android Camera 使用小结
- UML系列图——类图与对象图