美文网首页
Java内部类

Java内部类

作者: 四喜汤圆 | 来源:发表于2018-10-25 11:14 被阅读4次

一、内部类作用

二、使用

a)通用规则

1.类相关、实例相关

1)普通内部类、匿名内部类、局部内部类对象的创建依赖于外部类对象,普通内部类、匿名内部类、局部内部类对象中持有外部类引用。(由编译器在字节码文件中自动添加外部类类型的变量,并通过带参的构造函数将实例传入)
2)静态内部类对象的创建独立于外部类对象(静态内部类是类相关的)

普通内部类对象中持有外部类对象的引用

参见下文

匿名内部类对象中持有外部类对象的引用

对于下文中匿名内部类的代码,其对应的字节码文件中:


持有外部类对象的引用

局部内部类对象中持有外部类对象的引用

对于下文中局部内部类的代码,其对应的字节码文件中:


持有外部类对象的引用

2.外部类/内部类中私有字段的可访问性

内部类类型 外部类中可否访问内部类的私有数据(包括变量、方法) 内部类中可否访问外部类的私有数据(包括变量、方法)
普通内部类
静态内部类
匿名内部类 ×
局部内部类 ×

Q:为什么可以访问到私有数据?

普通内部类

public class InnerClassTest {
    private int outField1=1;
    int outField2=2;
    protected int outField3=3;
    public int outField4=4;

    private void outF1(){
    
    }

    public InnerClassTest(){
        InnerClassA innerObj=new InnerClassA();
        System.out.println("create "+this.getClass().getSimpleName()+"object");
        System.out.println("the value of inner class field1="+ innerObj.field1);
        System.out.println("the value of inner class field2="+ innerObj.field2);
        System.out.println("the value of inner class field3="+ innerObj.field3);
        System.out.println("the value of inner class field4="+ innerObj.field4);
        innerObj.innerF1();
    }

    // nor static inner class
    public class InnerClassA{
        private int field1=5;
        int field2=6;
        protected int field3=7;
        public int field4=8;
//        static int field5=1;// compile error

        public InnerClassA(){
            System.out.println("create"+this.getClass().getSimpleName()+"object");
            System.out.println("the value of outer class field1="+outField1);
            System.out.println("the value of outer class field2="+outField2);
            System.out.println("the value of outer class field3="+outField3);
            System.out.println("the value of outer class field4="+outField4);
            outF1();
        }

        private void innerF1(){
        }
    }

    public static void main(String[] args) {
        InnerClassTest test = new InnerClassTest();
    }
}

普通内部类对应的字节码文件中,编译器自动添加了外部类类型的变量


,并添加了一个带参的构造函数将外部类实例传入【故普通内部类对象中持有外部类对象的引用】

当在普通内部类中有代码访问外部类中私有数据(变量、方法)时System.out.println("the value of outer class field1="+outField1);outF1();),编译器会在外部类对应的字节码中添加静态方法access(),该方法需要传入一个外部类对象,在该方法中返回私有字段值,或调用私有方法。


若在普通内部类中无访问外部类私有数据的代码,则字节码文件中不会生成access方法

当在外部类中有代码访问普通内部类中私有数据(变量、方法)时System.out.println("the value of StaticInnerClass field1="+obj.staticInnerField1);innerObj.innerF1();),编译器会在普通内部类对应的字节码中添加静态方法access(),该方法需要传入一个普通内部类对象,在该方法中返回私有字段值,或调用私有方法。


若在外部类中无访问普通内部类私有数据的代码,则字节码文件中不会生成access方法

静态内部类

/**
 * <pre>
 *     author : 杨丽金
 *     time   : 2018/10/24
 *     desc   : 静态内部类【在外部类中访问静态内部类私有成员;在静态内部类中访问外部类私有成员】
 *     version: 1.0
 * </pre>
 */
public class StaticInnerClassTest {

    private int outField1=1;
    int outField2=2;
    protected int outField3=3;
    public int outField4=4;


    public StaticInnerClassTest(){
        System.out.println("create "+this.getClass().getSimpleName()+" object");
        // must create StaticInnerClassTest object manually
        StaticInnerClass obj = new StaticInnerClass();
       // System.out.println("the value of StaticInnerClass field1="+obj.staticInnerField1);
        System.out.println("the value of StaticInnerClass field2="+obj.staticInnerField2);
        System.out.println("the value of StaticInnerClass field3="+obj.staticInnerField3);
        System.out.println("the value of StaticInnerClass field4="+obj.staticInnerField4);
    }

    // static class
    public static class StaticInnerClass{
        private int staticInnerField1=1;
        int staticInnerField2=2;
        protected int staticInnerField3=3;
        public int staticInnerField4=4;

        public StaticInnerClass(){
            System.out.println("create "+this.getClass().getSimpleName()+" object");
            // must create StaticInnerClassTest object manually
            StaticInnerClassTest obj=new StaticInnerClassTest();
            //System.out.println("the value of out class field1="+obj.outField1);
            System.out.println("the value of out class field2="+obj.outField2);
            System.out.println("the value of out class field3="+obj.outField3);
            System.out.println("the value of out class field4="+obj.outField4);
        }
    }
}

当在静态内部类中有代码访问外部类中私有数据(变量、方法)时System.out.println("the value of out class field4="+obj.outField4);),编译器会在外部类对应的字节码中添加静态方法access(),该方法需要传入一个外部类对象(手动创建StaticInnerClassTest obj=new StaticInnerClassTest();),将该对象的私有字段值返回。


若在静态内部类中无访问外部类私有字段的代码,则外部类字节码文件中不会生成access方法

