30根据官方教程详解嵌套类内部类静态嵌套类局部类匿名类 ...

Posted JavaLearnerZGQ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了30根据官方教程详解嵌套类内部类静态嵌套类局部类匿名类 ...相关的知识,希望对你有一定的参考价值。

文章目录

🌻 嵌套类、内部类、局部类等是 Java 面向对象中的难点,但好好研究清楚感觉也不是特别难。博主再次学习这部分内容,以次巩固知识。
🌻 博主其他介绍相关内容的文章:嵌套类、内部类、静态嵌套类…
🌻 博主以官方教程为基础开始学习,其中的概念都是以官方教程为主,这样学习起来比较放心。

一、嵌套类(Nested Classes)

(1) 嵌套类、内部类、静态嵌套类概念

✏️ The Java programming language allows you to define a class within another class. Such a class is called a nested class.
📜 Java 语言允许您在一个类中定义其他的类,这样的类叫做嵌套类
📜 嵌套类:定义在其他类中的类

public class OuterClass 
    class NestedClass 

    

    static class StaticNestedClass 
        
    

🌻 上面示例中的 NestedClass 类和 StaticNestedClass 类都是被定义在 OuterClass 类中的类
🌻 NestedClass 和 StaticNestedClass 是嵌套类


✏️ Nested classes are divided into two categories: non-static and static. ① Non-static nested classes are called inner classes. ② Nested classes that are declared static are called static nested classes.
📜 嵌套类被分为两种:静态的和非静态的
📜 【非静态嵌套类】非静态嵌套类没有被static关键字修饰,也叫做内部类
📜 【静态嵌套类】静态嵌套类被static关键字修饰

public class OuterClass 
    class InnerClass  // 内部类(非静态嵌套类)

    

    static class StaticNestedClass  // 静态嵌套类

    


📜 嵌套类外层的类叫做外部类(outer class)
📜 最外层的外部类叫做顶级类(Top-level Class)

public class A 
    class B 
        class C 

        
    

🌻 B 的外部类是 A
🌻 C 的外部类是 B 和 A
🌻 A 是 B 和 C 的顶级类


(2) 嵌套类的特点

✏️ A nested class is a member of its enclosing class(外部类). ① Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private. ❓ ② Static nested classes do not have access to other members of the enclosing class.❓ As a member of the OuterClass, a nested class can be declared private, public, protected, or package private. 【Recall(回想) that outer classes can only be declared public or package private.】
📜 嵌套类(内部类或静态嵌套类)属于它的外部类的成员。
📜 非静态嵌套类(内部类)可以访问它的外部类的所有成员(静态成员和实例成员),即使是private成员
📜 静态嵌套类无法直接访问外部类的实例成员(若想访问,需创建外部类实例)
📜 作为外部类的一个成员,嵌套类可以被 private、public、protected、package-private(没有修饰符) 等修饰

🌻 顶级类只能被 public 修饰,或没有访问修饰符

public class TopLevel 
    private static int six = 6;
    private int five = 5;

    static class StaticNested 
        class Hello 
            void test() 
                // 访问外部类(此处是顶级类)的静态成员
                System.out.println(six); // 6

                // 创建外部类实例后, 才可访问外部类的实例成员
                TopLevel topLevel = new TopLevel();
                System.out.println(topLevel.five); // 5
            
        
    


class TestMain 
    public static void main(String[] args) 
        // 创建一个静态嵌套类
        TopLevel.StaticNested staticNested = new TopLevel.StaticNested();
        // 通过静态嵌套类实例创建静态嵌套类里面的内部类实例
        TopLevel.StaticNested.Hello hello = staticNested.new Hello();
        // 6
        // 5
        hello.test();
    


(3) 何时使用嵌套类?

博主其他嵌套类的文章
✏️ ① 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.
📜 这是一种对仅在一个地方使用的类进行逻辑分组的方法: 如果一个类(如:A)仅仅在另一个类(如:B)中被使用,那么把它嵌套到另一个类中(把 A 嵌套到 B 中)是合乎逻辑的。嵌套这样的帮助类可以让程序包呈现流线型,更加高效。


✏️ ② 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.
📜 嵌套类增加了封装性: ① 考虑顶级类 A 和顶级类 B;② B 中需要访问 A 中被声明为private的成员;③ 通过把 B 隐藏在类 A 中(把 B 弄成 A 的嵌套类),A 的成员可以被声明为private,并且 B 可以访问到 A 中的私有成员。另外,B 类本身也可以不向外界暴露。

