Java内部类和静态嵌套类

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

890786 次浏览

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

编辑:如果您实际上是指内部与匿名:内部类只是在类中定义的类,例如:

public class A {public class B {}}

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

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

进一步编辑:

维基百科声称有区别Java,但我已经和Java一起工作了八年,这是我第一次听到这样的区别——更不用说那里没有引用来支持这个说法……底线,内部类是在类中定义的类(静态或非静态),嵌套只是另一个术语,意思是同样的事情。

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

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

public class Outer {public class Inner {}
public static class Nested {}}

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

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() { ... }在静态上下文中定义的内部类,没有封闭实例。

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

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

静态嵌套类没有具体实例,在第一次使用时(和静态方法一样)被加载。它是一个完全独立的实体,其方法和变量对外部类的实例没有任何访问权限。

静态嵌套类不与外部对象耦合,它们更快,并且不占用堆/堆栈内存,因为没有必要创建此类的实例。因此经验法则是尝试定义静态嵌套类,范围尽可能有限(私有>=类>=保护>=公共),然后将其转换为内部类(通过删除“静态”标识符)并放宽范围。

我不认为真正的区别在上述答案中变得清晰。

首先要正确理解术语:

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

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

如果您只想将类保持在一起,或者如果嵌套类专门用于封闭类,则可以使用静态嵌套类。静态嵌套类和其他类之间没有语义差异。

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

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 availablereturn new Item(data);}public Item createSubItem(Object data){// compiles, since 'this' Container is availablereturn new Item(data);}}

在这种情况下,您希望从子项引用父容器。使用非静态嵌套类,这无需任何工作即可工作。您可以使用语法Container.this访问容器的封闭实例。

更多硬核解释如下:

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

// class version 49.0 (49)// access flags 33public class Container$Item {
// compiled from: Container.java// access flags 1public INNERCLASS Container$Item Container Item
// access flags 0Object data
// access flags 4112final Container this$0
// access flags 1public getContainer() : ContainerL0LINENUMBER 7 L0ALOAD 0: thisGETFIELD Container$Item.this$0 : ContainerARETURNL1LOCALVARIABLE this Container$Item L0 L1 0MAXSTACK = 1MAXLOCALS = 1
// access flags 1public <init>(Container,Object) : voidL0LINENUMBER 12 L0ALOAD 0: thisALOAD 1PUTFIELD Container$Item.this$0 : ContainerL1LINENUMBER 10 L1ALOAD 0: thisINVOKESPECIAL Object.<init>() : voidL2LINENUMBER 11 L2ALOAD 0: thisALOAD 2: dataPUTFIELD Container$Item.data : ObjectRETURNL3LOCALVARIABLE this Container$Item L0 L3 0LOCALVARIABLE data Object L0 L3 2MAXSTACK = 2MAXLOCALS = 3}

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

马丁的例子

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

将被编译为类似(在字节码中)的调用

new InnerClass(outerObject)

为完整起见:

匿名类是非静态嵌套类的完美示例,它没有与之关联的名称,以后无法引用。

Java教程说

术语:嵌套类是分为两类:静态和非静态。嵌套类被声明为静态的简单调用静态嵌套类。非静态嵌套类称为内部类类。

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

类可以嵌套无限,例如类A可以包含类B,其中包含类C,其中包含类D,等等。然而,多于一个级别的类嵌套是罕见的,因为它通常是糟糕的设计。

有三个原因可以创建嵌套类:

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

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

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

让我更详细地阐述一下。


静态类

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

静态类是声明为另一个类的静态成员的类。就像其他静态成员一样,这样的类实际上只是一个使用包含类作为其命名空间的悬挂器,e. g.在包披萨中声明为类犀牛的静态成员的类山羊被称为名称披萨犀牛山羊

package pizza;
public class Rhino {
...
public static class Goat {...}}

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


内部类

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

package pizza;
public class Rhino {
public class Goat {...}
private void jerry() {Goat g = new Goat();}}

与静态类一样,内部类被其包含类名披萨犀牛山羊称为限定类,但在包含类内部,它可以通过其简单名称已知。然而,内部类的每个实例都绑定到其包含类的特定实例:在上面,在杰里中创建的山羊隐式绑定到杰里中的犀牛实例这个。否则,当我们实例化山羊时,我们将关联的犀牛实例显式化:

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

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

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

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

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


局部内部类

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

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

如果一个局部内部类是在实例方法中声明的,则该内部类的实例化在创建实例时与包含方法的这个持有的实例绑定,因此可以像在实例内部类中一样访问包含类的实例成员。局部内部类只是通过实例化其名称,e. g.局部内部类Cat实例化为新Cat(),而不是像你想象的那样新的this. Cat()。


匿名内部类

匿名内部类是一种在语法上方便的编写本地内部类的方法。最常见的是,本地内部类在每次运行其包含方法时最多实例化一次。如果我们能将本地内部类定义及其单个实例化组合成一种方便的语法形式会很好,如果我们不必为类想一个名称(代码包含的无用名称越少越好)也会更好。匿名内部类允许这两件事:

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

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

或者,您可以指定一个接口来实现:

new *InterfaceName*() {*members*}

这样的声明创建了一个未命名类的新实例,该实例扩展了Object并实现了接口名字。同样,您不能提供自己的构造函数;在这种情况下,Java隐式地提供了一个no-arg,什么都不做的构造函数(因此在这种情况下永远不会有构造函数参数)。

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

需要清楚的是,匿名内部类只是使用一个实例创建本地内部类的一种不太灵活的方式。如果你想要一个实现多个接口的本地内部类,或者在扩展对象以外的类或指定自己的构造函数时实现接口的本地内部类,你就只能创建一个常规的命名本地内部类。

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

而静态属性在类通过其构造函数实例化之前被实例化,嵌套静态类内的静态属性似乎直到类的构造函数被调用,或者至少直到属性首次被引用之后,即使它们被标记为“最终”。

考虑这个例子:

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

即使“嵌套”和“innerItem”都被声明为“静态最终”nested.inner直到类实例化(或至少直到嵌套的静态项第一次被引用),正如你可以看到自己通过注释和取消注释我在上面提到的行。同样的情况不成立'outerItem'为true。

至少这是我在Java6.0中看到的。

嵌套类:类内的类

类型:

  1. 静态嵌套类
  2. 非静态嵌套类[内部类]

区别:

非静态嵌套类[内部类]

在非静态嵌套类中,内部类的对象存在于外部类的对象中。因此外部类的数据成员可以被内部类访问。因此要创建内部类的对象,必须先创建外部类的对象。

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

静态嵌套类

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

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

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

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

我认为,一般遵循的惯例是这样的:

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

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

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

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

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

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

我觉得更大的问题仍然是使用哪个以及何时使用?嗯,这主要取决于你正在处理的情况,但阅读@jrudolph给出的回复可能会帮助你做出一些决定。

我认为这里的人应该注意到海报:静态巢类只是第一个内部类。例如:

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

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

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

概览

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

差异

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

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

结论

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

内部类(称为嵌套类)使用的静态修饰符表示它是外部类的静态成员,这意味着我们可以像其他静态成员一样访问它,而无需任何外部类的实例。(这最初是静态的好处。)

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

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

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

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

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

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

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

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

它们被视为封闭类的成员,因此您可以指定四个访问说明符中的任何一个-private, package, protected, public。我们对顶级类没有这种奢侈,只能声明public或包私有。

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

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相关。

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

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

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

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

当你知道一个静态的内部类与封闭类/顶部类的实例没有任何关系时,你会定义一个静态的内部类。如果你的内部类不使用外部类的方法或字段,那只是浪费空间,所以让它成为静态的。

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

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

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

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

例如:

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

目标学习者,谁是新手Java和/或嵌套类

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


1.内部类
示例:

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


内部类是嵌套类的子集:

  • 内部类是一种特定类型的嵌套类
  • 内部类是嵌套类的子集
  • 你可以说一个内部类也是一个嵌套类,但是你可以Not说嵌套类也是一个内部类

内部类的特长:

  • 内部类的实例有获得所有个外部类的成员,即使是那些标记为“私有”的成员


2.静态嵌套类:
示例:

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

静态类的特点:

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

结论:
提问:Java中内部类和静态嵌套类的主要区别是什么?
回答:只是通过上面提到的每个类的细节。

我认为这里没有太多要补充的,大多数答案完美地解释了静态嵌套类和内部类之间的区别。然而,在使用嵌套类和内部类时,请考虑以下问题。正如在几个答案中提到的,内部类不能在没有它们的封闭类的实例的情况下实例化,这意味着它们保留指针实例化为它们的封闭类的实例,这可能导致内存溢出或堆栈溢出异常,因为GC将无法垃圾收集封闭类,即使它们不再使用。为了清楚这一点,请检查以下代码:

public class Outer {

public  class Inner {
}

public Inner inner(){return new Inner();}
@Overrideprotected void finalize() throws Throwable {// as you know finalize is called by the garbage collector due to destroying an object instanceSystem.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 destroyedouter = null;
//// inner = null;
//kick out garbage collectorSystem.gc();
}

如果删除// inner = null;上的注释,程序将输出"我被毁灭了!",但保留此注释不会。
原因是白色的内部实例仍然被引用GC无法收集它,因为它引用(有一个指针指向)外部实例,它也不会被收集。与静态内部类相比,它不持有指向内部类实例的点,因为它不是实例相关的,而是类相关的。上面的程序可以打印“我被毁灭了!”,如果你使内部类静态并用Outer.Inner i = new Outer.Inner();实例化

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

希望有帮助!

内部类

  • 可以访问到外部类实例和静态方法和字段
  • 与封闭类的实例关联所以要实例化它首先需要一个外部类的实例(注意新的关键字place):

    Outerclass.InnerClass innerObject = outerObject.new Innerclass();
  • Cannot define any static members itself

  • Cannot have Class or Interface declaration

Static nested class

  • Cannot access outer class instance methods or fields

  • Not associated with any instance of enclosing class So to instantiate it:

    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?

According to Oracle documentation there're several reasons (full documentation):

  • 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.

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

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

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

当我们在类内声明静态成员类时,它被称为顶级嵌套类或静态嵌套类。它可以演示如下:

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

以下是static nested classinner class的示例:

OuterClass.java

public class OuterClass {private String someVariable = "Non Static";
private static String anotherStaticVariable = "Static";
OuterClass(){
}
//Nested classes are staticstatic class StaticNestedClass{private static String privateStaticNestedClassVariable = "Private Static Nested Class Variable";
//can access private variables declared in the outer classpublic static void getPrivateVariableofOuterClass(){System.out.println(anotherStaticVariable);}}
//non staticclass InnerClass{
//can access private variables of outer classpublic String getPrivateNonStaticVariableOfOuterClass(){return someVariable;}}
public static void accessStaticClass(){//can access any variable declared inside the Static Nested Class//even if it privateString var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable;System.out.println(var);}
}

外部测试:

public class OuterClassTest {public static void main(String[] args) {
//access the Static Nested ClassOuterClass.StaticNestedClass.getPrivateVariableofOuterClass();
//test the private variable declared inside the static nested classOuterClass.accessStaticClass();/** Inner Class Test* */
//Declaration
//first instantiate the outer classOuterClass outerClass = new OuterClass();
//then instantiate the inner classOuterClass.InnerClass innerClassExample =  outerClass. new InnerClass();
//test the non static private variableSystem.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass());
}
}

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

什么是Java内部阶级?

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

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

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 classLocal local = new Local();local.name(); //calling method from local inner class
//Creating anonymous inner class in Java for implementing threadThread anonymous = new Thread(){@Overridepublic void run(){System.out.println("Anonymous class example in java");}};anonymous.start();
//example of creating instance of inner classInnerClassTest test = new InnerClassTest();InnerClassTest.Inner inner = test.new Inner();inner.name(); //calling method of inner class}
//Creating Inner class in Javaprivate class Inner{public void name(){System.out.println("Inner class example in java");}}}

什么是嵌套静态类在Java?

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

1)它可以访问外部类的静态数据成员,包括私有类。
2)静态嵌套类不能访问非静态(实例)数据成员方法

public class NestedStaticExample {public static void main(String args[]){StaticNested nested = new StaticNested();nested.name();}//static nested class in javaprivate static class StaticNested{public void name(){System.out.println("static nested class example in java");}}}

参考:内类和嵌套静态类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 belowclass localInnerNonStatic1 {
synchronized    public void innerMethod(String str11) {str11 = temp1 +" sharma";System.out.println("innerMethod ===> "+str11);}
/*//  static method with final not permittedpublic 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 permittedpublic 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 permittedstatic  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 stepstr11 = temp1 +" india";//str11 = str11+ tempNonStatic +" sharma";System.out.println("innerMethod ===> "+str11);}//}}
//synchronized keyword is not permitted belowclass innerNonStatic1 {
//This is important we have to keep final with static modifier in non// static innerclass belowstatic 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 steppublic static void innerStaticMethod(String str11) {//  error in below step// str11 = tempNonStatic +" india";str11 = temp1 +" india";System.out.println("innerMethod ===> "+str11);}*///}}}

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

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

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

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

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

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

为什么我们使用嵌套类

  1. 它是一种对只在一个地方使用的类进行逻辑分组的方法。
  2. 它增加了封装。
  3. 它可以导致更具可读性和可维护性的代码。

来源:Java™教程-嵌套类

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

让我们看一下以下两个例子。

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

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

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

  2. 在生成器模式中,生成器是一个帮助类,用于创建银行账户。

  3. BankAccount. Builder仅与Bank帐户相关联。没有其他类与BankAccount. Builder相关。所以最好在不使用名称约定的情况下将它们组织在一起。
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,我们使用内部类,主要是因为:

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

一个图表

在此处输入图片描述

static nestednon-static nested类之间的主要区别是static nested没有访问非静态外部类成员

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

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

public class Bank {
// maximum limit as per current bank policy// is subject to changeprivate 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 limitcreditCard.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 classprivate 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 falsepublic 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了解它们与内部类一起存在的原因。