当在外部类中有代码访问静态内部类中私有数据(变量、方法)时System.out.println("the value of StaticInnerClass field1="+obj.staticInnerField1);),编译器会在静态内部类对应的字节码中添加一个静态方法access(),该方法需要传入一个静态内部类对象,将该对象的私有字段值返回。


若在外部类中无访问静态内部类私有字段的代码,则静态内部类字节码文件中不会生成access方法

匿名内部类

/**
 * <pre>
 *     author : 杨丽金
 *     time   : 2018/10/25
 *     desc   : 匿名内部类
 *     version: 1.0
 * </pre>
 */
public class AnonymousInnerTest {
    private int outField1=1;
    int outField2=2;
    protected int outField3=3;
    public int outFiled4=4;

    // 定义接口
    public interface OnCliclListener {
        void onClick(Object obj);
    }

    // 匿名内部类:实现接口或继承父类
    private void anonymousClassTest(){
        OnCliclListener listener=new OnCliclListener() {
            // 定义属性,但外部类访问不到(因为外部类获取不到匿名内部类类名,所以也就无法创建匿名内部类对象)
            int innerField=1;
            @Override
            public void onClick(Object obj) {
                System.out.println("对象 "+obj+"被点击");
                System.out.println(outField1);
                System.out.println(outField2);
                System.out.println(outField3);
                System.out.println(outFiled4);
            }
        };
        listener.onClick(new Object(){
            @Override
            public String toString() {
                return "Myobj";
            }
        });
    }

    public static void main(String[] args) {
        AnonymousInnerTest test = new AnonymousInnerTest();
        test.anonymousClassTest();
    }
}

在匿名内部类对应的字节码文件中:1)该类中虽然定义了私有数据,但不可被外部类访问到;
在外部类对应的字节码文件中:1)为匿名内部类中访问的私有数据提供了相应的静态方法供调用。

局部内部类

public class LocalInnerTest {
    private int outField1=1;
    int outField2=2;
    protected int outField3=3;
    public int outField4=4;

    // 外部类的私有方法
    private void outF1(){

    }

    private void localInnerClassTest(){
        // 方法内部类
        class A{
            public A(){
                System.out.println("create A object");
                System.out.println(outField1);
                System.out.println(outField2);
                System.out.println(outField3);
                System.out.println(outField4);
                outF1();
            }
        }
        A a=new A();
        if(true){
            class B{
                public B(){
                    System.out.println("create B object");
                    System.out.println(outField1);
                    System.out.println(outField2);
                    System.out.println(outField3);
                    System.out.println(outField4);
                    outF1();
                }
            }
            B b=new B();
        }
    }

    public static void main(String[] args) {
        new LocalInnerTest().localInnerClassTest();
    }
}

在外部类对应的字节码文件中:1)为匿名内部类中访问的私有数据(变量、方法)提供了相应的静态方法供调用。


3.静态成员不能访问实例成员

  • 静态内部类不能访问外部类的实例成员

因为:要想访问外部类的实例成员,必须通过外部类实例进行。无论是静态内部类还是静态内部类对象中只持有外部类的引用,但不持有外部类对象的引用,所以直接调用外部类的实例成员会造成错误。

  • 外部类的静态成员(静态变量、静态方法、静态初始化块)不能访问普通内部类、匿名内部类、局部内部类(不可用于定义变量、创建实例)

A:访问普通内部类、匿名内部类、局部内部类这些普通成员,必须通过外部类实例进行。外部类的静态成员中不持有外部类对象的引用,所以直接调用会造成错误。

4.不允许在普通内部类、匿名内部类、局部内部类中定义静态成员

a)针对个体的规则

1.普通内部类

  • 变量访问规则

  • 如何在外部类之外的类访问普通内部类

  • 创建普通内部类实例

2.匿名内部类

new 实现接口()|父类构造器(实参列表)
{
    // 匿名内部类的实体部分
}

3.局部内部类

参考文献

回归Java基础,详解 Java 内部类
疯狂Java

相关文章

  • Java 中的方法内部类

    Java 中的方法内部类 方法内部类就是内部类定义在外部类的方法中,方法内部类只在该方法的内部可见,即只在该方法内...

  • PHP转JAVA的记录

    Java 数组 内部类 内部类的创建:内部类可以对包内其他类隐藏想实现一个接口时, 不想新建类文件 内部类可以访问...

  • Java内部类

    Java内部类,简单来说就是将一个类定义在另一个类或者方法里面,主要分为成员内部类,局部内部类,匿名内部类和静态内...

  • Java内部类

    Java内部类 大纲: java内部类有什么特点?为什么需要内部类? 非静态内部类持有外部类的引用 内部类的分类。...

  • 内部类

    内部类可以分为:非静态内部类;静态内部类;匿名内部类。 一、内部类 首先要说,Java为什么要使用内部类?java...

  • Java静态内部类

    Java静态内部类 博客分类: java 两种内部类 Java的内部类有两种,一种是静态内部类,另一种是普通内部类...

  • Kotlin内联类、内部类、嵌套类

    Kotlin内联类、内部类、嵌套类 在开始介绍Kotlin内联类、内部类、嵌套类之前,先简要回顾一下java中的内...

  • JavaSE基础知识学习-----内部类

    内部类 类的五个成分:属性,方法,构造器,代码块,内部类。什么是内部类?在java中,允许一个类定义在另一个类的内...

  • Java 内部类和泛型的理解

    Java 内部类 Java非静态内部类持有对外部类的引用,可以访问外部类的状态使用方法 OuterClass.th...

  • kotlin之内部类,匿名内部类与伴生对象

    个人博客:haichenyi.com。感谢关注 内部类   kotlin的内部类与java的内部类有点不同java...

网友评论

      本文标题:Java内部类

      本文链接:https://www.haomeiwen.com/subject/uyvozftx.html