🌻 上图:A 类中定义的私有属性和私有方法无法被类 C 访问和调用;B 被嵌套到类 A 中,B 可以访问或调用类 A 中的私有属性和私有方法。


✏️ ③ 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.
📜 嵌套类可以使代码更具可读性和可维护性: 将类嵌套在顶级类中,能使代码更接近它被使用的位置。

二、内部类(Inner Classes)

✏️ As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object’s methods and fields. Also, because an inner class is associated with an instance, it cannot define any static members itself.
📜 与实例方法和实例变量一样,内部类与其外部类的实例相关联,并且可以直接访问该对象的方法和字段。此外,由于内部类与实例相关联,它本身不能定义任何静态成员。


public class OuterClass 
    class InnerClass 
         
    

✏️ An instance of InnerClass can exist only within an instance of OuterClass and has direct access to the methods and fields of its enclosing instance.
📜 InnerClass 的实例仅存在于 OuterClass 的实例中,InnerClass 的实例可以直接访问其外部类的方法和属性。

✏️ To instantiate an inner class, you must first instantiate the outer class.
📜 要创建内部类对象必须先创建外部类对象

下面是创建一个 InnerClass 对象的语法:

public class OuterClass 
    class InnerClass 
        void print() 
            System.out.println("print something");
        
    


class TestDemo 
    public static void main(String[] args) 
        // 先有外部类实例后, 才能创建内部类实例
        OuterClass outer = new OuterClass();

        // 通过外部类对象, 创建内部类对象
        OuterClass.InnerClass inner = outer.new InnerClass();
        // output: print something
        inner.print();
    


✏️ There are two special kinds of inner classes: local classes and anonymous classes.
📜 局部类和匿名类是两种特殊的内部类。

三、静态嵌套类

✏️ As with class methods and variables, a static nested class is associated with its outer class. And like static class methods, a static nested class cannot refer directly to instance variables or methods defined in its enclosing class: it can use them only through an object reference.
📜 与类方法和类变量一样,静态嵌套类与其外部类相关联。和类方法一样,静态嵌套类不能直接引用其外部类中定义的实例变量或方法(只能通过对象引用使用外部类的实例成员)


✏️ A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.
📜 静态嵌套类与其外部类的实例成员交互,就像与任何其他顶级类交互一样。实际上,静态嵌套类在行为上就是一个顶级类。只是为了方便打包,把它嵌套在另一个顶级类中而已。

✏️ You instantiate a static nested class the same way as a top-level class.
📜 就像实例化一个顶级类一样实例化静态嵌套类。

public class OuterClass 
    private static final int sixFive = 65;

    static class StaticNestedClass 
        void hundred() 
            System.out.println(sixFive + 35);
        
    


class TestDemo 
    public static void main(String[] args) 
        OuterClass.StaticNestedClass snc = new OuterClass.StaticNestedClass();
        // 100
        snc.hundred();
    

四、内部类、静态嵌套类官方案例

一个顶级类:

public class TopLevelClass 
    void accessMembers(OuterClass outer) 
        System.out.println(outer.outerField);
        System.out.println(OuterClass.staticOuterField);
    

public class OuterClass 
    String outerField = "1.Outer field";
    static String staticOuterField = "2.Static outer field";

    class InnerClass 
        void accessMembers() 
            System.out.println(outerField);
            System.out.println(staticOuterField);
        
    

    static class StaticNestedClass 
        void accessMembers(OuterClass outer) 
            System.out.println(outer.outerField);
            System.out.println(staticOuterField);
        
    

    public static void main(String[] args) 
        System.out.println("Inner class:");
        System.out.println("------------");
        OuterClass outerObject = new OuterClass();
        // 通过外部类实例创建内部类实例
        OuterClass.InnerClass innerObject = outerObject.new InnerClass();
        innerObject.accessMembers();

        System.out.println("\\nStatic nested class:");
        System.out.println("--------------------");
        // 创建静态嵌套类实例
        StaticNestedClass staticNestedObject = new StaticNestedClass();
        staticNestedObject.accessMembers(outerObject);

        System.out.println("\\nTop-level class:");
        System.out.println("--------------------");
        // 创建外部类实例
        TopLevelClass topLevelObject = new TopLevelClass();
        topLevelObject.accessMembers(outerObject);
    

五、匿名类和局部类

① 📖 类的五大成员:① 属性;② 方法;③ 构造器;④ 代码块;⑤ 嵌套类


② 📖 嵌套类的分类

