Java内部类和静态嵌套类

Java inner class and static nested class

Java中的内部类和静态嵌套类的主要区别是什么?设计/实现是否在选择其中一个方面发挥作用?


从Java教程:

Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are simply called static nested classes. Non-static nested classes are called inner classes.

使用封闭类名称访问静态嵌套类:

1
OuterClass.StaticNestedClass

例如,要为静态嵌套类创建对象,请使用以下语法:

1
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

作为内部类实例的对象存在于外部类的实例中。考虑以下类别:

1
2
3
4
5
6
class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

InnerClass实例只能存在于OuterClass实例中,并且可以直接访问其封闭实例的方法和字段。

要实例化内部类,必须首先实例化外部类。然后,使用以下语法在外部对象内创建内部对象:

1
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

参见:Java教程-嵌套类

为完整性起见,请注意,还有一个类似于没有封闭实例的内部类的东西:

1
2
3
4
class A {
  int t() { return 1; }
  static A a =  new A() { int t() { return 2; } };
}

这里,new A() { ... }是一个在静态上下文中定义的内部类,没有封闭实例。


Java教程说:好的。

Terminology: Nested classes are
divided into two categories: static
and non-static. Nested classes that
are declared static are simply called
static nested classes. Non-static
nested classes are called inner
classes.

Ok.

一般来说,"嵌套"和"内部"这两个术语在大多数程序员中是可以互换使用的,但是我将使用正确的术语"嵌套类",它涵盖内部和静态。好的。

类可以无限嵌套,例如,A类可以包含B类,B类包含C类,C类包含D类等。但是,多个级别的类嵌套很少,因为通常设计不好。好的。

创建嵌套类有三个原因:好的。

  • 组织:有时将一个类排序到另一个类的名称空间中似乎是最明智的,尤其是当它不会在任何其他上下文中使用时。
  • 访问:嵌套类对其包含类的变量/字段具有特殊的访问权限(确切地说,哪些变量/字段取决于嵌套类的类型,无论是内部的还是静态的)。
  • 便利性:为每一个新类型创建一个新文件也是很麻烦的,特别是当类型只在一个上下文中使用时。

Java中有四种嵌套类。简而言之,它们是:好的。

  • 静态类:声明为其他类的静态成员
  • 内部类:声明为其他类的实例成员
  • 局部内部类:在另一个类的实例方法中声明
  • 匿名内部类:类似于本地内部类,但写为返回一次性对象的表达式

让我详细阐述一下。好的。

好的。静态类

静态类是最容易理解的类,因为它们与包含类的实例无关。好的。

静态类是声明为其他类的静态成员的类。与其他静态成员一样,此类实际上只是一个使用包含类作为其命名空间的挂接器,例如,在包pizza中声明为类rino静态成员的类goat的名称为pizza.rino.goat。好的。

1
2
3
4
5
6
7
8
9
10
package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

坦率地说,静态类是一个毫无价值的特性,因为类已经被包划分为名称空间。创建静态类的唯一真正可能的原因是这样一个类可以访问其包含类的私有静态成员,但是我发现这是静态类特性存在的一个很不合理的理由。好的。

好的。内部类

内部类是声明为其他类的非静态成员的类:好的。

1
2
3
4
5
6
7
8
9
10
11
12
package pizza;

public class Rhino {

    public class Goat {
        ...
    }

    private void jerry() {
        Goat g = new Goat();
    }
}

与静态类一样,内部类也被称为通过其包含类名pizza.rhino.goat进行限定,但在包含类内部,可以通过其简单名称进行识别。然而,内部类的每个实例都与包含类的特定实例相关联:上面,Jerry创建的山羊隐式地与Jerry中的犀牛实例相关联。否则,在实例化山羊时,我们将关联的Rhino实例显式化:好的。

1
2
Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();

(注意,在怪异的新语法中,你把内部类型称为纯山羊:Java从犀牛部分推断出包含类型。而且,是的,新的犀牛山羊()对我来说也更有意义。)好的。

那么这对我们有什么好处呢?内部类实例可以访问包含类实例的实例成员。这些封闭实例成员仅通过其简单名称在内部类中引用,而不是通过此引用(内部类中的此引用内部类实例,而不是关联的包含类实例):好的。

1
2
3
4
5
6
7
8
9
10
public class Rhino {

    private String barry;

    public class Goat {
        public void colin() {
            System.out.println(barry);
        }
    }
}

在内部类中,可以将包含类的这个称为Rhino.This,并且可以使用它来引用其成员,例如Rhino.This.Barry。好的。

好的。局部内部类

