1.四种内部类

java中的四种内部类:成员内部类、静态内部类、局部内部类和匿名内部类。其中匿名内部类用到的最多。

1.1.成员内部类

若一个类定义在另一个类的内部作为实例成员,我们把这个作为实例成员的类称之为成员内部类,也可以叫做实例成员内部类。

在成员内部类的里面可以无条件的访问外部类的任何成员(包括private成员和静态成员)。

class Circle {

    private double radius = 0;

    public static int count =1;

    public Circle(double radius) {

        this.radius = radius;

    }     

    class Draw {     //内部类无条件的访问外部类成员

        public void drawSahpe() {

            System.out.println(radius);  //外部类的private成员

            System.out.println(count);   //外部类的静态成员

        }

    }

}

但是,在外部类中访问成员内部类的成员,必须要通过内部类的对象才能访问,而不能直接访问。

class Circle {

    private double radius = 0;

    public Circle(double radius) {

        this.radius = radius;

        getDrawInstance().drawSahpe();   //必须先创建成员内部类的对象,再进行访问

    }     

    private Draw getDrawInstance() {

        return new Draw();

    }     

    class Draw {     //内部类

        public void drawSahpe() {

            System.out.println(radius);  //外部类的private成员

        }

    }

}

1.2.静态内部类

若一个类定义在另一个类的内部且加了static关键字作为静态成员,我们把这个作为静态成员的类称之为静态内部类。

静态内部类是不需要依赖于外部类实例的,这点和类的其它静态成员一样,作为静态成员他只能访问外部类的静态成员 ,而不能访问外部类的实例成员。

public class OuterClass {

private String outerClass1="我是外部类的实例成员";

private static String outerClass2="我是外部类的静态成员";

private static class StaticInnerClass{

public void printOuterClassMumber(){

//静态内部类里面只能访问外部类的静态成员

//System.out.println(outerClass1);此句需被注释掉否则会报错

System.out.println(outerClass2);

}
}
}

同成员内部类一样,外部类中也不能直接访问静态内部类成员,必须要通过内部类的对象才能访问。但是和成员内部类不同的是,静态内部类中可以定义静态成员,若外部类访问的是静态内部类的静态成员,则可以通过类名来完成,就无需创建静态内部类对象。

public class OuterClass {
private static class StaticInnerClass{
private String staticInnerClass1="我是静态内部类的实例成员变量";
private static String staticInnerClass2="我是静态内部类的静态成员变量";
}
public void staticInnerClassTest(){
//必须要通过内部类对象才能访问实例变量
System.out.println(new StaticInnerClass().staticInnerClass1);
//可以通过类名来访问静态变量
System.out.println(StaticInnerClass.staticInnerClass2);
}
}

1.3.局部内部类

局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法或者该作用域内。局部内部类同局部变量一样,不能加如何访问修饰符,在其作用域外不能被访问。

class OuterClass {
public void localInnerClassTest(){
System.out.println("<<<<<<<<<<<<<<<<测试局部内部类>>>>>>>>>>>>>>>>>");
class LocalInnerClass{
public void pritTest(){
System.out.println("我是局部内部类");
}
}
new LocalInnerClass().pritTest();
}
}

1.4.匿名内部类

匿名内部类通过父类类名加上子类类体new出子类对象,减少了单独定义子类的环节。

public class OuterClass {
public void anonymousInnerClassTest(){
System.out.println("<<<<<<<<<<<<<<<<测试匿名内部类>>>>>>>>>>>>>>>>>");
new AnonymousClass(){
public void printAnonymousClass(){
System.out.println("我是生成的匿名内部类");
}
}.printAnonymousClass();
} }

2.深入理解内部类

2.1.成员内部类为什么可以无条件的访问外部类的所有成员

我们通过查看编译后的文件可知,编译后内部类和外部类不再是嵌套关系,而是在同一个包下的两个类,并将内部类命名为"外部类类名$内部类类名.class"。

不仅如此,通过反编译成员内部类.class文件可知,编译器为内部类生成了一个指向外部类对象的引用this$0和一个以外部类对象引用作为形参的构造函数。当创建内部类对象时,通过构造函数给对象引用this$0赋值,更为重要的是针对外部类的私有成员还会创建访问他们的accesso方法。结合指向外部类的对象和访问私有成员的方法,才实现了内部类对外部类的无条件访问。这里也间接说明了成员内部类是依赖于外部类的,如果没有创建外部类的对象,则无法对Outter this&0进行赋值,也就无法创建成员内部类对象了。

