`
crud0906
  • 浏览: 134759 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

java嵌套类(Nested Classes)总结(转)

    博客分类:
  • JAVA
 
阅读更多
原文链接: http://www.cnblogs.com/aigongsi/archive/2012/04/24/2467183.html

java嵌套类(Nested Classes)总结
Nested Classes定义

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

A nested class is any class whose declaration occurs within the body of another class or interface. A top level class is a class that is not a nested class.

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


嵌套类分类

根据nested class定义的地方,可以分为member nested 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关键字

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 classes,Inner Classes 不能定义为static,不能有static方法和static初始化语句块。在JLS(java语言规范)里面是这么定义的:

An inner class is a nested class that is not explicitly or implicitly declared static. Inner classes may not declare static initializers (§8.7) or member inter- faces



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

1 inner member classes :没有用static 修饰的成员内部类

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

3 anonymous inner classes :定义在方法里面匿名类,方法可以是static的也可以是非static的
嵌套类访问规则

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

    Static Nested Classes访问规则

用Static修饰的Nested Classes,只能访问外部类的非static变量。对于public 的 static Nested Classes 可以用 new 外部类.内部类()的方式直接创建。而默认的static Nested Classes 可以在同一包名下,用 new 外部类.内部类()的方式创建。其实和外部类的方式差不多。静态成员类可以使用访问控制符,可以使用static修饰,可以是abstract抽象类


?
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();
         
        //可以在同一package下创建
        StaticNestedClass.DefaultNestedClass defaultNestedClass = new StaticNestedClass.DefaultNestedClass();
        //编译错误,无法访问内部内
        //StaticNestedClass.PrivateNestedClass privateNestedClass = new StaticNestedClass.PrivateNestedClass();
    }
}


  

    Inner Class访问规则

inner member classes(内部成员类) 可以访问外部类的所有实例属性,静态属性。因为内部成员类持有一个外部对象的引用,内部类的实例可以对外部类的实例属性进行修改。如果是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

  

2 local inner classes(局部类)

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

局部类可以定义在一个static上下文里面 和 非static上下文里面。局部类不能有访问控制符(private,public,protected修饰),可以是抽象的,也可以定义为final

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


?
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 {
            // local inner class不能定义静态属性
            // private static int c;
            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 可以访问外部类的所有属性
                System.out.println(i);
                System.out.println(k);
                System.out.println(j);
                System.out.println(m);
            }
        }
    }
 
}


 

3 anonymous inner 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里面又包含了为名B的nested 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类里面有一个定义了Entry类abstract inner class。所以我们在遍历map的时候,一般使用

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

}



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

相关推荐

    java-嵌套类(inner class)-来自oracle官网

    1.Nested Class(嵌套类) 1.1.Nested class 1.2.Nested class的分类 1.3.Nested class的使用原因 2.Static Nested Classes 2.1.static nested class访问enclosing class(outer class)的成员 2.2.enclosing...

    java解决nested exception is java.lang.OutOfMemoryError Java heap space

    java解决nested exception is java.lang.OutOfMemoryError Java heap space 解决OOM

    java代码-Nested

    java代码-Nested

    Java-Docs-3.zip_nested

    Java Notes For Dates And Nested Classes very imp for interview

    解决Handler processing failed; nested exception is java.lang.NoClassDefFoundError_kmode exception

    java解决Handler processing failed; nested exception is java.lang.NoClassDefFoundError

    Nested array.rar_arrays DOA_nested-array_nested_array_嵌套_嵌套阵列doa

    嵌套阵列DOA估计matlab例程,基于Nested Arrays A Novel Approach to Array Processing With Enhanced Degrees of Freedom。

    java笔试题,java程序员常见的笔试

    Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用上。注: 静态内部类(Inner Class)意味着1创建一个static内部类的对象,不需要一个外部类对象,2不能从一个static内部类的一个对象访问一个外部类对象

    json--nested-sample

    Gson对Java嵌套对象和JSON字符串之间的转换

    详解C++编程中的嵌套类的声明与其中的函数使用

    这样的类称为“嵌套类”。 嵌套类被视为在封闭类的范围内且可在该范围内使用。若要从嵌套类的即时封闭范围之外的某个范围引用该类,则必须使用完全限定名。 下面的示例演示如何声明嵌套类: // nested_class_...

    yii2-nested-sets, Yii框架的嵌套集行为.zip

    yii2-nested-sets, Yii框架的嵌套集行为 nest 2的行为 一种利用改进的预排序树遍历算法的Yii框架的现代嵌套。安装安装这个扩展的首选方法是通过 composer插件。运行$ composer require creocoder/yii2-nes

    Spring Nested事务简单案例

    这里是Spring的一个Nested事务的代码及数据库文件,因为NESTED资源很少,这里作出了一个通俗易懂的 让需要者下载。

    java中内部类的分类及用法

    在java语言中,有一种类叫做内部类(inner class),也称为嵌入类(nested class),它是定义在其他类的内部。

    java 面试题 总结

    java.lang.String类是final类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,我们应该用StringBuffer类 3、int 和 Integer 有什么区别 Java 提供两种不同的类型:引用类型和原始类型(或内置...

    Java程序员面试陷阱大全.doc

    Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用上。  注: 静态内部类(Inner Class)意味着1创建一个static内部类的对象,不需要一个外部类对象,2不能从一个static内部类的一个对象访问一个外部类...

    嵌套聚集示例数据--nested-data.json

    学习elasticsearch嵌套聚集所需的示例数据,方便学习者进行测试。 关于城市宠物注册的web应用,系统包括下列一些实体: * City(city, type) * Citizen(occupation,age) * Pet(kind,name,age) city包括多个...

    java面试题大全-基础方面

    Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用上。注: 静态内部类(Inner Class)意味着1创建一个static内部类的对象,不需要一个外部类对象,2不能从一个static内部类的一个对象访问一个外部类对象 ...

    java面试宝典

    嵌套类最大的不同就在于 是否有指向外部的引用上。注: 静态内部类(Inner Class)意味着1创建一个static内部类 的对象,不需要一个外部类对 象,2 不能从一个static内部类的一个对象访问一个外部类对象 4、&和&&...

    Java.7.A.Comprehensive.Tutorial

    Chapter 14 Nested and Inner Classes Chapter 15 Swing Basics Chapter 16 Swinging Higher Chapter 17 Polymorphism Chapter 18 Annotations Chapter 19 Internationalization Chapter 20 Applets Chapter 21 Java...

    java错误处理:java.lang.OutOfMemoryError: Java heap space

    搜集整理关于java错误处理:java.lang.OutOfMemoryError: Java heap space java.lang.OutOfMemoryError: Java heap space 资料整理

Global site tag (gtag.js) - Google Analytics