局部内部类是在方法体中声明的类。此类仅在其包含方法中已知,因此只能对其进行实例化,并在其包含方法中访问其成员。这样做的好处是,一个局部内部类实例被绑定到并且可以访问其包含方法的最终局部变量。当实例使用其包含方法的最后一个局部时,变量保持在实例创建时保持的值,即使变量已超出范围(这实际上是Java的粗略、封闭版本的有限版本)。好的。

因为本地内部类既不是类或包的成员,所以它没有用访问级别声明。(但是,要清楚,它自己的成员具有与普通类类似的访问级别。)好的。

如果在实例方法中声明了本地内部类,则在创建实例时,内部类的实例化绑定到包含方法的this所持有的实例,因此包含类的实例成员可以像在实例内部类中一样访问。本地内部类只通过其名称进行实例化,例如,本地内部类cat被实例化为new cat(),而不是像您预期的那样新建this.cat()。好的。

好的。匿名内部类

匿名内部类是编写本地内部类的一种语法上方便的方法。最常见的是,一个本地内部类在每次运行其包含方法时最多实例化一次。如果我们可以将本地内部类定义和它的单个实例化组合成一种方便的语法形式,那就太好了;如果我们不必为类想出一个名称(代码包含的无效名称越少越好),那也就更好了。匿名内部类允许以下两种情况:好的。

1
new *ParentClassName*(*constructorArgs*) {*members*}

这是一个表达式,返回扩展parentclassname的未命名类的新实例。您不能提供自己的构造函数;相反,它是隐式提供的,只调用超级构造函数,因此提供的参数必须适合超级构造函数。(如果父级包含多个构造函数,那么"最简单的"一个称为"最简单的",这是由一组相当复杂的规则决定的,这些规则不值得费心学习细节——只需注意netbeans或eclipse告诉您的内容。)好的。

或者,可以指定要实现的接口:好的。

1
new *InterfaceName*() {*members*}

这样的声明将创建一个未命名类的新实例,该实例扩展对象并实现InterfaceName。同样,您不能提供自己的构造函数;在这种情况下,Java隐式地提供一个无ARG,不做任何构造函数(因此在这种情况下永远不会有构造函数参数)。好的。

即使不能为匿名内部类提供构造函数,也可以使用初始值设定项块(放置在任何方法外部的块)执行任何所需的设置。好的。

显然,匿名内部类只是用一个实例创建本地内部类的一种不太灵活的方法。如果您想要一个实现多个接口的本地内部类,或者在扩展对象以外的某个类或指定自己的构造函数时实现接口,那么您将无法创建一个名为本地内部类的常规内部类。好的。好啊。


我认为上述答案之间的真正区别并不明显。

首先要让条款正确:

  • 嵌套类是包含在源代码级别的另一个类中的类。
  • 如果用静态修饰符声明它,则它是静态的。
  • 非静态嵌套类称为内部类。(我使用非静态嵌套类。)

马丁的回答是对的。然而,实际的问题是:声明嵌套类static的目的是什么?

如果只想将类放在一起(如果它们属于主题类),或者如果嵌套类仅在封闭类中使用,则可以使用静态嵌套类。静态嵌套类和其他所有类之间没有语义差异。

非静态嵌套类是不同的Beast。类似于匿名内部类,这种嵌套类实际上是闭包。这意味着它们捕获它们周围的范围和它们的封闭实例,并使其可访问。也许有个例子可以说明这一点。请参阅容器的存根:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Container {
    public class Item{
        Object data;
        public Container getContainer(){
            return Container.this;
        }
        public Item(Object data) {
            super();
            this.data = data;
        }

    }

    public static Item create(Object data){
        // does not compile since no instance of Container is available
        return new Item(data);
    }
    public Item createSubItem(Object data){
        // compiles, since 'this' Container is available
        return new Item(data);
    }
}

在这种情况下,您希望有一个从子项到父容器的引用。使用一个非静态的嵌套类,这是不需要做一些工作的。您可以使用语法Container.this访问容器的封闭实例。

更多的核心解释如下:

如果查看Java字节码,编译器会生成一个(非静态)嵌套类,它可能变得更加清晰:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// class version 49.0 (49)
// access flags 33
public class Container$Item {

  // compiled from: Container.java
  // access flags 1
  public INNERCLASS Container$Item Container Item

  // access flags 0
  Object data

  // access flags 4112
  final Container this$0

