Java内部类和静态嵌套类

2073

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


99
Joshua Bloch在《Effective Java》一书的第22条建议中提到:优先使用静态成员类而不是非静态成员类。 - Raymond Chenon
24
记录一下,它是同一本书的第三版中的第24项。 - ZeroCool
28个回答

4

当我们在一个类中声明静态成员类时,它被称为顶层嵌套类或静态嵌套类。以下是示例:

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

当我们在类内部声明静态成员类时,它被称为顶层嵌套类。这并没有意义。顶层类是指不是嵌套类的类。请参考:https://docs.oracle.com/javase/specs/jls/se10/html/jls-8.html。因此,“顶层嵌套类”这个概念是不存在的。 - Radiodef

3
以下是静态嵌套类和内部类的示例:
OuterClass.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);
     }

}

OuterClassTest:

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

    }

}

1
Java编程语言允许您在另一个类中定义一个类。这样的类被称为嵌套类,下面是示例:
class OuterClass {
...
class NestedClass {
    ...
    }
}

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

要实例化内部类,必须先实例化外部类。然后,使用以下语法在外部对象中创建内部对象:
OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();

为什么我们使用嵌套类

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

来源:Java™教程 - 嵌套类


0
首先,没有叫做静态类的类。使用静态修饰符与内部类(称为嵌套类)一起使用时,表示它是外部类的静态成员,这意味着我们可以像访问其他静态成员一样访问它,而不需要任何外部类的实例。(这就是静态的好处。)
使用嵌套类和常规内部类之间的区别在于:
OuterClass.InnerClass inner = new OuterClass().new InnerClass();

首先,我们可以实例化外部类,然后才能访问内部类。

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

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

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


1
它不是错误的想法认为静态嵌套类是外部类的“成员类”,但是与静态字段和方法相似之处就到此为止了。 静态嵌套类不“属于”外部类。在几乎所有有关的方面,静态嵌套类都是一个独立的顶级类,其类定义已嵌套在外部类的类定义中,以进行打包便利(并且,希望因为嵌套类和外部类之间存在逻辑关联...尽管不需要)。 - scottb
1
“静态内部类”是一个自相矛盾的说法。静态类确实存在于第一层嵌套中,但根据定义,它们不是内部类。非常困惑。 - user207421

0

静态嵌套类可以访问其所定义的类的私有类级静态变量。从架构的角度来看,这可能非常重要(例如,在服务中使用嵌套静态辅助类的服务定位器模式),并且可以帮助 OP 理解为什么它们与内部类一起存在。


0

嵌套类的另一个用例是当嵌套类具有仅应从外部类访问的方法时。这是可能的,因为外部类可以访问嵌套类的私有构造函数、字段和方法。

在下面的示例中,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;
        }
    }
}

-1

区别在于嵌套类声明也是静态的,可以在封闭类之外实例化。

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

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


1
这是不正确的。有一种特殊的语法可以在封闭类的范围之外创建内部类。 - user207421
@user207421 这是什么语法?你是指 new outer().new inner() 吗? - Scratte
@Scratte 是的,或者更一般地说是 outer.newInner(),其中 outerOuter 类型实例的任何引用。您不必为每个内部实例创建一个新的外部实例。 - user207421

-2

我已经说明了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);
                        }*/
                    //}
                }
    }

1
显然是代码部分。而且如果你没有注意到的话:你的代码示例非常难以阅读。即使在我巨大的台式电脑显示器上,我也看到了一个水平滚动条。考虑将您的注释放在它们所评论的事物之上或之下,而不是在其后面 - GhostCat
不确定我是否理解您对“同步”的使用。什么时候允许,什么时候不允许以及为什么?您的注释与代码显示的内容相矛盾。 - Scratte
“static inner” 是一个自相矛盾的说法。因此这里没有静态内部类。 - user207421
注释行说->“这很重要,我们必须在下面的非静态内部类中保持final和static修饰符”。因此没有提到静态内部类。 - Ashish Sharma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接