Java基础知识(11)- Java 面向对象(三)| 内部类 (Inner)、封装 (Encapsulation)


1. 内部类 (Inner)

    在类内部可定义属性和方法,且在类内部也可以定义另一个类。如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)。

    内部类是一个独立的类,在编译之后内部类会被编译成独立的 .class 文件,但是前面冠以外部类的类名和 $ 符号。

    内部类分类:成员内部类(实例内部类)、静态内部类、局部内部类、匿名内部类


    1) 成员内部类(或实例内部类)       

        (1) 在成员内部类中,不能定义 static 成员,除了静态常量(final static 修饰的变量);
        (2) 在成员内部类中,可以访问外部类的所有成员;
        (3) 在外部类中,不能直接访问内部类的成员变量和方法,必须通过内部类的实例来进行访问;
        (4) 在外部类的静态方法中(或其他类中),必须通过外部类的实例创建内部类的实例来进行访问;      
        (5) 外部类实例与内部类实例是一对多的关系,也就是说一个内部类实例只对应一个外部类实例,而一个外部类实例则可以对应多个内部类实例;     

        实例:

复制代码
 1     class Outer {
 2 
 3         int a = 1;
 4         final String outerFinalMsg = "Outer final message";
 5         static String outerStaticMsg = "Outer static message";
 6 
 7         public String getFinalMessage() {
 8 
 9             Inner inner = new Inner();  // 不需要创建外部类实例
10             return inner.innerStaticMsg;
11         }
12 
13         public static String getStaticMessage() {
14             Inner inner = new Outer().new Inner(); // 需要创建外部类实例
15             return inner.innerStaticMsg;
16         }
17 
18         // 成员内部类
19         class Inner {
20             private String name;
21             // 不能定义 static 成员变量,除了 final static 修饰
22             final static String innerStaticMsg = "Inner static message";
23 
24             public Inner() {}
25 
26             public Inner(String name) {
27                 this.name = name;
28             }
29 
30             void display() {
31 
32                 // 直接访问外部类的成员
33                 System.out.println("Inner(" + this.name + "): (a+1) = " + (a+1));
34                 System.out.println("Inner(" + this.name + "): outerFinalMsg = " + outerFinalMsg);
35                 System.out.println("Inner(" + this.name + "): outerStaticMsg = " + outerStaticMsg);
36                 System.out.println("Inner(" + this.name + "): getFinalMessage() = " + getFinalMessage());
37                 System.out.println("Inner(" + this.name + "): getStaticMessage() = " + getStaticMessage());
38             }
39 
40             // 不能定义 static 方法
41             //static void show() {}
42         }
43 
44         Inner obj3 = new Inner("Object 3"); // 不需要创建外部类实例
45 
46     }
47 
48     public class App {
49         public static void main( String[] args ) {
50 
51             // 方法1:先创建外部类对象,再创建内部类对象
52             Outer outer = new Outer();
53             Outer.Inner obj1 = outer.new Inner("Object 1");
54             obj1.display();
55 
56             // 方法2:同时创建外部类和内部类对象,只保存内部类对象引用
57             Outer.Inner obj2 = new Outer().new Inner("Object 2");
58             obj2.display();
59 
60             // obj3 作为外部类的成员变量
61             outer.obj3.display();
62         }
63     }
复制代码

        输出:

            Inner(Object 1): (a+1) = 2
            Inner(Object 1): outerFinalMsg = Outer final message
            Inner(Object 1): outerStaticMsg = Outer static message
            Inner(Object 1): getFinalMessage() = Inner static message
            Inner(Object 1): getStaticMessage() = Inner static message
            Inner(Object 2): (a+1) = 2
            Inner(Object 2): outerFinalMsg = Outer final message
            Inner(Object 2): outerStaticMsg = Outer static message
            Inner(Object 2): getFinalMessage() = Inner static message
            Inner(Object 2): getStaticMessage() = Inner static message
            Inner(Object 3): (a+1) = 2
            Inner(Object 3): outerFinalMsg = Outer final message
            Inner(Object 3): outerStaticMsg = Outer static message
            Inner(Object 3): getFinalMessage() = Inner static message
            Inner(Object 3): getStaticMessage() = Inner static message


    2) 静态内部类

        静态内部类是指使用 static 修饰的内部类。

        (1) 创建静态内部类的实例,不需要创建外部类的实例;
        (2) 在静态内部类中,可以定义静态成员(静态变量和静态方法)和实例成员(成员变量和方法);
        (3) 在静态内部类中,可以直接访问外部类的静态成员;
        (4) 在静态内部类中,访问外部类的实例成员,需要通过外部类的实例去访问;
        (5) 外部类以外的其他类,需要通过完整的类名访问静态内部类中的静态成员;
        (6) 访问静态内部类中的实例成员,则需要通过静态内部类的实例;

        实例:

复制代码
 1     class Outer2 {
 2 
 3         int b = 2;
 4         final String outer2FinalMsg = "Outer2 final message";
 5         static String outer2StaticMsg = "Outer2 static message";
 6 
 7         public String getFinalMessage() {
 8             // 直接访问静态内部类 static 成员
 9             return StaticInner.staticLabel;
10         }
11 
12         public static String getStaticMessage() {
13             // 直接访问静态内部类 static 成员
14             return StaticInner.staticLabel;
15         }
16 
17         // 静态内部类
18         static class StaticInner {
19             int x = 100;
20             static String staticLabel = "StaticInner Label";
21 
22             void display() {
23 
24                 // 访问外部类实例成员,需要通过外部类的实例去访问
25                 Outer2 outer2 = new Outer2();
26                 System.out.println("StaticInner: (outer2.b + 1) = " + (outer2.b+1));
27                 System.out.println("StaticInner: outer2.outer2FinalMsg = " + outer2.outer2FinalMsg);
28                 System.out.println("StaticInner: outer2.getFinalMessage() = " + outer2.getFinalMessage());
29 
30                 // 直接访问外部类 static 成员
31                 System.out.println("StaticInner: outer2StaticMsg = " + outer2StaticMsg);
32                 System.out.println("StaticInner: getStaticMessage() = " + getStaticMessage());
33             }
34 
35             static void staticDisplay(String str) {
36                 System.out.println("StaticInner: " + str);
37             }
38         }
39     }
40 
41     public class App {
42         public static void main( String[] args ) {
43             // display() 是静态内部类的实例方法,所以需要 new 一个静态内部类实例对象
44             Outer2.StaticInner staticInnerObj = new Outer2.StaticInner();
45             staticInnerObj.display();
46             //
47             staticInnerObj.staticDisplay("staticInnerObj.x: " + staticInnerObj.x);
48             staticInnerObj.staticDisplay("staticInnerObj.label: " + staticInnerObj.staticLabel);
49 
50             // 不需要创建外部类实例,可以直接访问静态内部类的静态成员
51             Outer2.StaticInner.staticDisplay("Outer2.StaticInner.staticLabel: " + Outer2.StaticInner.staticLabel);
52         }
53    }
复制代码

        输出:

            StaticInner: (outer2.b + 1) = 3
            StaticInner: outer2.outer2FinalMsg = Outer2 final message
            StaticInner: outer2.getFinalMessage() = StaticInner Label
            StaticInner: outer2StaticMsg = Outer2 static message
            StaticInner: getStaticMessage() = StaticInner Label
            StaticInner: staticInnerObj.x: 100
            StaticInner: staticInnerObj.label: StaticInner Label
            StaticInner: App.InnerStaticClass.staticLabel: StaticInner Label


    3) 局部内部类

        (1) 局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰;
        (2) 局部内部类只在当前方法中有效;
        (3) 局部内部类中不能定义 static 变量和方法;
        (4) 局部内部类中还可以包含内部类,但是这些内部类也不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰;
        (5) 在局部内部类中可以访问外部类的所有成员;
        (6) 在局部内部类中只可以访问当前方法中 final 类型的参数与变量。如果方法中的成员与外部类中的成员同名,则可以使用 <OuterClassName>.this.<MemberName> 的形式访问外部类中的成员;

        实例:

复制代码
 1     class Outer3 {
 2 
 3         int c = 3;
 4         static int d = 4;
 5         final String outer3FinalMsg = "Outer3 final message";
 6         static String outer3StaticMsg = "Outer3 static message";
 7 
 8         public String getFinalMessage() {
 9             return outer3FinalMsg;
10         }
11 
12         public static String getStaticMessage() {
13             return outer3StaticMsg;
14         }
15 
16         public void testLocalInner() {
17             final int y = 777;
18             int z = 999;
19 
20             // 局部内部类
21             class LocalInner {
22 
23                 // 不能定义 static 变量和方法
24                 //static int i = 9;
25                 //static void test() {}
26 
27                 // 可以直接访问外部类的所有成员
28                 void display() {
29                     // 访问外部类成员变量和方法
30                     System.out.println("LocalInner: (c+1) = " + (c+1));
31                     System.out.println("LocalInner: getFinalMessage() = " + getFinalMessage());
32                     // 访问部类 static 变量和方法
33                     System.out.println("LocalInner: (d+1) = " + (d+1));
34                     System.out.println("LocalInner: getStaticMessage() = " + getStaticMessage());
35 
36                     // 只可以访问当前方法中 final 类型的参数与变量
37                     System.out.println("LocalInner: y = " + y);
38                     //System.out.println("LocalInner: z =" + z);
39                 }
40             }
41             LocalInner localInner = new LocalInner();
42             localInner.display();
43         }
44     }
45 
46     public class App {
47         public static void main( String[] args ) {
48             Outer3 outer3 = new Outer3();
49             outer3.testLocalInner();
50         }
51     }
复制代码

        输出:

            LocalInner: (c+1) = 4
            LocalInner: getFinalMessage() = Outer3 final message
            LocalInner: (d+1) = 5
            LocalInner: getStaticMessage() = Outer3 static message
            LocalInner: y = 777

    4) 匿名内部类

        匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类。

        匿名类有两种实现方式:

            (1) 继承一个类,重写其方法。
            (2) 实现一个接口(可以是多个),实现其方法。

        匿名类的特点:

            (1) 匿名类和局部内部类一样,可以访问外部类的所有成员。如果匿名类位于一个方法中,则匿名类只能访问方法中 final 类型的局部变量和参数;
            (2) 匿名类中允许使用非静态代码块进行成员初始化操作;
            (3) 匿名类的非静态代码块会在父类的构造方法之后被执行;

        
        实例