  // access flags 1
  public getContainer() : Container
   L0
    LINENUMBER 7 L0
    ALOAD 0: this
    GETFIELD Container$Item.this$0 : Container
    ARETURN
   L1
    LOCALVARIABLE this Container$Item L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 1
  public <init>(Container,Object) : void
   L0
    LINENUMBER 12 L0
    ALOAD 0: this
    ALOAD 1
    PUTFIELD Container$Item.this$0 : Container
   L1
    LINENUMBER 10 L1
    ALOAD 0: this
    INVOKESPECIAL Object.<init>() : void
   L2
    LINENUMBER 11 L2
    ALOAD 0: this
    ALOAD 2: data
    PUTFIELD Container$Item.data : Object
    RETURN
   L3
    LOCALVARIABLE this Container$Item L0 L3 0
    LOCALVARIABLE data Object L0 L3 2
    MAXSTACK = 2
    MAXLOCALS = 3
}

如您所见,编译器创建一个隐藏字段Container this$0。这是在具有容器类型的附加参数的构造函数中设置的,该参数用于指定封闭实例。在源中看不到该参数,但编译器隐式地为嵌套类生成该参数。

马丁的例子

1
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

会编译成类似(字节码)的调用吗?

1
new InnerClass(outerObject)

为了完整起见:

匿名类是一个非静态嵌套类的完美示例,该类没有关联的名称,以后不能引用。


我认为上述答案都不能解释嵌套类和静态嵌套类在应用程序设计方面的真正区别:

概述

嵌套类可以是非静态的或静态的,并且在每种情况下都是在另一个类中定义的类。一个嵌套类应该只存在于服务于封闭类,如果一个嵌套类被其他类(不仅仅是封闭类)使用,那么应该声明为顶级类。

差异

非静态嵌套类:与包含类的封闭实例隐式关联,这意味着可以调用封闭实例的方法和访问变量。非静态嵌套类的一个常见用法是定义适配器类。

静态嵌套类:无法访问封闭类实例并对其调用方法,因此在嵌套类不需要访问封闭类的实例时应使用该类。静态嵌套类的常见用法是实现外部对象的组件。

结论

所以从设计的角度来看,两者的主要区别在于:非静态嵌套类可以访问容器类的实例,而静态类不能。


简单地说,我们需要嵌套类,主要是因为Java不提供闭包。

嵌套类是在另一个封闭类的主体内定义的类。它们有两种类型-静态和非静态。

它们被视为封闭类的成员,因此您可以指定四个访问说明符中的任何一个-private, package, protected, public。我们没有顶级的豪华车,只能宣布为public或Package private。

内部类也称为非堆栈类,可以访问顶级的其他成员,即使它们被声明为私有的,而静态嵌套类不能访问顶级的其他成员。

1
2
3
4
5
6
public class OuterClass {
    public static class Inner1 {
    }
    public class Inner2 {
    }
}

Inner1是我们的静态内部类,Inner2是我们的非静态内部类。它们之间的关键区别在于,如果没有外部实例,就不能创建Inner2实例,因为可以独立创建Inner1对象。

你什么时候使用内部课程?

想想一种情况,Class AClass B是相关的,Class B需要访问Class A成员,Class B只与Class A相关。图中出现了内部类。

要创建内部类的实例,需要创建外部类的实例。

1
2
OuterClass outer = new OuterClass();
OuterClass.Inner2 inner = outer.new Inner2();

1
OuterClass.Inner2 inner = new OuterClass().new Inner2();

什么时候使用静态内部类?

当您知道静态内部类与封闭类/顶级类的实例没有任何关系时,您将定义一个静态内部类。如果您的内部类不使用外部类的方法或字段,那么这只是浪费空间,因此请使其保持静态。

例如,要为静态嵌套类创建对象,请使用以下语法:

1
OuterClass.Inner1 nestedObject = new OuterClass.Inner1();

静态嵌套类的优点是它不需要包含类/顶级类的对象来工作。这可以帮助您减少应用程序在运行时创建的对象的数量。


我认为,通常遵循的惯例是:

  • 顶级类中的静态类是嵌套类
  • 顶级类中的非静态类是一个内部类,进一步还有两种形式:
    • 局部类-在块内部声明的命名类,如方法或构造函数体
    • 匿名类-其实例在表达式和语句中创建的未命名类

然而,要记住的其他几点是:

  • 顶级类和静态嵌套类在语义上是相同的,除非在静态嵌套类的情况下,它可以静态引用其外部[父]类的私有静态字段/方法,反之亦然。

  • 内部类可以访问外部[父级]类的封闭实例的实例变量。但是,并不是所有的内部类都有封闭实例,例如静态上下文中的内部类(如静态初始值设定项块中使用的匿名类)不具有封闭实例。

  • 默认情况下,匿名类扩展父类或实现父接口,并且没有进一步的子句来扩展任何其他类或实现任何其他接口。所以,

    • new YourClass(){};表示class [Anonymous] extends YourClass {}
    • new YourInterface(){};表示class [Anonymous] implements YourInterface {}

