设为首页 加入收藏

TOP

夯实Java基础系列18:深入理解Java内部类及其实现原理(一)
2019-10-09 20:03:31 】 浏览:37
Tags:夯实 Java 基础 系列 深入 理解 部类 及其 实现 原理

本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看

https://github.com/h2pl/Java-Tutorial

喜欢的话麻烦点下Star哈

文章首发于我的个人博客:

www.how2playlife.comww.how2playlife.com

内部类初探

什么是内部类?

  内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的。内部类可为静态,可用protected和private修饰(而外部类只能使用public和缺省的包访问权限)。内部类主要有以下几类:成员内部类、局部内部类、静态内部类、匿名内部类

内部类的共性

(1)内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。

(2)内部类不能用普通的方式访问。

(3)内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。

(4)外部类不能直接访问内部类的的成员,但可以通过内部类对象来访问

  内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的。

  因为当某个外围类的对象创建内部类的对象时,此内部类会捕获一个隐式引用,它引用了实例化该内部对象的外围类对象。通过这个指针,可以访问外围类对象的全部状态。

通过反编译内部类的字节码,分析之后主要是通过以下几步做到的:

  1 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象的引用;

  2 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为1中添加的成员变量赋值;

  3 在调用内部类的构造函数初始化内部类对象时, 会默认传入外部类的引用。

使用内部类的好处:

静态内部类的作用:

1 只是为了降低包的深度,方便类的使用,静态内部类适用于包含类当中,但又不依赖与外在的类。

2 由于Java规定静态内部类不能用使用外在类的非静态属性和方法,所以只是为了方便管理类结构而定义。于是我们在创建静态内部类的时候,不需要外部类对象的引用。

非静态内部类的作用:

1 内部类继承自某个类或实现某个接口,内部类的代码操作创建其他外围类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。

2 使用内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响

3 如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。
从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了"多重继承"。

那静态内部类与普通内部类有什么区别呢?

问得好,区别如下:

(1)静态内部类不持有外部类的引用
在普通内部类中,我们可以直接访问外部类的属性、方法,即使是private类型也可以访问,这是因为内部类持有一个外部类的引用,可以自由访问。而静态内部类,则只可以访问外部类的静态方法和静态属性(如果是private权限也能访问,这是由其代码位置所决定的),其他则不能访问。

(2)静态内部类不依赖外部类
普通内部类与外部类之间是相互依赖的关系,内部类实例不能脱离外部类实例,也就是说它们会同生同死,一起声明,一起被垃圾回收器回收。而静态内部类是可以独立存在的,即使外部类消亡了,静态内部类还是可以存在的。

(3)普通内部类不能声明static的方法和变量
普通内部类不能声明static的方法和变量,注意这里说的是变量,常量(也就是final static修饰的属性)还是可以的,而静态内部类形似外部类,没有任何限制。

为什么普通内部类不能有静态变量呢?

1 成员内部类 之所以叫做成员 就是说他是类实例的一部分 而不是类的一部分

2 结构上来说 他和你声明的成员变量是一样的地位 一个特殊的成员变量 而静态的变量是类的一部分和实例无关

3 你若声明一个成员内部类 让他成为主类的实例一部分 然后又想在内部类声明和实例无关的静态的东西 你让JVM情何以堪啊

4 若想在内部类内声明静态字段 就必须将其内部类本身声明为静态

非静态内部类有一个很大的优点:可以自由使用外部类的所有变量和方法

下面的例子大概地介绍了

1 非静态内部类和静态内部类的区别。

2 不同访问权限的内部类的使用。

3 外部类和它的内部类之间的关系

//本节讨论内部类以及不同访问权限的控制
//内部类只有在使用时才会被加载。
//外部类B
public class B{
    int i = 1;
    int j = 1;
    static int s = 1;
    static int ss = 1;
    A a;
    AA aa;
    AAA aaa;
    //内部类A

    public class A {
//        static void go () {
//
//        }
//        static {
//
//        }
//      static int b = 1;//非静态内部类不能有静态成员变量和静态代码块和静态方法,
        // 因为内部类在外部类加载时并不会被加载和初始化。
        //所以不会进行静态代码的调用
        int i = 2;//外部类无法读取内部类的成员,而内部类可以直接访问外部类成员

        public void test() {
            System.out.println(j);
            j = 2;
            System.out.println(j);
            System.out.println(s);//可以访问类的静态成员变量
        }
        public void test2() {
            AA aa = new AA();
            AAA aaa = new AAA();
        }

    }
    //静态内部类S,可以被外部访问
    public static class S {
        int i = 1;//访问不到非静态变量。
        static int s = 0;//可以有静态变量

        public static void main(String[] args) {
            System.out.println(s);
        }
        @Test
        public void test () {
//            System.out.println(j);//报错,静态内部类不能读取外部类的非静态变量
            System.out.println(s);
            System.out.println(ss);
            s = 2;
            ss = 2;
            System.out.println(s);
            System.out.println(ss);
        }
    }

    //内部类AA,其实这里加protected相当于default
    //因为外部类要调用内部类只能通过B。并且无法直接继承AA,所以必须在同包
    //的类中才能调用到(这里不考虑静态内部类),那么就和default一样了。
    protected class AA{
        int i = 2;//内部类之间不共享变量
        public void test (){
            A a = new A();
            AAA aaa = new AAA();
            //内部类之间可以互相访问。
        }
    }
    //包外部依然无法访问,因为包没有继承关系,所以找不到这个类
    protected static class SS{
        int i = 2;//内部类之间不共享变量
        public v
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇夯实Java基础系列17:一文搞懂Jav.. 下一篇夯实Java基础系列19:一文搞懂Jav..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目