English 中文(简体)
Java内部类和静态嵌套类
原标题:
  • 时间:2008-09-16 08:22:35
  •  标签:

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

最佳回答

Java教程

嵌套类分为两类:静态类和非静态类。声明为静态的嵌套类简称为静态嵌套类。非静态嵌套类称为内部类。

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

OuterClass.StaticNestedClass

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

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

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

class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

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

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

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

请参阅:Java教程-嵌套类

为了完整起见,请注意还有一个内部类没有封闭实例

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.

一般来说,“嵌套”和“内部”这两个术语被大多数程序员互换使用,但我将使用正确的术语“嵌套类”,它涵盖内部和静态。

类可以无限嵌套,例如,类A可以包含B类,B类包含C类,C类包含D类等。然而,很少有一个以上级别的类嵌套,因为这通常是糟糕的设计。

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

  • organization: sometimes it seems most sensible to sort a class into the namespace of another class, especially when it won t be used in any other context
  • access: nested classes have special access to the variables/fields of their containing classes (precisely which variables/fields depends on the kind of nested class, whether inner or static).
  • convenience: having to create a new file for every new type is bothersome, again, especially when the type will only be used in one context

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

  • static class: declared as a static member of another class
  • inner class: declared as an instance member of another class
  • local inner class: declared inside an instance method of another class
  • anonymous inner class: like a local inner class, but written as an expression which returns a one-off object

让我详细阐述一下。


Static Classes

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

静态类是一个被声明为另一个类的静态成员的类。就像其他静态成员一样,这样的类实际上只是一个使用包含类作为其命名空间的挂钩,例如在包pizza中声明为类Rhino的静态成员的类Goat被称为pizza.Rhino.Goat

package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

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


Inner Classes

内部类是一个被声明为另一个类的非静态成员的类:

package pizza;

public class Rhino {

    public class Goat {
        ...
    }

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

与静态类一样,内部类通过其包含类名pizza.Rhino.Goat来限定,但在包含类内部,可以通过其简单名称来知道。然而,内部类的每个实例都绑定到其包含类的特定实例:上面,在jerry中创建的Goat隐式绑定到Rhino实例thisjerry中。否则,当我们实例化<em>Goat</em>时,我们会使关联的<em>Rhino</em〕实例显式:

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

(请注意,在奇怪的new语法中,您将内部类型称为Goat:Java从rhino部分推断出包含类型。是的,new rhino.Goat()对我来说也更有意义。)

那么,这给我们带来了什么呢?好吧,内部类实例可以访问包含类实例的实例成员。这些封闭实例成员在内部类中通过引用,只是引用它们的简单名称,而不是通过this(内部类中的this指的是内部类实例,而不是关联的包含类实例):

public class Rhino {

    private String barry;

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

在内部类中,您可以将包含类的this引用为Rhino.this,并且您可以使用this来引用其成员,例如Rhino.tis.barry


Local Inner Classes

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

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

如果在实例方法中声明了本地内部类,则内部类的实例化在实例创建时绑定到包含方法sthis所持有的实例,因此包含类的实例成员可以像在实例内部类中一样访问。本地内部类通过其名称被简单地实例化,例如本地内部类Cat被实例化为new Cat(),而不是你所期望的new this.Cat()。


Anonymous Inner Classes

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

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

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

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

new *InterfaceName*() {*members*}

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

即使不能为匿名内部类提供构造函数,也可以使用初始化器块(放置在任何方法外部的{}块)进行任何需要的设置。

要清楚的是,匿名内部类只是用一个实例创建本地内部类的一种不太灵活的方法。如果您想要一个实现多个接口的本地内部类,或者在扩展<em>Object</em>以外的某个类时实现接口,或者指定自己的构造函数,那么您需要创建一个常规的命名本地内部类。

我不认为上述答案中真正的区别是显而易见的。

首先要正确使用条款:

  • A nested class is a class which is contained in another class at the source code level.
  • It is static if you declare it with the static modifier.
  • A non-static nested class is called inner class. (I stay with non-static nested class.)

到目前为止,马丁的回答是正确的。然而,实际的问题是:是否声明嵌套类为静态的目的是什么?

如果您只想将类保持在一起(如果它们以主题方式属于一起),或者如果嵌套类仅在封闭类中使用,则可以使用静态嵌套类。静态嵌套类和其他类之间没有语义上的区别。

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

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访问Container的封闭实例。

更多核心解释如下:

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

// 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
}

正如您所看到的,编译器创建了一个隐藏字段容器this$0。这是在构造函数中设置的,该构造函数有一个Container类型的附加参数来指定封闭实例。您无法在源代码中看到此参数,但编译器会为嵌套类隐式生成它。

马丁的例子

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

会被编译为类似(字节码中)的调用吗

new InnerClass(outerObject)

为了完整起见:

匿名类非静态嵌套类的完美例子,该类没有与之关联的名称,以后也不能引用。

我认为以上任何一个答案都无法向您解释嵌套类和静态嵌套类在应用程序设计方面的真正区别:

OverView

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

Difference

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

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

Conclusion

因此,从设计的角度来看,两者之间的主要区别是:<em>非静态嵌套类可以访问容器类的实例,而静态嵌套类不能访问</em>。

以下是Java内部类和静态嵌套类之间的主要区别和相似之处。

希望它能有所帮助!

Inner class