我觉得还有一个更大的问题有待解决,那就是什么时候用哪一个?好吧,这主要取决于您正在处理的场景,但是阅读@jrudolph给出的回复可能会帮助您做出一些决定。


这里是Java内部类和静态嵌套类之间的关键区别和相似之处。

希望它有帮助!

内部阶级

  • 可以访问外部类,包括实例和静态方法和字段
  • 与封闭类的实例关联,因此要先实例化它,需要一个外部类的实例(注意新的关键字位置):

    1
    Outerclass.InnerClass innerObject = outerObject.new Innerclass();
  • 无法定义任何静态成员本身

  • 不能有类或接口声明

静态嵌套类

  • 无法访问外部类实例方法或字段

  • 不与封闭类的任何实例关联,因此要实例化它:

    1
    OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

相似之处

  • 两个内部类都可以访问甚至是外部类的私有字段和方法
  • 同时,外部类可以访问内部类的私有字段和方法
  • 这两个类都可以有private、protected或public访问修饰符

为什么使用嵌套类?

根据Oracle文档,有几个原因(完整文档):

  • It is a way of logically grouping classes that are only used in one place: If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. Nesting such"helper classes" makes their package more streamlined.

  • It increases encapsulation: Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A's members can be declared private and B can access them. In addition, B itself can be hidden from the outside world.

  • It can lead to more readable and maintainable code: Nesting small classes within top-level classes places the code closer to where it is used.


嵌套类:类内的类