复制代码
 1 class Outer4 {
 2         void display() {
 3             System.out.println("Outer4 -> display()");
 4         }
 5     }
 6 
 7     public class App {
 8 
 9         static int f = 6;
10         static String staticMsg = "Anonymous static message";
11 
12         public static String getStaticMessage() {
13             return staticMsg;
14         }
15 
16         public static void main( String[] args ) {
17             final int e = 5;
18             final String finalMsg = "Anonymous final message";
19             Outer4 outer4 = new Outer4() {
20                 void display() {
21 
22                     // 访问外部方法 final 变量
23                     System.out.println("Anonymous(outer4): (e+1) = " + (e+1));
24                     System.out.println("Anonymous(outer4): finalMsg = " + finalMsg);
25 
26                     // 访问外部类 static 方法和变量
27                     System.out.println("Anonymous(outer4): (f+1) = " + (f+1));
28                     System.out.println("Anonymous(outer4): getStaticMessage() = " + getStaticMessage());
29                 }
30             };
31             outer4.display();
32 
33         }
34     }
复制代码

        输出:

            Anonymous(outer4): (e+1) = 6
            Anonymous(outer4): finalMsg = Anonymous final message
            Anonymous(outer4): (f+1) = 7
            Anonymous(outer4): getStaticMessage() = Anonymous static message

2. 封装 (Encapsulation)

    封装是将类的某些信息隐藏在类内部,不允许外部程序直接访问,只能通过该类提供的方法来实现对隐藏信息的操作和访问。
    
    要访问该类的代码和数据,必须通过严格的接口控制。封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。

    适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。

    封装的优点:
        1) 良好的封装能够减少耦合。
        2) 类内部的结构可以自由修改。
        3) 可以对成员变量进行更精确的控制。
        4) 隐藏信息,实现细节。

    实现封装的具体步骤如下:
        1) 修改属性的可见性来限制对属性的访问,一般设为 private。
        2) 为每个属性创建一对赋值(setter)方法和取值(getter)方法,一般设为 public,用于属性的读写。
        3) 在赋值和取值方法中,加入属性控制语句(对属性值的合法性进行判断)。


    实例:

复制代码
 1        class User {
 2         private String name;    // 姓名
 3         private int age;        // 年龄
 4         private String phone;   // 联系电话
 5         private String address; // 家庭住址
 6 
 7         public String getName() {
 8             return name;
 9         }
10 
11         public void setName(String name) {
12             this.name = name;
13         }
14 
15         public int getAge() {
16             return age;
17         }
18 
19         public void setAge(int age) {
20             // 对年龄进行限制
21             if (age < 18 || age > 65) {
22                 System.out.println("年龄必须在 18 到 65之间!");
23                 this.age = 35; // 默认年龄
24             } else {
25                 this.age = age;
26             }
27         }
28 
29         public String getPhone() {
30             return phone;
31         }
32 
33         public void setPhone(String phone) {
34             this.phone = phone;
35         }
36 
37         public String getAddress() {
38             return address;
39         }
40 
41         public void setAddress(String address) {
42             this.address = address;
43         }
44 
45     }
46 
47     public class App {
48         public static void main( String[] args ) {
49 
50             User user = new User();
51             user.setName("Tester");
52             user.setAge(32);
53             user.setPhone("1234567879");
54             user.setAddress("Home address ...");
55             System.out.println("Name: " + user.getName());
56             System.out.println("Age: " + user.getAge());
57             System.out.println("Phone: " + user.getPhone());
58             System.out.println("Address: " + user.getAddress());
59 
60         }
61     }
复制代码

    输出:

        Name: Tester
        Age: 32
        Phone: 1234567879
        Address: Home address ...

posted @   垄山小站  阅读(327)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
点击右上角即可分享
微信分享提示