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. 织梦cms 应急响应 修复建议

    通过分析log日志,可以知道攻击者的IP 攻击时间 和具体操作 本片文章为内网测试,通过分析日志,进行复现攻击流程,同时对网站的后门给予修复建议 通过分析日志可以知道,攻击者使用了扫描工具进行网站扫描 ...

  2. ebullient(2018.10.25)

    结论巨好想,每一次操作可以看作把一个b往前移一位,另一个b往后移一位,逆序对个数不改变,判断即可做第一问. 此处代码仅给出第一问做法: #include<cstdio> #include& ...

  3. 51Nod 1127 最短的包含字符串 (尺取法)

    #include <iostream> #include <algorithm> #include <string> #include <cstring> ...

  4. 采集-telegraf

    1 介绍 Telegraf是一款Go语言编写的metrics收集.处理.聚合的代理其设计目标是较小的内存使用,通过插件来构建各种服务和第三方组件的metrics收集Telegraf由4个独立的插件驱动 ...

  5. ZROI 普及组模拟赛02总结

    ZROI 普及组模拟赛02总结 先放[网址][http://zhengruioi.com/contest/96] 可能是有一段时间没有打这种正式的比赛了,今天打的很奇怪... T1 模拟水题 既然是普 ...

  6. Nodejs 定时任务

    安装扩展:node-schedule npm install node-schedule 1.linux Crontab风格 var schedule = require('node-schedule ...

  7. html 手机端click 事件去掉黑色阴影效果

    添加css样式 html{-webkit-text-size-adjust: 100%;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);} 1.  -web ...

  8. nginx 配置步骤

    D:\myphp2017\nginx\conf.nginx.conf37行 吧localhost 改为www.ff.com41行取消注释44行 加D:\myphp2017\nginx\html45 在 ...

  9. 09通过winfrom实现简单的播放音、视频

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  10. springclould feign客户端添加全局参数

    用springclould feign作为调用服务的客户端,一般来说参数可以写在feignclient的方法参数里 有时需要所有feign请求都统一添加一些参数,例如token用于鉴权等,可以这样做: ...