  • Can access to outer class both instance and static methods and fields
  • 与封闭类的实例关联,因此要实例化它,首先需要一个外部类的实例(注意new关键字place):

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

  • Cannot have Class or Interface declaration

Static nested class

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

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

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

Similarities

  • Both Inner classes can access even private fields and methods of outer class
  • Also the Outer class have access to private fields and methods of inner classes
  • Both classes can have private, protected or public access modifier

Why Use Nested Classes?

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

  • 这是一种对只在一个地方使用的类进行逻辑分组的方法:如果一个类只对另一个类有用,那么将其嵌入该类并将两者保持在一起是合乎逻辑的。嵌套这样的“辅助类”可以使它们的包更加精简。

  • 它增加了封装:考虑两个顶级类A和B,其中B需要访问A的成员,否则这些成员将被声明为私有。通过将类B隐藏在类A中,可以将A的成员声明为私有,B可以访问它们。此外,B本身可以对外界隐藏。

  • 它可以产生更具可读性和可维护性的代码:将小类嵌套在顶级类中会使代码更接近使用位置。

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

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

它们被视为封闭类的成员,因此您可以指定四个访问说明符中的任何一个-<code>private、package、protected、public

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

public class OuterClass {
    public static class Inner1 {
    }
    public class Inner2 {
    }
}

Inner1是我们的静态内部类,而Inner2则是我们的非静态内部类。它们之间的关键区别是,如果没有Outer,您无法创建Inner2实例,因为您可以独立创建Inner1对象。

你什么时候使用Inner类?

想想这样一种情况:ClassAClass B是相关的,Class B需要访问ClassA成员,而类别Ba类相关。内心的阶级也随之出现。

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

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

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

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

You would define a static inner class when you know that it does not have any relationship with the instance of the enclosing class/top class. If your inner class doesn t use methods 或 fields of the outer class, it s just a waste of space, so make it static.

F或 example, to create an object f或 the static nested class, use this syntax:

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

The advantage of a static nested class is that it doesn t need an object of the containing class/top class to w或k. This can help you to reduce the number of objects your application creates at runtime.

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

  • static class within a top level class is a nested class
  • non static class within a top level class is a inner class, which further has two more form:
    • local class - named classes declared inside of a block like a method or constructor body
    • anonymous class - unnamed classes whose instances are created in expressions and statements

然而,要记住的其他要点很少:

  • 顶层类和静态嵌套类在语义上是相同的,只是在静态嵌套类的情况下,它可以静态引用其Outer〔parent〕类的私有静态字段/方法,反之亦然。

  • 内部类可以访问外部[parent]类的封闭实例的实例变量。然而,并不是所有的内部类都有封闭实例,例如静态上下文中的内部类,如静态初始化器块中使用的匿名类,没有。

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

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

我觉得还有一个更大的问题悬而未决,那就是什么时候使用哪一个?这主要取决于你正在处理的情况,但阅读@jrudolph给出的回复可能会帮助你做出一些决定。

嵌套类:类内部的类

类型:

  1. Static nested class
  2. Non-static nested class [Inner class]

差异:

非静态嵌套类〔内部类〕

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

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

静态嵌套类

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

class outerclass A {
    static class nestedclass B {
        static int x = 10;
    }
}

如果您想访问x,那么在方法内部编写以下内容

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

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

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

静态嵌套类不与外部对象耦合,速度更快,而且不占用堆/堆栈内存,因为不需要创建此类的实例。因此,经验法则是尝试定义静态嵌套类,其范围尽可能有限(private>;=class>;=protected>;=public),然后将其转换为内部类(通过删除“静态”标识符),如果确实有必要,则放宽范围。

嵌套静态类的使用有一个微妙之处,它在某些情况下可能很有用。

Whereas static attributes get instantiated before the class gets instantiated via its constructor, static attributes inside of nested static classes don t seem to get instantiated until after the class s constructor gets invoked, or at least not until after the attributes are first referenced, even if they are marked as final .

考虑这个例子:

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");
    }
}

Even though nested and innerItem are both declared as static final . the setting of nested.innerItem doesn t take place until after the class is instantiated (or at least not until after the nested static item is first referenced), as you can see for yourself by commenting and uncommenting the lines that I refer to, above. The same does not hold true for outerItem .

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