Types:

  • 静态嵌套类
  • 非静态嵌套类[内部类]
  • 差异:

    非静态嵌套类[内部类]

    在非静态嵌套类中,内部类的对象存在于外部类的对象中。这样,外部类的数据成员就可以被内部类访问。所以要创建内部类的对象,我们必须首先创建外部类的对象。

    1
    2
    outerclass outerobject=new outerobject();
    outerclass.innerclass innerobjcet=outerobject.new innerclass();

    静态嵌套类

    在内部类的静态嵌套类对象中,不需要外部类的对象,因为单词"static"表示不需要创建对象。

    1
    2
    3
    4
    5
    class outerclass A {
        static class nestedclass B {
            static int x = 10;
        }
    }

    如果要访问x,请在方法内部编写以下内容

    1
      outerclass.nestedclass.x;  i.e. System.out.prinltn( outerclass.nestedclass.x);

    嵌套静态类的使用在某些情况下可能很有用,这是一个微妙的问题。

    而静态属性在类通过其构造函数实例化之前就被实例化了,嵌套静态类中的静态属性在类的构造函数被调用,或者至少在首次引用属性之前,即使它们被标记为"最终"。

    考虑这个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    public class C0 {

        static C0 instance = null;

        // Uncomment the following line and a null pointer exception will be
        // generated before anything gets printed.
        //public static final String outerItem = instance.makeString(98.6);

        public C0() {
            instance = this;
        }

        public String makeString(int i) {
            return ((new Integer(i)).toString());
        }

        public String makeString(double d) {
            return ((new Double(d)).toString());
        }

        public static final class nested {
            public static final String innerItem = instance.makeString(42);
        }

        static public void main(String[] argv) {
            System.out.println("start");
            // Comment out this line and a null pointer exception will be
            // generated after"start" prints and before the following
            // try/catch block even gets entered.
            new C0();
            try {
                System.out.println("retrieve item:" + nested.innerItem);
            }
            catch (Exception e) {
                System.out.println("failed to retrieve item:" + e.toString());
            }
            System.out.println("finish");
        }
    }

    即使"nested"和"inneritem"都声明为"static final"。设置在类被实例化(或至少正如您自己看到的那样,直到嵌套的静态项第一次被引用之后通过注释和取消注释上面提到的行。相同的不适用"outeritem"为true。

    至少这是我在Java 6中看到的。


    内部类的实例是在创建外部类的实例时创建的。因此,内部类的成员和方法可以访问外部类的实例(对象)的成员和方法。当外部类的实例超出范围时,内部类实例也将停止存在。

    静态嵌套类没有具体实例。它只是在第一次使用时加载(就像静态方法一样)。它是一个完全独立的实体,其方法和变量不能访问外部类的实例。

    静态嵌套类不与外部对象耦合,速度更快,并且不占用堆/堆栈内存,因为不需要创建此类的实例。因此,经验法则是尽量用有限的作用域(private>=class>=protected>=public)定义静态嵌套类,然后将其转换为内部类(通过删除"static"标识符),如果确实需要,则松开作用域。


    在创建实例的情况下,非静态内部类是使用以下引用创建的在其中定义它的外部类的对象。这个意味着它有包含实例。但是静态内部类的实例是用外部类的引用创建的,而不是用外部类对象的引用。这意味着它没有包含实例。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    class A
    {
      class B
      {
        // static int x; not allowed here…..    
      }
      static class C
      {
        static int x; // allowed here
      }
    }

    class Test
    {
      public static void main(String… str)
      {
        A o=new A();
        A.B obj1 =o.new B();//need of inclosing instance

        A.C obj2 =new A.C();

        // not need of reference of object of outer class….
      }
    }


    我认为这里没有什么可补充的,大多数答案都完美地解释了静态嵌套类和内部类之间的区别。但是,在使用嵌套类与内部类时,请考虑以下问题。正如在一些答案中提到的那样,没有和其封闭类的实例,内部类就不能被实例化,这意味着它们持有指向其封闭类实例的指针,这可能导致内存溢出或堆栈溢出异常,因为事实上,GC将无法垃圾收集封闭类,即使Y不再使用。要清除此问题,请检查以下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    public class Outer {


        public  class Inner {

        }


        public Inner inner(){
            return new Inner();
        }

        @Override
        protected void finalize() throws Throwable {
        // as you know finalize is called by the garbage collector due to destroying an object instance
            System.out.println("I am destroyed !");
        }
    }


    public static void main(String arg[]) {

        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();

        // out instance is no more used and should be garbage collected !!!
        // However this will not happen as inner instance is still alive i.e used, not null !
        // and outer will be kept in memory until inner is destroyed
        outer = null;

        //
        // inner = null;

        //kick out garbage collector
        System.gc();

    }

    如果删除对// inner = null;的注释,程序将输出"我被摧毁了!",但保持这个评论它不会。原因是白色内部实例仍然被引用,GC无法收集它,并且因为它引用(有指向)外部实例,所以也没有收集它。在项目中拥有足够的这些对象,可能会耗尽内存。与静态内部类相比,静态内部类不具有指向内部类实例的点,因为它与实例无关,但与类相关。上面的程序可以打印"我被摧毁了!"如果使内部类静态化并用Outer.Inner i = new Outer.Inner();实例化


    这些术语可以互换使用。如果你真的想学究一点,那么你可以定义"嵌套类"来引用一个静态的内部类,这个类没有封闭的实例。在代码中,您可能会遇到类似的情况:

    1
    2
    3
    4
    5
    public class Outer {
        public class Inner {}

        public static class Nested {}
    }

    但这并不是一个被广泛接受的定义。


    嵌套类是一个非常通用的术语:每个不是顶级的类都是嵌套类。内部类是非静态嵌套类。约瑟夫·达西写了一篇关于嵌套类、内部类、成员类和顶级类的非常好的解释。


    针对初学者,学习Java和/或嵌套类的初学者

    嵌套类可以是:1。静态嵌套类。2。非静态嵌套类。(也称为内部类)=>请记住这一点

    1、内部类例子:

    1
    2
    3
    4
    5
    class OuterClass  {
    /*  some code here...*/
         class InnerClass  {  }
    /*  some code here...*/
    }

    内部类是嵌套类的子集:

    • 内部类是特定类型的嵌套类
    • 内部类是嵌套类的子集
    • 可以说内部类也是嵌套类,但不能说嵌套类也是内部类。

    内类专业:

    • 内部类的实例可以访问外部类的所有成员,甚至那些标记为"private"的成员。

    2.静态嵌套类:例子:

    1
    2
    3
    4
    5
    class EnclosingClass {
      static class Nested {
        void someMethod() { System.out.println("hello SO"); }
      }
    }

    案例1:从非封闭类实例化静态嵌套类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class NonEnclosingClass {

      public static void main(String[] args) {
        /*instantiate the Nested class that is a static
          member of the EnclosingClass class:
        */


        EnclosingClass.Nested n = new EnclosingClass.Nested();
        n.someMethod();  //prints out"hello"
      }
    }

    案例2:从封闭类实例化静态嵌套类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class EnclosingClass {

      static class Nested {
        void anotherMethod() { System.out.println("hi again"); }
      }

      public static void main(String[] args) {
        //access enclosed class:

        Nested n = new Nested();
        n.anotherMethod();  //prints out"hi again"
      }

    }

    静态类专业:

    • 静态内部类只能访问外部类的静态成员,不能访问非静态成员。

    结论:问题:Java中的内部类和静态嵌套类的主要区别是什么?答:只需仔细阅读上述每门课的细节即可。


    嗯…内部类是嵌套类…你是说匿名阶级和内部阶级吗?

    编辑:如果你实际上是指内心对匿名…内部类只是在类中定义的类,例如:

    1
    2
    3
    4
    public class A {
        public class B {
        }
    }

    而匿名类是匿名定义的类的扩展,因此没有定义实际的"类",如:

    1
    2
    3
    4
    public class A {
    }

    A anon = new A() { /* you could change behavior of A here */ };

    进一步编辑:

    维基百科声称爪哇有不同之处,但我已经和Java工作了8年,这是我第一次听到这样的区别…更不用说这里没有证明索赔的参考资料…归根结底,内部类是在类中定义的类(静态或非静态),嵌套只是表示相同事物的另一个术语。

    静态嵌套类和非静态嵌套类之间有细微的区别…基本上,非静态内部类对封闭类的实例字段和方法具有隐式访问权限(因此它们不能在静态上下文中构造,这将是一个编译器错误)。另一方面,静态嵌套类不具有对实例字段和方法的隐式访问,可以在静态上下文中构造。


    Java中的内部类和嵌套静态类都是在另一个类中声明的类,称为Java中的顶层类。在Java术语中,如果声明嵌套类静态,则它将在Java中称为嵌套静态类,而非静态嵌套类则简称为内部类。

    Java中的内部类是什么?

    任何不是顶级的或在另一个类中声明的类都被称为嵌套类,而在那些嵌套类中,被声明为非静态的类在Java中被称为内部类。Java中有三种内部类:

    1)局部内部类-在代码块或方法内声明。2)匿名内部类-是一个没有名称可引用的类,并且在创建它的同一位置初始化。3)成员内部类-声明为外部类的非静态成员。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public class InnerClassTest {
        public static void main(String args[]) {      
            //creating local inner class inside method i.e. main()
            class Local {
                public void name() {
                    System.out.println("Example of Local class in Java");

                }
            }      
            //creating instance of local inner class
            Local local = new Local();
            local.name(); //calling method from local inner class

            //Creating anonymous inner class in Java for implementing thread
            Thread anonymous = new Thread(){
                @Override
                public void run(){
                    System.out.println("Anonymous class example in java");
                }
            };
            anonymous.start();

            //example of creating instance of inner class
            InnerClassTest test = new InnerClassTest();
            InnerClassTest.Inner inner = test.new Inner();
            inner.name(); //calling method of inner class
        }

         //Creating Inner class in Java
        private class Inner{
            public void name(){
                System.out.println("Inner class example in java");
            }
        }
    }

    Java中嵌套静态类是什么?

    嵌套静态类是另一个类,该类在类内部声明为成员并成为静态类。嵌套的静态类也被声明为外部类的成员,可以像任何其他成员一样成为私有、公共或受保护的类。嵌套静态类相对于内部类的一个主要好处是嵌套静态类的实例没有附加到外部类的任何封闭实例。您也不需要任何外部类实例来创建Java中嵌套静态类的实例。

    1)可以访问包括private在内的外部类的静态数据成员。2)静态嵌套类不能访问非静态(实例)数据成员或方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class NestedStaticExample {
        public static void main(String args[]){  
            StaticNested nested = new StaticNested();
            nested.name();
        }  
        //static nested class in java
        private static class StaticNested{
            public void name(){
                System.out.println("static nested class example in java");
            }
        }
    }

    REF:Java中的内部类和嵌套静态类


    当我们在类内声明静态成员类时,它被称为顶级嵌套类或静态嵌套类。具体表现如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class Test{
        private static int x = 1;
            static class A{
            private static int y = 2;
            public static int getZ(){
                return B.z+x;
            }
        }
        static class B{
            private static int z = 3;
            public static int getY(){
                return A.y;
            }
        }
    }

    class TestDemo{
         public static void main(String[] args){
            Test t = new Test();
            System.out.println(Test.A.getZ());
            System.out.println(Test.B.getY());
        }
    }

    当我们在一个类中声明非静态成员类时,它被称为内部类。内部类可以演示如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        class Test{
            private int i = 10;
            class A{
                private int i =20;
                void display(){
                int i = 30;
                System.out.println(i);
                System.out.println(this.i);
                System.out.println(Test.this.i);
            }
        }
    }


    我认为这里的人应该注意海报上的那一点:静态嵌套类只是第一个内部类。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     public static class A {} //ERROR

     public class A {
         public class B {
             public static class C {} //ERROR
         }
     }

     public class A {
         public static class B {} //COMPILE !!!

     }

    总之,静态类不依赖于它包含的类。所以,他们不能在普通班。(因为普通类需要一个实例)。


    以下是static nested classinner class的示例:

    Java语言

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public class OuterClass {
         private String someVariable ="Non Static";

         private static String anotherStaticVariable ="Static";  

         OuterClass(){

         }

         //Nested classes are static
         static class StaticNestedClass{
            private static String privateStaticNestedClassVariable ="Private Static Nested Class Variable";

            //can access private variables declared in the outer class
            public static void getPrivateVariableofOuterClass(){
                System.out.println(anotherStaticVariable);
            }
         }

         //non static
         class InnerClass{

             //can access private variables of outer class
             public String getPrivateNonStaticVariableOfOuterClass(){
                 return someVariable;
             }
         }

         public static void accessStaticClass(){
             //can access any variable declared inside the Static Nested Class
             //even if it private
             String var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable;
             System.out.println(var);
         }

    }

    OuterClassTest:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class OuterClassTest {
        public static void main(String[] args) {

            //access the Static Nested Class
            OuterClass.StaticNestedClass.getPrivateVariableofOuterClass();

            //test the private variable declared inside the static nested class
            OuterClass.accessStaticClass();
            /*
             * Inner Class Test
             * */


            //Declaration

            //first instantiate the outer class
            OuterClass outerClass = new OuterClass();

            //then instantiate the inner class
            OuterClass.InnerClass innerClassExample =  outerClass. new InnerClass();

            //test the non static private variable
            System.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass());

        }

    }

    我认为以上的答案都不能为您提供一个真实的例子,说明嵌套类和静态嵌套类在应用程序设计方面的区别。静态嵌套类和内部类的主要区别在于访问外部类实例字段的能力。

    让我们看看下面的两个例子。

    静态嵌套类:使用静态嵌套类的一个好例子是构建器模式(https://dzone.com/articles/design patterns-the-builder-pattern)。

    对于BankAccount,我们使用静态嵌套类,主要是因为

  • 静态嵌套类实例不能在外部类之前创建。

  • 在构建器模式中,构建器是用于创建银行帐户的帮助器类。

  • BankAccount.Builder仅与BankAccount关联。没有其他类与BankAccount.Builder相关。所以最好不要使用名称约定将它们组织在一起。
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public class BankAccount {

        private long accountNumber;
        private String owner;
        ...

        public static class Builder {

        private long accountNumber;
        private String owner;
        ...

        static public Builder(long accountNumber) {
            this.accountNumber = accountNumber;
        }

        public Builder withOwner(String owner){
            this.owner = owner;
            return this;
        }

        ...
        public BankAccount build(){
                BankAccount account = new BankAccount();
                account.accountNumber = this.accountNumber;
                account.owner = this.owner;
                ...
                return account;
            }
        }
    }

    内部类:内部类的常见用法是定义事件处理程序。https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html

    对于MyClass,我们使用内部类,主要是因为:

  • 内部类MyAdapter需要访问外部类成员。

  • 在这个例子中,myadapter只与myclass关联。没有其他类与myadapter相关。所以最好不使用名称约定将它们组织在一起

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class MyClass extends Applet {
        ...
            someObject.addMouseListener(new MyAdapter());
        ...
        class MyAdapter extends MouseAdapter {
            public void mouseClicked(MouseEvent e) {
                ...// Event listener implementation goes here...
                ...// change some outer class instance property depend on the event
            }
        }
    }

    Java编程语言允许您在另一个类中定义类。这样的类称为嵌套类,如图所示:

    1
    2
    3
    4
    5
    6
    class OuterClass {
    ...
    class NestedClass {
        ...
        }
    }

    嵌套类分为两类:静态类和非静态类。声明为静态的嵌套类称为静态嵌套类。非静态嵌套类称为内部类。我们应该记住的一点是,非静态嵌套类(内部类)可以访问封闭类的其他成员,即使它们被声明为私有的。静态嵌套类只能访问封闭类的其他成员(如果这些成员是静态的)。它不能访问外部类的非静态成员。与类方法和变量一样,静态嵌套类与其外部类相关联。例如,要为静态嵌套类创建对象,请使用以下语法:

    1
    2
    OuterClass.StaticNestedClass nestedObject =
     new OuterClass.StaticNestedClass();

    要实例化内部类,必须首先实例化外部类。然后,使用以下语法在外部对象内创建内部对象:

    1
    OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();

    为什么使用嵌套类

  • 它是一种逻辑分组类的方法,只在一个地方使用。
  • 它增加了封装。
  • 它可以导致更可读和可维护的代码。
  • 来源:Java?教程-嵌套类


    首先,没有一个称为静态类的类。静态修饰符与内部类(称为嵌套类)一起使用表示它是外部类的静态成员,这意味着我们可以像访问其他静态成员一样访问它,而不需要任何外部类的实例。(原来是静态的好处。)

    使用嵌套类和常规内部类的区别是:

    1
    OuterClass.InnerClass inner = new OuterClass().new InnerClass();

    首先我们可以实例化outerClass,然后我们可以访问inner。

    但是如果类是嵌套的,那么语法是:

    1
    OuterClass.InnerClass inner = new OuterClass.InnerClass();

    它使用静态语法作为静态关键字的正常实现。


    不同之处在于,也为静态的嵌套类声明可以在封闭类的外部实例化。

    当嵌套类声明不是静态的,也称为内部类时,Java将不允许您实例化它,除非通过封闭类。从内部类创建的对象链接到从外部类创建的对象,因此内部类可以引用外部类的字段。

    但是如果它是静态的,那么链接就不存在了,外部字段就不能被访问(除了通过普通的引用,像任何其他对象一样),因此您可以自己实例化嵌套类。


    我已经演示了Java代码中可能出现的各种可能的正确和错误场景。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
        class Outter1 {

            String OutStr;

            Outter1(String str) {
                OutStr = str;
            }

            public void NonStaticMethod(String st)  {

                String temp1 ="ashish";
                final String  tempFinal1 ="ashish";

                //  below static attribute not permitted
                // static String tempStatic1 ="static";    

                //  below static with final attribute not permitted        
                // static final String  tempStatic1 ="ashish";  

                // synchronized keyword is not permitted below          
                class localInnerNonStatic1 {            

                    synchronized    public void innerMethod(String str11) {
                        str11 = temp1 +" sharma";
                        System.out.println("innerMethod ===>"+str11);
                    }

                    /*
            //  static method with final not permitted
              public static void innerStaticMethod(String str11) {

                        str11 = temp1 +" india";
                        System.out.println("innerMethod ===>"+str11);
                    }*/

                }

                // static class not permitted below
                //  static class localInnerStatic1 {   }                            

            }

            public static  void StaticMethod(String st)     {

                String temp1 ="ashish";
                final String  tempFinal1 ="ashish";

                // static attribute not permitted below
                //static String tempStatic1 ="static";    

                //  static with final attribute not permitted below
                // static final String  tempStatic1 ="ashish";                        

                class localInnerNonStatic1 {
                    public void innerMethod(String str11) {
                        str11 = temp1 +" sharma";
                        System.out.println("innerMethod ===>"+str11);
                    }

                    /*
        // static method with final not permitted
        public static void innerStaticMethod(String str11) {  
                        str11 = temp1 +" india";
                        System.out.println("innerMethod ===>"+str11);
                    }*/

                }

                // static class not permitted below
                //  static class localInnerStatic1 {   }    

            }

            // synchronized keyword is not permitted
            static  class inner1 {          

                static String  temp1 ="ashish";
                String  tempNonStatic ="ashish";
                // class localInner1 {

                public void innerMethod(String str11) {
                    str11 = temp1 +" sharma";
                    str11 = str11+ tempNonStatic +" sharma";
                    System.out.println("innerMethod ===>"+str11);
                }

                public static void innerStaticMethod(String str11) {
                    //  error in below step
                    str11 = temp1 +" india";    
                    //str11 = str11+ tempNonStatic +" sharma";
                    System.out.println("innerMethod ===>"+str11);
                }
                //}
            }

            //synchronized keyword is not permitted below
            class innerNonStatic1 {            

    //This is important we have to keep final with static modifier in non
    // static innerclass below
                static final String  temp1 ="ashish";  
                String  tempNonStatic ="ashish";
                // class localInner1 {

                synchronized    public void innerMethod(String str11) {
                    tempNonStatic = tempNonStatic +" ...";
                    str11 = temp1 +" sharma";
                    str11 = str11+ tempNonStatic +" sharma";
                    System.out.println("innerMethod ===>"+str11);
                }

                /*
                //  error in below step
                public static void innerStaticMethod(String str11) {  
                                //  error in below step
                                // str11 = tempNonStatic +" india";                    
                                str11 = temp1 +" india";
                                System.out.println("innerMethod ===>"+str11);
                            }*/

                        //}
                    }
        }