`
DavidIsOK
  • 浏览: 75855 次
社区版块
存档分类
最新评论

java嵌套类(Nested Classes)总结

 
阅读更多

Nested Classes定义

java语言规范里面,嵌套类(Nested Classes)定义是:

A nested class isany class whose declaration occurs within the body of another class orinterface. A top level class is a class that is not a nested class.

说的简单一点,就是定义在类里面的类。一般把定义内部类的外围类成为包装类(enclosing class)或者外部类

嵌套类分类

根据nestedclass定义的地方,可以分为membernested class,local nested class ,anonymous nested class

member nested class(成员嵌套类):成员嵌套类作为enclosing class 的成员定义的,成员嵌套类有enclosing class属性(这个是什么意思?)

local nested class (局部嵌套类):局部嵌套类定义在enclosing class 的方法里面,局部嵌套类有enclosing class 属性和enclosing method 属性

anonymous nested class(匿名嵌套类):匿名嵌套类没有显示的定义一个类,直接通过new 的方法创建类的实例。一般回调模式情况下使用的比较多

member nested class可以使用public,private,protected访问控制符,也可以用static,final关键字(使用static修饰的成员嵌套类成为“顶级嵌套类”:当你在其它类的外面声明一个类时,Java就认为该类是一个顶级类。如果你在一个顶级类中声明一个类,并且在该嵌套类的声明前加上static的修饰符,你就得到了一个顶级嵌套类)

local nested class 可以使用final关键字

anonymous nested class 不使用任何关键字和访问控制符

见下面的代码


public class EnclosingClass {
 
    public static final class NestedMemberClass {
 
    }
 
    public void nestedLocalClass() {
 
        final class NestedLocalClass {
 
        }
    }
 
    public void nestedAnonymousClass() {
 
        new Runnable() {
 
            @Override
            public void run() {
            }
        };
    }
}

在大多数情况下,一般把nested classes 分为两种:

Static Nested Classes(静态嵌套类): 就是用static修饰的成员嵌套类(或者叫静态成员类

InnerClass静态嵌套类之外所有的嵌套类的总称,也就是非静态嵌套类,也就是没有用static定义的nested classesInner Classes 不能定义为static不能有static方法和static初始化语句块。(不然即使你定义了外部也访问不了)JLSjava语言规范)里面是这么定义的:

Aninner class is a nested class that is not explicitly or implicitly declaredstatic. Inner classes may not declare static initializers (§8.7) or memberinter- faces

其中Inner Class又可以分为三种:

1 inner member classes :没有用static 修饰的成员内部类(所谓“成员”就是类的成员,跟成员变量,成员方法一样的)

2 local inner classes 定义在方法里面的内部类,方法可以是static的也可以是非static的,也可以是构造器方法。

3anonymous inner classes :定义在方法里面匿名类,方法可以是static的也可以是非static

嵌套类访问规则

Static Nested Classes 以及 inner classes 有一些限制规则,下面介绍一下这些规则。

·Static Nested Classes访问规则

Static修饰的Nested Classes,只能访问外部类的非static变量。(这一点不懂的话是对static的理解不够深入,可以参考这篇文章:http://blog.csdn.net/a512592151/article/details/38453811对于public staticNested Classes 可以用new 外部类.内部类()的方式直接创建。而默认的static Nested Classes 可以在同一包名下,用 new 外部类.内部类()的方式创建。其实和外部类的方式差不多。静态成员类可以使用访问控制符,可以使用static修饰,可以是abstract抽象类

我的理解:对于上面为什么可以直接这样new 外部类.内部类()创建这个嵌套类呢,从这里我引出了一个队static 的个人理解,在嵌套类前面加static 不是用来修饰这个嵌套类的,而是为了让其上层类知道这个类是静态的,从而可以直接引用,而不必先实例化上层类。其他静态XX我想也是类似的。(初学者的理解,大牛勿喷)


public class StaticNestedClass {
 
    // 私有局部
    private int i = 0;
 
    // 静态
    public static int j = 0;
 
    // 不变值
    private final int k = 0;
 
    // static final
    private static final int m = 0;
 
    // 静态嵌套内,这里不是innerclass,可以直接new出来
    public static class PublicNestedClass {
 
        private void test1() {
            // System.out.println(i); 非innerClass不能访问enclosing类的非static属性
            System.out.println(j);
            System.out.println(m);
            // System.out.println(k); 非innerClass不能访问enclosing类的非static属性
        }
 
        // 可以定义static方法
        private static void test2() {
 
        }
    }
 
    // 静态嵌套内,这里不是innerclass,由于是私有的,不可以直接new出来
    private static class PrivateNestedClass {
 
    }
}

下面的例子演示了static Nested class的创建


public class TestClass {
 
    public static void main(String[] args) {
        
        //任何地方都可以创建
        StaticNestedClass.PublicNestedClass publicNestedClass = new StaticNestedClass.PublicNestedClass();
        
       
        //编译错误,无法访问内部内
        //StaticNestedClass.PrivateNestedClass privateNestedClass = new StaticNestedClass.PrivateNestedClass();
    }
}

·Inner Class访问规则

inner member classes(内部成员类)可以访问外部类的所有实例属性,静态属性(而静态内部类是不能这样访问的,因为引用静态内部类根本不需要实例化上一层类,所以也不会存在什么实例属性了)。因为内部成员类持有一个外部对象的引用(jvm的机制方面解释一下?),内部类的实例可以对外部类的实例属性进行修改。如果是public inner member classes,可以通过外部类实例.new 内部类()的方式进行创建,当调用内部类的构造器的时候,会把当前创建的内部类对象实例中持有的外部对象引用赋值为当前创建内部类的外部类实例。内部成员类可以是使用访问控制符,可以定义为final,也可以是抽象类。

public class MemberInnerClass {
 
    // 私有局部
    public int i = 0;
    // 静态
    private static int j = 0;
    // 不变值
    private final int k = 0;
    // static final
    private static final int m = 0;
 
    public class PublicMemberInnerClass {
        // enclosing Class的属性都可以访问
        public void test() {
            System.out.println(i);
            System.out.println(j);
            System.out.println(m);
            System.out.println(k);
        }
 
        public MemberInnerClass getOutterClass() {
            return MemberInnerClass.this;
        }
        // 这里会报错,不允许定义static方法
        // private static final void test();
    }
 
    // 私有的innerclass 外部不能访问
    private class PrivateMemberInnerClass {
    }
 
    // 公开局部类,外部可以访问和创建,但是只能通过OutterClass实例创建
 
    class DefaultMemberInnerClass {
        public MemberInnerClass getOutterClass() {
            return MemberInnerClass.this;
        }
    }
 
}


下面例子演示了内部成员类的创建

public class TestClass {
 
    public static void main(String[] args) {
 
        // 任何地方都可以创建
        MemberInnerClass t = new MemberInnerClass();
 
        // 可以创建,pmic里面保存对t的引用
        MemberInnerClass.PublicMemberInnerClass pmic = t.new PublicMemberInnerClass();
 
        // 可以在同一package下创建,dmic保存对t的引用
        MemberInnerClass.DefaultMemberInnerClass dmic = t.new DefaultMemberInnerClass();
 
        // 编译错误,无法访问内部内
        // MemberInnerClass.PrivateMemberInnerClass pmic = t.new
        // PrivateMemberInnerClass();
 
        // 下面验证一下outterClass是同一个对象
        System.out.println(pmic.getOutterClass() == t);
        System.out.println(dmic.getOutterClass() == t);
 
    }
}


 运行程序,打印结果:

true

true

2local inner classes(局部类)

局部类定义在类方法里面。这个方法既可以是静态方法,也可以是实例方法,也可以是构造器方法或者静态初始化语句块

局部类可以定义在一个static上下文里面static上下文里面。局部类不能有访问控制符(private,public,protected修饰)(方法中不需要定义成员可见性),可以是抽象的,也可以定义为final

定义在static上下文(static 字段初始化,static初始化块,static方法)里面的local inner classes 可以访问类的静态属性,如果定义在静态方法里面的局部类,还可以方法里面定义的final变量。在static上下文定义的局部类,不能引用父类的实例变量,因为static方法不属于类的实例,属于类本身,局部类不能在外部进行创建,只能在方法调用的时候进行创建

package com.hxw.T2;
public class LocalInnerClass {
 
    // 私有局部
    private int i = 0;
 
    // 静态
    public static int j = 0;
 
    // 不变值
    private final int k = 0;
 
    // static final
    private static final int m = 0;
 
    public static void test() {
        final int a = 0;
        int b = 0;
        // local inner class不能够有访问控制符比如public private
        abstract class LocalStaticInnerClass {
            private int d = 0;
            public LocalStaticInnerClass() {
                // 可以访问方法里面定义的final 变量
                System.out.println(a);
                // 不能访问b 因为b不是final
                // System.out.println(b);     
                // 定义在static上下文里面的local inner class 不能访问外部类的非static字段
                // System.out.println(i);
                // System.out.println(k);
                System.out.println(j);
                System.out.println(m);
            }
            // local inner class不能定义静态方法为什么?
            // public static void test(){}
        }
    }
 
    public void test2() {
        final int a = 0;
        int b = 0;
        final class LocalNonStaticInnerClass{ 
            public LocalNonStaticInnerClass() {
                //定义在非static上下文的local inner class 可以访问外部类的所有属性
             
              // private static int c;
             
              /*local inner class不能定义静态属性(因为如果要外界访问该方法的话是如此形式的,
               * LocalInnerClass.LocalNonStaticInnerClass.c;
               * 但是实际上对于非静态内部类我们的访问方法是这样的:
              LocalInnerClass  localinner=new LocalInnerClass()
              LocalInnerClass.LocalNonStaticInnerClass inner =localinner.new LocalNonStaticInnerClass();
              不难解释,因为LocalNonStaticInnerClass不是静态成员怎么直接访问呢,必须实例化后做一个外部引用才可以访问的。
              这样一来,
              */
             
             
                System.out.println(i);
                System.out.println(k);
                System.out.println(j);
                System.out.println(m);
            }
        }
    }
 
}


提问:为什么上面的例子,b不是final,就不能访问呢?答案见:http://blog.csdn.net/a512592151/article/details/38468953

3anonymousinner classes (匿名类)也是定义在方法里面,匿名类和局部类访问规则一样,只不过内部类显式的定义了一个类,然后通过new的方式创建这个局部类实例,而匿名类直接new一个类实例,没有定义这个类。匿名类最常见的方式就是回调模式的使用,通过默认实现一个接口创建一个匿名类然后,然后new这个匿名类的实例。

public class AnonymousInnerClass {
    //访问规则和局部类一样
    public void test() {
        
        //匿名类实现
        new Thread(new Runnable() {
 
            @Override
            public void run() {
 
            }
        }).start();
        
        //非匿名类实现
        class NoneAnonymousClass implements Runnable{
            public void run() {
 
            }
        }  
        NoneAnonymousClass t = new NoneAnonymousClass();
        new Thread(t).start();
    }
}


嵌套类的层次

嵌套类是可以有层次的,也就是说嵌套类里面还是定义类,成为嵌套类中的嵌套类。虚拟机如何保证嵌套类正确的嵌套层层次?

对于merber class,内部嵌套类的可以表示为 A$B 其中A为外部类,B为内部成员类,如果B里面又有成员为C的嵌套类,那么C就可以表示为A$B$C,如果A定义了两个同名member class,那么编译器就会报错。如果B里面又包含了为名Bnested class,则编译器会报错.

对于local inner Class,局部类可以表示为A$1B的方式,其中A为外部类,B为第一个局部类如果在不同的方法里面定义了同名的局部类B,编译器是可以编译通过的,那么定义的第二个局部类B可以表示为A$2B如果在同一个方法里面同定义两个相同的局部类B,那么编译错是要报错的。如果B里面又定义了同名的成员类,则可以表示为A$1B$B

对于anonymous inner classes,匿名类可以表示为A$1的方式,代表程序里面有一个匿名类。如果有N个,可以表示为A$N的方式(N为自然数).

看看下面的例子

public class NestedClassLevel {
 
    class A {
        // 编译器会报错,A里面不能在定义名为A的nested classes
        // class A{}
        public void test() {
            class B {
            }
        }
    }
 
    //可以在继续定义B
    class B {
        public void test(){
            //可以无限定义匿名类
            new Runnable() {
                public void run() {
                    //可以无限定义匿名类
                    new Runnable() {           
                        public void run() {        
                        }
                    };
                }
            };
        }
    }
 
    // 只能定义一个B
    // class B{}
 
    public void test() {
        // 可以定义A
        class A {
            public void test() {
                //可以有同名的局部类B和成员类B
                class B {
                    public void test() {
                        
                    }
                }
                //局部类A里面不能在定义A
                //class A{}
            }
        }
        //可以有同名的局部类B和成员类B
        class B {
 
        }
    }
 
}


对于定义在非static上下文里面的nested类层次,比如A$B$1C ,则最内层的嵌套类C有一个指向B实例的引用,B有一个指向A实例的引用,最终最内层的嵌套类可以访问A中的属性可以方法,一般把B成为A的直接嵌套类。但是A不可以访问B或者C中属性或者方法(因为没有实例化)

nested interface

由于interface默认是定义为一个 public static的特殊类,所以interface可以直接作为 static member class。可以通过A.B的方式进行访问。

nested class的应用

java提供的基本类库里面,大量使用nested classes。比如我们知道的map类。其中 Map类里面有一个定义了Entryabstract inner class。所以我们在遍历map的时候,一般使用

for (Map.Entry entry:map.entrySet()){

}

总结:nested类是java里面比较复杂的一个概念,必须详细了解jvm中对于嵌套类的实现以及java编译器对嵌套类的处理才可以深入了解嵌套类细节。


分享到:
评论

相关推荐

    Java 深入理解嵌套类和内部类

    Java 中的嵌套类和内部类是指在一个类的内部定义另一个类,这种类称为嵌套类(nested classes)。嵌套类有两种类型:静态嵌套类和非静态嵌套类。静态嵌套类使用很少,非静态嵌套类也即被称作为内部类(inner)。嵌套...

    java嵌套类

    在Java语言中,嵌套类(Nested Classes)是Java语言规范中定义的术语,指的是在其他类或接口的主体内部声明的类。嵌套类可以细分为多种类型,每种类型都有其特点和使用场景。 首先,根据嵌套类定义的位置,可以将...

    深入理解Java嵌套类和内部类

    深入理解Java嵌套类和内部类 Java 嵌套类(nested classes)是指在一个类的内部定义另一个类,这种类有两种类型:静态嵌套类和非静态嵌套类。非静态嵌套类也称为内部类(inner classes)。在Java中,嵌套类从JDK1.1...

    java代码-Nested

    在Java编程语言中,"Nested"通常指的是嵌套类或者嵌套结构,这是一门强大的特性,使得代码更加模块化和高效。嵌套类可以分为两种主要类型:内部类(Inner Classes)和局部类(Local Classes)。让我们深入探讨这两种...

    Java-Docs-3.zip_nested

    这个主题涵盖了内部类(inner classes)、静态嵌套类(static nested classes)以及其他相关的概念,这些都是理解和编写复杂Java代码的关键部分。 首先,让我们来理解什么是内部类。内部类是定义在另一个类的内部的...

    java内部类的讲解

    1. **嵌套顶级类(Nested Top-Level Classes)**:这种内部类类似于普通的类,但它们被定义在另一个类的内部。它们没有访问外部类的实例变量或方法的能力,除非它们是静态的。嵌套顶级类可以通过外部类名访问。 2. ...

    Java教学详细内容课件.ppt

    模块6:Nested Classes(嵌套类),涵盖了Java中的嵌套类概念,包括静态嵌套类、非静态嵌套类等内容。 模块7:Packages(包),涵盖了Java中的包概念,包括包的声明、导入包、包的使用等内容。 模块8:Exceptions...

    Java面向对象设计最佳实践_-_内置类设计

    5. **静态嵌套类(Static Nested Classes)**: 静态嵌套类与外部类之间没有实例关联,不持有对外部类的引用。它们类似于普通的顶级类,但可以访问外部类的静态成员,有助于模块化设计。 6. **使用内置类的优点**...

    《SCJP学习指南》chap8

    本章节《SCJP学习指南》第八章主要聚焦于Java中的内部类(Inner Classes),包括静态嵌套类(Static Nested Classes)。由于内部类在SCJP考试中占据着重要的位置,因此对这一主题的深入理解对于通过考试至关重要。 ...

    SCJP Sun® Certified Programmer for Java™ 6 Study Guide chapter 8

    在本章中,我们将深入了解Java中的内部类(Inner Classes),这是SCJP认证考试的重要部分之一。虽然没有专门针对内部类的官方考试目标,但内部类作为Java编程语言的一个关键特性被包含在Objective 1.1之中。由于内部...

    Java 中包的概念,类的说明符与内部类21

    4. 静态嵌套类(Static Nested Class):相当于成员内部类,但可以拥有静态成员,并且可以直接通过外部类访问,无需外部类实例。 在提供的文件列表中,"317.swf"和"316.swf"可能是视频教程的一部分,由孙鑫老师讲解...

    Java学习笔记

    - **嵌套类(Nested Classes)**:在一个类的内部定义的类。 - **类修饰符** - **注解(Annotations)**:用于向编译器或其他工具提供元数据。 - **public**:公共修饰符,表示类及其公共成员对外部可见。 - ...

    Java使用static

    五、静态嵌套类(Static Nested Classes) 1. **类型**:静态嵌套类是与非静态嵌套类(内部类)相对的,它们不持有对外部类的隐式引用。 2. **用途**:常用于表示与外部类有关系但不依赖其状态的辅助类,比如事件...

    java常用词汇汇总

    #### nested [java] 嵌套的 ['nestid] 如:内部类(nested classes) - **中文释义**:嵌套的 - **用途**:嵌套类是指在一个类内部定义的另一个类。Java支持两种类型的嵌套类:静态嵌套类和非静态嵌套类(内部类)。 ...

    4static封装类.rar在类的声明里查看有无静态元素(static

    5. 静态类(Static Nested Classes): 在Java中,静态内部类(也称为顶级嵌套类)不是某个特定对象的一部分,而是其外部类的一个静态成员。它们可以独立于外部类的对象存在,且没有对外部类的隐式引用。 封装是...

    Nested-Class-Models-Rest-Api-Neo4j:在休息环境中作为 neo4j 扩展实现的嵌套类模型

    org.neo4j.server.thirdparty_jaxrs_classes=org.neo4j.example.unmanagedextension=/example 启动 Neo4j 服务器。 写评论 curl ...

    JSON与JAVA数据的转换

    4. **JSON Nested Objects <-> Java Custom Classes** - 当JSON对象包含嵌套的对象时,可以将其映射为Java中的自定义类。 #### JSON与Java数据转换方法 - **库的选择:** - 在Java中进行JSON与Java数据之间的...

    整理后java开发全套达内学习笔记(含练习)

    nested [java] 嵌套的 ['nestid] '如:内部类(nested classes) Object [java] 对象 ['ɒbdʒekt] Overload [java] 方法的重载(不同参数列表的同名方法) [,әuvә'lәud] Override [java] 方法的覆盖(覆盖父类的...

    要static还是不要static?

    4. **内部类与静态内部类(inner classes and static nested classes)** 在 `InnerInterfaceNotStaticTest.java` 文件中,我们可能会遇到内部类与静态内部类的区别。内部类可以访问外部类的私有成员,但需要与外部...

Global site tag (gtag.js) - Google Analytics