这些术语可以互换使用。如果你想对此非常迂腐,那么可以定义“嵌套类”来引用静态内部类,即没有封闭实例的类。在代码中,您可能会有这样的内容:

public class Outer {
    public class Inner {}

    public static class Nested {}
}

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

In the case of creating instance, the instance of non static inner class is created with the reference of object of outer class in which it is defined. This means it have inclosing instance. But the instance of static inner class is created with the reference of Outer class, not with the reference of object of outer class. This means it have not inclosing instance.

例如:

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….
  }
}

I don t think there is much to add here, most of the answers perfectly explain the differences between static nested class and Inner classes. However, consider the following issue when using nested classes vs inner classes. As mention in a couple of answers inner classes can not be instantiated without and instance of their enclosing class which mean that they HOLD a pointer to the instance of their enclosing class which can lead to memory overflow or stack overflow exception due to the fact the GC will not be able to garbage collect the enclosing classes even if they are not used any more. To make this clear check the following code out:

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();

}

If you remove the comment on // inner = null; The program will out put "I am destroyed !", but keeping this commented it will not.
The reason is that white inner instance is still referenced GC cannot collect it and because it references (has a pointer to) the outer instance it is not collected too. Having enough of these objects in your project and can run out of memory.
Compared to static inner classes which does not hold a point to inner class instance because it is not instance related but class related. The above program can print "I am destroyed !" if you make Inner class static and instantiated with Outer.Inner i = new Outer.Inner();

Nested class is a very general term: every class which is not top level is a nested class. An inner class is a non-static nested class. Joseph Darcy wrote a very nice explanation about Nested, Inner, Member, and Top-Level Classes.

针对Java和/或嵌套类新手的学习者

Nested classes can be either:
1. Static Nested classes.
2. Non Static Nested classes. (also known as Inner classes) =>Please remember this


1.Inner classes
Example:

class OuterClass  {
/*  some code here...*/
     class InnerClass  {  }
/*  some code here...*/
}


内部类是嵌套类的子集:

  • inner class is a specific type of nested class
  • inner classes are subsets of nested classes
  • You can say that an inner class is also a nested class, but you can NOT say that a nested class is also an inner class.

内班专业:

  • instance of an inner class has access to all of the members of the outer class, even those that are marked “private”


2.Static Nested Classes:
Example:

class EnclosingClass {
  static class Nested {
    void someMethod() { System.out.println("hello SO"); }
  }
}

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

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:从封闭类实例化静态嵌套类

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"
  }

}

静态类专业:

  • Static inner class would only have access to the static members of the outer class, and have no access to non-static members.

Conclusion:
Question: What is the main difference between a inner class and a static nested class in Java?
Answer: just go through specifics of each class mentioned above.

我认为上面的答案都没有给你一个真正的例子,说明嵌套类和静态嵌套类在应用程序设计方面的区别。静态嵌套类和内部类之间的主要区别是访问外部类实例字段的能力。

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

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

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

  1. 静态嵌套类实例可以在外部类之前创建。

  2. 在生成器模式中,生成器是一个用于创建BankAccount的辅助类。

  3. BankAccount.Builder is only associated with BankAccount. No other classes are related to BankAccount.Builder. so it is better to organize them together without using name convention.
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;
        }
    }
}

Inner class: A common use of inner classes is to define an event handler. https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html

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

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

  2. 在该示例中,MyAdapter仅与MyClass相关联。没有其他类与MyAdapter相关。所以最好在不使用名称约定的情况下将它们组织在一起

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
        }
    }
}

嗯…内部类是嵌套类…你是指匿名类和内部类吗?

编辑:如果你实际上是指内部v.s.匿名:内部类只是在类中定义的一个类,例如:

public class A {
    public class B {
    }
}

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

public class A {
}

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

进一步编辑:

维基百科声称Java中存在差异,但我已经使用Java八年了,这是我第一次听到这样的区别——更不用说没有引用来支持这种说法了…总而言之,内部类是在类中定义的类(静态或非静态),嵌套只是另一个意思相同的术语。

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

Java中的内部类嵌套静态类

Java中的内部类是什么

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

1) Local inner class - is declared inside a code block or method.
2) Anonymous inner class - is a class which doesn t have name to reference and initialized at same place where it gets created.
3) Member inner class - is declared as non static member of outer class.

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中的嵌套静态类是什么

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

1) It can access static data members of outer class including private.
2) Static nested class cannot access non-static (instance) data member or method.

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");
        }
    }
}

参考:Java中的内部类和嵌套静态类(带示例)

图表

静态嵌套非静态嵌套类之间的主要区别在于static nested不能访问非静态外部类成员