✏️ There are two special kinds of inner classes: local classes and anonymous classes.
📜 局部类和匿名类是两种特殊的内部类。

(1) 局部类(Local Classes)

✏️ Local classes are classes that are defined in a block, which is a group of zero or more statements between balanced braces. You typically find local classes defined in the body of a method.
📜 代码块(block):在花括号中的零条或多条语句
📜 局部类是定义在代码块中的类
📜 通常您看到的局部类都是定义在方法体中的


✏️ You can define a local class inside any block. For example, you can define a local class in a method body, a for loop, or an if clause.
📜 您可以把局部类定义在任何代码块中(如方法体、for 循环、if 子句)


✏️ A local class has access to the members of its enclosing class.
📜 局部类可以直接访问它的外部类的所有成员(即使是 private 成员)


📜 局部类不能被访问修饰符(public、protected、private)修饰。局部类的地位就是一种局部变量。
📜 局部类可以被final关键字修饰(因为局部变量也可以用final修饰,被final修饰的局部类不能被其他局部类继承)


📜 局部类的作用域仅仅在定义它的代码块中

局部类例子:

public class OuterClass 
    private int five = 5;

    private void m() 
        System.out.println("OuterClass_m()");
    

    public void test() 
        /* LocalClass 是一个局部类(被定义在方法体中) */
        final class LocalClass 
            private void test() 
                System.out.println("LocalClass_five = " + five);
                m();
            
        

        // 创建一个局部类对象
        LocalClass localClass = new LocalClass();
        localClass.test();
    


class TestMain 
    public static void main(String[] args) 
        OuterClass outerClass = new OuterClass();
        
        // LocalClass_five = 5
        // OuterClass_m()
        outerClass.test();
    


📜 外部类和局部类的成员重名的时候遵循就近原则(若想访问外部类的成员:外部类类名.this.成员

public class OuterClass 
    private int num = 5;

    private void m() 
        System.out.println("OuterClass_m()");
    

    public void test() 
        class LocalClass 
            int num = 6;

            private void test() 
                System.out.println(num); // 6
                System.out.println(OuterClass.this.num); // 5
                m();
                OuterClass.this.m();
                // OuterClass.this 是调用方法的外部类的对象
            

            private void m() 
                System.out.println("LocalClass_m()");
            
        

        LocalClass localClass = new LocalClass();
        localClass.m();
        localClass.test();
    


class TestMain 
    public static void main(String[] args) 
        OuterClass outerClass = new OuterClass();

        // 1. LocalClass_m()
        // 2. 6
        // 3. 5
        // 4. LocalClass_m()
        // 5. OuterClass_m()
        outerClass.test();
    


✏️ a local class has access to local variables. However, a local class can only access local variables that are declared final. When a local class accesses a local variable or parameter of the enclosing block, it captures that variable or parameter.
📜 局部类可以访问局部变量。然而,局部类只能访问被声明为final的局部变量。当局部类访问了局部变量或参数的时候,局部类捕获了该局部变量或参数。

✏️ Starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final.
📜 从 jdk8 开始,局部类可以访问 final有效 final 的局部变量或参数。
📜 有效 final:假如一个变量或参数的值在被初始化后从来也没有被改变过,那么这个变量或参数就是有效 final

public class OuterClass 
    public void test(int v) 
        int n = 5; // n 是有效 final 的变量
        // n = 1; // n 不能第二次赋值, 否则就不是有效final

        // v = 2; // v 不能第二次赋值, 否则就不是有效final

        class LocalClass 
            private void m() 
                System.out.println(n + 6); // 11
                System.out.println(v + v); // 16
            
        

        LocalClass localClass = new LocalClass();
        localClass.m();
    


class TestMain 
    public static void main(String[] args) 
        OuterClass outerClass = new OuterClass();

        // 11
        // 16
        outerClass.test(8);
    

📜 局部类中不能定义任何的static成员(编译时常量除外)

(2) 匿名类(Anonymous Classes)

匿名类相关文章

✏️ Anonymous classes enable you to make your code more concise(简洁的). They enable you to declare and instantiate a class at the same time. They are like local classes except that they do not have a name. Use them if you need to use a local class only once.
📜 匿名类可以让您的代码更加简洁。匿名类可以让您在声明类的同时创建该类的一个实例。匿名类类似局部类,只是匿名类没有类名。如果您只需要使用一次局部类,您可以考虑使用匿名类。

📜 当接口或抽象类的实现类在整个项目中只使用过一次的时候,可以考虑使用匿名类(Anonymous Class)


① 基于接口的匿名类

看下面的代码,引出匿名类:

public class DemoMain 
    public static void main(String[] args) 

    


interface InterPhone 
    void playGame(String name);

🌻 在上面的代码中,有一个接口 InterPhone
🌻 若需要使用该接口,需要进行以下几步:① 写一个类实现(implements)该接口,并给予该接口中的抽象方法以具体实现;② 创建该类的实例;③ 通过该类的实例调用 playGame 方法【代码如下】

public class DemoMain 
    public static void main(String[] args) 
        // (2) 创建该类(ApplePhone)的实例
        ApplePhone applePhone = new ApplePhone();

        // (3) 通过该类的实例调用 playGame 方法
        // output: ApplePhone_playGame(String name)_王者荣耀
        applePhone.playGame("王者荣耀");
    


interface InterPhone 
    void playGame(String name);


/* (1) 写一个类实现(implements)该接口,并给予该接口中的抽象方法以具体实现 */
class ApplePhone implements InterPhone 
    @Override
    public void playGame(String name) 
        System.out.println("ApplePhone_playGame(String name)_" + name);
    


🌻 假如 ApplePhone 在整个项目过程中,只使用了一次,以后永远不会使用:可以通过匿名类完成 InterPhone 接口的使用,无需创建 ApplePhone 类【代码如下】

public class DemoMain 
    public static void main(String[] args) 
        /*
            applePhone 的编译类型是:InterPhone
            applePhone 的运行类型是:匿名类
            
            匿名类类名是:外部类类名$数字(如:DemoMain$1)
            数字是匿名类对象的编号
            
            new: 创建匿名类对象
         */
        InterPhone applePhone = new InterPhone() 
            @Override
            public void playGame(String name) 
                System.out.println("AnonymousClass_" + name);
            
        ;

        // 匿名类类名:class com.gq.DemoMain$1
        System.out.println(applePhone.getClass());

        // output: AnonymousClass_王者荣耀
        applePhone.playGame("王者荣耀");
    


interface InterPhone 
    void playGame(String name);

② 基于类的匿名类

非抽象类:

public class DemoTest 
    public static void main(String[] args) 
        /*
            c1 的运行类型是:class com.gq.Computer
         */
        Computer c1 = new Computer();
        System.out.println(c1.getClass());
        // Computer_open()
        c1.open()

Java基础教程(14)--嵌套类

??Java允许在一个类中定义另外一个类,这样的类被称为嵌套类,就像下面这样:

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

??嵌套类分为两种:静态的和非静态的。声明为static的嵌套类被称为静态嵌套类,非静态嵌套类则被称为内部类:

class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}