下面是经编译后的成员内部类字节码文件:

class OuterClass$MumberInnerClass {
private String mumberInnerClass1;
private OuterClass$MumberInnerClass(OuterClass var1) {
this.this$0 = var1;
this.mumberInnerClass1 = "我是成员内部类的实例变量";
}
public void printOuterClassMumber() {
System.out.println(OuterClass.access$000(this.this$0));
System.out.println(OuterClass.access$100());
}
}

2.2.外部类中为什么要创建内部类的对象才能访问内部类成员

成员内部类中对外部类的访问是无条件的,但是外部类中访问内部类成员需要通过内部类对象才能完成。原因在于编译器并未在外部类中自动创建内部类对象,所以需要自己去创建。

下面是编译后的外部类字节码文件,可以看出外部类经编译后没有自动创建内部类对象。

package innerClassTest;

public class OuterClass {
private String outerClass1 = "我是外部类的实例成员";
private static String outerClass2 = "我是外部类的静态成员"; public OuterClass() {
} public void mumberInnerClassTest() {
System.out.println("<<<<<<<<<<<<<<<<1.测试成员内部类>>>>>>>>>>>>>>>>>");
System.out.println((new OuterClass.MumberInnerClass(null)).mumberInnerClass1);
(new OuterClass.MumberInnerClass(null)).printOuterClassMumber();
} public void staticInnerClassTest() {
System.out.println("<<<<<<<<<<<<<<<<2.测试静态内部类>>>>>>>>>>>>>>>>>");
System.out.println((new OuterClass.StaticInnerClass(null)).staticInnerClass1);
System.out.println(OuterClass.StaticInnerClass.staticInnerClass2);
(new OuterClass.StaticInnerClass(null)).printOuterClassMumber();
} public void localInnerClassTest() {
System.out.println("<<<<<<<<<<<<<<<<3.测试局部内部类>>>>>>>>>>>>>>>>>");
class LocalInnerClass {
LocalInnerClass() {
} public void pritTest() {
System.out.println("我是局部内部类");
}
} (new LocalInnerClass()).pritTest();
} public void anonymousInnerClassTest() {
System.out.println("<<<<<<<<<<<<<<<<测试匿名内部类>>>>>>>>>>>>>>>>>");
(new AnonymousClass() {
public void printAnonymousClass() {
System.out.println("我是生成的匿名内部类");
}
}).printAnonymousClass();
} private static class StaticInnerClass {
private String staticInnerClass1;
private static String staticInnerClass2 = "我是静态内部类的静态成员变量"; private StaticInnerClass() {
this.staticInnerClass1 = "我是静态内部类的实例成员变量";
} public void printOuterClassMumber() {
System.out.println(OuterClass.outerClass2);
}
} private class MumberInnerClass {
private String mumberInnerClass1; private MumberInnerClass() {
this.mumberInnerClass1 = "我是成员内部类的实例变量";
} public void printOuterClassMumber() {
System.out.println(OuterClass.this.outerClass1);
System.out.println(OuterClass.outerClass2);
}
}
}

2.3.四种内部类的区别

1.四种内部类经编译后均会产生独立的class文件,除了静态内部类以外编译器均会为内部类添加一个指向外部类的引用,使得内部类能无条件访问外部类成员。

2.虽然内部类经编译后会产生独立的字节码文件,但是仍然要满足作为外部类成员的要求,即成员内部类中不能定义静态成员、静态内部类中可以定义静态成员、局部内部类同局部变量一样不能被其作用域以外的地方访问。

3.在外部类的外面创建内部类对象

a.由于成员内部类是依赖于外部类的,所以创建成员内部类对象必须先创建外部类对象。

b.静态内部类是不依赖外部类的,因此可以无需创建外部类对象而直接创建静态内部类对象。

下面是外部类之外创建内部类对象的案例:

public class Test {
public static void main(String[] args) {
OuterClass outerClass=new OuterClass();
OuterClass.MumberInnerClass mumberInnerClassInstance=outerClass.new MumberInnerClass();
mumberInnerClassInstance.printOuterClassMumber();
OuterClass.StaticInnerClass staticInnerClassInstance=new OuterClass.StaticInnerClass();
staticInnerClassInstance.printOuterClassMumber();
}
}

本文参考与:Java内部类详解 Java外部类可以访问内部类private变量

【Java_基础】Java内部类详解的更多相关文章

  1. Java内部类详解

    Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...

  2. [转] Java内部类详解

    作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...

  3. 【转】Java内部类详解

    一.内部类基础 在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类.广泛意义上的内部类一般来说包括这四种:成员内部类.局部内部类.匿名内部类和静态内部类.下面就先来了解一 ...

  4. Java内部类详解(一)

    (转自:http://blog.csdn.net/wangpeng047/article/details/12344593) 很多人对于Java内部类(Inner Class)都十分陌生,甚至听都没听 ...

  5. Java内部类详解 2

    Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...

  6. Java——内部类详解

    说起内部类,大家肯定感觉熟悉又陌生,因为一定在很多框架源码中有看到别人使用过,但又感觉自己使用的比较少,今天我就带你具体来看看内部类. 内部类基础 所谓内部类就是在类的内部继续定义其他内部结构类. 在 ...

  7. Java内部类详解(转)

    说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就来一探究竟.下面是本 ...

  8. (转)java内部类详解

    本文转自http://www.cnblogs.com/dolphin0520/p/3811445.html,谢谢作者 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能 ...

  9. Java 内部类详解

    什么 定义在一个类内部的类,称为内部类(累不累),如下: public class A { private int c = 1; public class C { public void test() ...

随机推荐

  1. BackgroundWorker的使用一二(可视化编程,开始后台工作,报告进度,取消后台工作等)

    C# 提供了BackgroundWorker功能非常强大,可以将某项工作放到后台运行,可以让后台报告进度,可以取消后台工作...... BackgroundWorker的上述功能是通过 1. 三个主要 ...

  2. endless(2018.10.25)

    这题就是个线段树合并板子. #include<cstdio> #include<algorithm> #include<cstring> using namespa ...

  3. tensorflow:实战Google深度学习框架第四章02神经网络优化(学习率,避免过拟合,滑动平均模型)

    1.学习率的设置既不能太小,又不能太大,解决方法:使用指数衰减法 例如: 假设我们要最小化函数 y=x2y=x2, 选择初始点 x0=5x0=5  1. 学习率为1的时候,x在5和-5之间震荡. im ...

  4. [ZJOI2008]无序运动Movement

    Description D博士对物理有着深入的研究,经典物理.天体物理.量子物理都有着以他的名字命名的定理.最近D博士着迷于研究粒子运动的无规则性.对圣经深信不疑的他相信,上帝创造的任何事物必然是有序 ...

  5. BZOJ1218(线段树+扫描线)

    1.扫描线扫描x轴,线段树维护y轴. 2.坐标+1,线段树是从1开始维护.然后让边长--,这样就能包含边上的点了. 3.为了保证点在正方形内:在x轴上利用差分的思想,在x出Add(val),在x+r( ...

  6. UVA10305:Ordering Tasks(拓扑排序)

    John has n tasks to do. Unfortunately, the tasks are not independent and the execution of one task i ...

  7. JavaScript特点、优缺点及常用框架

    参考来源:   http://www.cnblogs.com/SanMaoSpace/archive/2013/06/14/3136774.html

  8. idea中deployment点击加号没有出现artifact

    转载 在主页面打开ProjectStructure,点击图示的按钮或是按ctrl+shift+alt+s快捷键 打开ProjectStructure后,按照图示依次点击Facets->+号,在弹 ...

  9. 惊人的CSS和JavaScript动画logos例子

    https://codepen.io/lindell/pen/mEVgJP Stack Overflow logo是我最喜欢的logo之一,因为它非常简单,但易于识别.并且这个片段动画点击预览Stac ...

  10. 打造自己的JavaScript武器库

    自己打造一把趁手的武器,高效率完成前端业务代码. 前言 作为战斗在业务一线的前端,要想少加班,就要想办法提高工作效率.这里提一个小点,我们在业务开发过程中,经常会重复用到日期格式化.url参数转对象. ...