I think people here should notice to Poster that : Static Nest Class just only the first inner class. For example:

 public static class A {} //ERROR

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

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

 }

所以,总结一下,静态类并不取决于它包含哪个类。所以,他们不能在普通课堂上。(因为普通类需要一个实例)。

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

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());
    }
}

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

    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);
        }
    }
}

以下是静态嵌套类内部类

外部类.java

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);
     }

}

外部类别测试:

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()); 

    }

}

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

class OuterClass {
...
class NestedClass {
    ...
    }
}

Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are called static nested classes. Non-static nested classes are called inner classes. One thing that we should keep in mind is Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private. Static nested classes only have access to other members of the enclosing class if those are static. It can not access non static members of the outer class. As with class methods and variables, a static nested class is associated with its outer class. For example, to create an object for the static nested class, use this syntax:

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

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

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

为什么我们使用嵌套类

  1. It is a way of logically grouping classes that are only used in one place.
  2. It increases encapsulation.
  3. It can lead to more readable and maintainable code.

来源:Java语言™ 教程-嵌套类

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

使用Nested类和常规Inner类的区别在于:

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

首先我们可以实例化Outerclass,然后我们可以访问Inner。

但如果Class是嵌套的,则语法为:

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

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

除了已经提到的那些用例之外,嵌套类的另一个用例是当嵌套类具有只能从外部类访问的方法时。这是可能的,因为外部类可以访问嵌套类的私有构造函数、字段和方法。

在下面的示例中,Bank可以发布一个Bank.CreditCard,它有一个私有构造函数,并且可以使用Bank.CreditCard的私有setLimit(…)实例方法根据当前银行策略更改信用卡的限额。(在这种情况下,直接字段访问实例变量limit也可以)。从任何其他类中,只能访问Bank.CreditCard的公共方法。

public class Bank {

    // maximum limit as per current bank policy
    // is subject to change
    private int maxLimit = 7000;

    // ------- PUBLIC METHODS ---------

    public CreditCard issueCard(
            final String firstName,
            final String lastName
    ) {
        final String number = this.generateNumber();
        final int expiryDate = this.generateExpiryDate();
        final int CVV = this.generateCVV();
        return new CreditCard(firstName, lastName, number, expiryDate, CVV);
    }


    public boolean setLimit(
            final CreditCard creditCard,
            final int limit
    ) {
        if (limit <= this.maxLimit) {    // check against current bank policy limit
            creditCard.setLimit(limit);  // access private method Bank.CreditCard.setLimit(int)
            return true;
        }
        return false;
    }

    // ------- PRIVATE METHODS ---------

    private String generateNumber() {
        return "1234-5678-9101-1123";   // the numbers should be unique for each card
    }


    private int generateExpiryDate() {
        return 202405;                  // date is YYYY=2024, MM=05
    }


    private int generateCVV() {
        return 123;                     // is in real-life less predictable
    }


    // ------- PUBLIC STATIC NESTED CLASS ---------

    public static final class CreditCard {
        private final String firstName;
        private final String lastName;
        private final String number;
        private final int expiryDate;
        private final int CVV;

        private int balance;
        private int limit = 100; // default limit

        // the constructor is final but is accessible from outer class
        private CreditCard(
                final String firstName,
                final String lastName,
                final String number,
                final int expiryDate,
                final int CVV
        ) {
            this.firstName = firstName;
            this.lastName = lastName;
            this.number = number;
            this.expiryDate = expiryDate;
            this.CVV = CVV;
        }

        // ------- PUBLIC METHODS ---------

        public String getFirstName() {
            return this.firstName;
        }

        public String getLastName() {
            return this.lastName;
        }

        public String getNumber() {
            return this.number;
        }

        public int getExpiryDate() {
            return this.expiryDate;
        }

        // returns true if financial transaction is successful
        // otherwise false
        public boolean charge(final int amount) {
            final int newBalance = this.balance - amount;
            if (newBalance < -this.limit) {
                return false;
            }
            this.balance = newBalance;
            return true;
        }

        // ------- PRIVATE METHODS ---------

        private int getCVV() {
            return this.CVV;
        }

        private int getBalance() {
            return this.balance;
        }

        private void setBalance(final int balance) {
            this.balance = balance;
        }

        private int getLimit() {
            return limit;
        }

        private void setLimit(final int limit) {
            this.limit = limit;
        }
    }
}

静态嵌套类访问它们所定义的类的PRIVATE类级静态变量。从体系结构的角度来看,这可能是巨大的(即服务定位器模式在服务中使用嵌套的静态帮助类),并可能帮助OP了解它们与内部类一起存在的原因。

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

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

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

我已经说明了在java代码中可能出现的各种正确和错误的情况。

    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);
                        }*/
                    //}
                }
    }




相关问题