??嵌套类是其所在的外部类的成员。内部类可以访问外部类中的其他成员,即使这个成员被private修饰。静态嵌套类则没有访问外部类中其他成员的权限。作为外部类的一个成员,嵌套类可以被声明为private、public、protected或者包私有的。
??下面是几个为什么要使用嵌套的类原因:

  • 能够将仅在一个地方使用的类合理地组合。如果一个类可能只对于另外一个类有用,此时将前者组合到后者,可以使得程序包更加简洁。
  • 增强封装性。假如有两个类A和B,B类需要使用A类中的成员,而恰好该成员又是仅类内部可见(private)的,如果将B定义为A的嵌套类,则B可以使用A的任何成员,而且B也可以声明为外部不可见(private),将B隐藏起来。
  • 能够使代码可读性和维护性更强。嵌套的类代码相较于顶级类,更靠近它被使用的地方,方便查看。

一.静态嵌套类

??就像静态方法和静态变量一样,静态嵌套类是和外部类相关联的。和静态方法一样,静态嵌套类不能直接引用实例变量和实力方法,只能通过一个对象引用。实际上,可以将静态嵌套类看作是一个顶级类,只不过将其嵌套在其他类中方便打包。
??静态嵌套类可以用过外部类的名字去访问:

OuterClass.StaticNestedClass

??可以使用下面的语法为静态嵌套类创建对象:

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

二.内部类

??就像实例方法和实例变量一样,内部类与外部类的实例相关联并且可以直接访问外部类的方法和成员。并且,因为内部类与外部类的实例相关联,因此它内部不能定义静态成员。
??要实例化内部类,必须创建外部类的对象,然后使用这个对象去创建内部类的对象:

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

??实际上,还有两种特殊的内部类————局部类和匿名类。有关这两种类的内容将会在下文中介绍。强烈建议不要对内部类(包括局部类和匿名类)进行序列化(把对象转换为字节序列的过程称为对象的序列化,有关序列化的内容会在以后的文章中进行介绍)。

三.屏蔽现象

??如果一个类型(例如成员变量或参数)与外部作用域中的类型同名,那么内部作用域中的声明将会屏蔽外部作用域中的声明,这样就不能直接通过名称去访问外部作用域中同名的类型。如下例所示:

public class ShadowTest {
    public int x = 0;

    class FirstLevel {
        public int x = 1;

        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
        }
    }

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}

??这个例子的输出如下:

x = 23
this.x = 1
ShadowTest.this.x = 0

??这个例子中定义了三个名为x的变量,分别是ShadowTest类的成员变量,内部类FirstLevel的成员变量,以及方法methodInFirstLevel的参数。方法methodInFirstLevel的参数x屏蔽了内部类FirstLevel的成员变量x和ShadowTest类的成员变量x。因此,在表示内部类FirstLevel的成员变量x时,要像下面这样:

System.out.println("this.x = " + this.x);

??在表示ShadowTest类的成员变量x时,要像下面这样:

System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);

四.局部类

??局部类是在块(由大括号包围的零条或多条语句)中定义的类。经常会在方法体中见到局部类。下面是一个定义在方法中的局部类:

public class OuterClass {
    public void method() {
        ...
        class LocalClass {
            ...
        }
    }
}

??局部类可以访问外部类的成员。此外,局部类还可以访问局部变量。然而,局部类只能访问由final修饰的局部变量。当一个局部类访问一个块中的局部变量或参数时,它就捕获了这个变量或者参数。从Java8开始,局部类不但可以访问由final修饰的局部变量和参数,还可以访问近似final的局部变量和参数。近似final的意思是说这个变量或参数的值自从初始化之后就没有修改过。此外,局部类中的变量也会屏蔽定义在外部的同名变量或参数。
??局部类中基本不能定义静态成员。不过也有例外,可以在局部类中定义静态常变量(常变量是指类型为基本数据类型或者String,被声明为final,并且使用编译时常量表达式进行初始化的变量。编译时常量表达式通常是可以在编译时计算的字符串或算术表达式)。
??定义在静态方法中的局部类,只能引用外部类的静态成员。不能在块中定义接口,因为接口是天生静态的。也不能在局部类中定义静态初始化器或者接口。

五.匿名类

??匿名类让代码看上去更加简洁,它能让你同时声明和实例化一个类。它们类似于局部类,只不过匿名类没有名称。如果某个局部类只使用一次,可以将它定义为匿名类。
??局部类是类的声明,而匿名类则是表达式,这意味着匿名类是在一个表达式中定义的。匿名类表达式的语法就像是调用构造器的语法,只不过构造器后面跟的是类的定义。就像下面这样:

HelloWorldInterface frenchGreeting = new HelloWorldInterface() {
    String name = "tout le monde";
    public void greet() {
        greetSomeone("tout le monde");
    }
    public void greetSomeone(String someone) {
        name = someone;
        System.out.println("Salut " + name);
    }
};

??匿名类的语法包含以下几部分:

  • new操作符;
  • 匿名类实现的接口或者继承的类;
  • 包含了构造器参数的小括号。注意,当匿名类实现了某个接口时,由于接口没有构造器,因此使用一个空的小括号来表示;
  • 匿名类的定义体。

??就像局部类一样,匿名类也可以捕获变量。下面是几条规则:

  • 匿名类可以访问它的外部类的成员;
  • 匿名类不能访问外部范围中没有使用final修饰或不是近似final的局部变量。
  • 匿名类中会屏蔽外部范围中同名的类型。

??匿名类在成员的定义上和局部类有相同的规则:

  • 不能在匿名类中声明静态初始化器或成员接口;
  • 匿名类中可以有静态成员,前提是这个静态成员必须是常变量。

??可以在匿名类中声明以下元素:

  • 域;
  • 额外的方法(接口中没有定义的方法);
  • 非静态初始化块;
  • 局部类。

??不能在匿名类中定义构造方法。







以上是关于30根据官方教程详解嵌套类内部类静态嵌套类局部类匿名类 ...的主要内容,如果未能解决你的问题,请参考以下文章

Java | 内部类(Inner Class)

java嵌套类和内部类详解

内部类(嵌套类)

Java嵌套类,内部类和外部类

Java | 嵌套类(Nested Class)

Java基础教程(14)--嵌套类