Java 封装(内部类)

时间:2021-05-15 15:46:11

1、封装

封装是指,一种将抽象性函式接口的实例细节部份包装、隐藏起来的方法。封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据,必须通过严格的接口控制,通过该类提供的方法来实现对隐藏信息的操作和访问。

  • 封装好处

    • 只能通过规定的方法访问数据。
    • 隐藏类的实例细节,方便修改和实现。
  • 实现封装

    • 修改属性的可见性,在属性的前面添加访问控制修饰符。
    • 对每个值属性提供对外的公共方法访问,如创建 getter/setter(取值和赋值) 方法,用于对私有属性的访问。
    • 在 getter/setter 方法里加入属性的控制语句,例如我们可以加一个判断语句,对于非法输入给予否定。

    • 注意不要编写返回引用可变对象的访问器方法。如果需要返回一个可变对象的引用,应该首先对它进行克隆(clone)。对象克隆是指存放在另一个位置上的对象副本。更多参见:详解 Java clone 方法

2、包

为了避免类重名带来的问题,Java 提供了包机制,用于区别类名的命名空间。

  • 包的作用

    • 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
    • 包采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。
    • 包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
  • 定义语法

    package 包名

3、访问修饰符

访问(控制)修饰符可以用来修饰属性和方法的访问范围。
Java 封装(内部类)

  • 可以在任何另外一个类中,使用public类创建对象。
  • 如果一个类不加 public 修饰,则称这样的类为友好类,在同一个包中的其他类可以使用友好类创建对象。
  • 不能使用 protected 和 private 修饰类。

4、this 关键字

this关键字代表当前对象。当我们封装对象属性的时候,经常会使用this关键字。
举例来说,在Eclipse中可以自动帮我们定义私有属性的getter和setter方法:

Java 封装(内部类)

Java 封装(内部类)

当系统帮我们创建好了getter和setter方法后,我们会发现系统创建的方法中参数名和我们的属性名一样。为了解决成员变量和局部变量之间发生的同名的冲突,我们在属性名前面添加了this关键字。

public void setAge(int age) {
this.age = age;
}
  • 注一:this 关键字不能出现在类方法中。
  • 注二:如果构造器的第一个语句形如this(...),这个构造器将调用同一个类的另一个构造器。

5、内部类

可以将一个类的定义放在另一个类的定义内部,这就是内部类。而包含内部类的类被称为外部类。

  • 主要作用

    1. 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
    2. 内部类的方法可以直接访问外部类的所有数据,包括私有的数据
    3. 内部类所实现的功能使用外部类同样可以实现,只是有时使用内部类更方便。
    4. 内部类允许继承多个非接口类型。
    5. 内部类的类体中不可以声明类变量和类方法。

    注:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。所以内部类的成员变量/方法名可以和外部类的相同

  • 详细分类

  1. 成员内部类

    相当于所在外部类的一个成员变量,可以使用任意访问修饰符。内部类里可以直接访问外部类的方法和属性。如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,可以使用 this 关键字。定义成员内部类后必须使用外部类对象来创建内部类对象,即:

      内部类 对象名 = 外部类对象.new 内部类();

    所以成员内部类不能含有static的变量和方法,因为成员内部类需要先创建了外部类,才能创建它自己的。

  2. 静态内部类

    静态内部类是 static 修饰的内部类,通常被称为嵌套类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问。如果外部类的静态成员与内部类的成员名称相同,可通过类名.静态成员访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过成员名直接调用外部类的静态成员。嵌套类和普通的内部类还有一个区别:普通内部类不能有static数据和static属性,也不能包含嵌套类,但嵌套类可以。而嵌套类不能声明为private,一般声明为public,方便调用。创建静态内部类的对象时不需要外部类的对象可以直接创建:

      内部类 对象名 = new 内部类();
  3. 局部内部类

    局部内部类,是指内部类定义在方法和作用域内。局部内部类也像别的类一样进行编译,但只是作用域不同而已。不能使用public或private访问说明符进行声明。局部类的方法只能引用定义为final的局部变量。

  4. 匿名内部类

    • 当使用类创建对象时,程序允许把类体与对象的创建组合在一起。也就是说。类创建对象时,除了构造方法还有类体,此类体被认为是该类的一个子类去掉类声明后的类体,称为匿名类。匿名类就是一个子类,由于无名可用,不能用来声明对象,但是却可以直接用匿名类创建对象
    • 使用匿名类时,必然是在某个类中直接用匿名类创建对象,因此匿名类一定是内部类。因为没有名字,不能重用,通常用来简化代码。使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口。匿名内部类是不能加访问修饰符的。当所在的方法的形参需要在内部类里面使用时,该形参必须为final。要注意的是,new 匿名类,这个类是要先定义的。
    • 尽管匿名类创建的对象没有经过类声明步骤,但匿名类对象的引用必须传递给一个匹配的参数,匿名类的主要用途就是向方法的参数传值。

      //假设f(B x)是一个方法
      void f(B x) {
      //x调用B中的方法
      }
      //其中参数是B类对象,那么在调用方法f时可以向其参数x传递一个匿名对象,如
      f (new B() {
      //匿名类的类体
      }
      );
    • 此外还有一种和接口相关的匿名类。类似的,Java 允许直接用接口名和一个类体创建一个匿名对象。如果某个方法的参数是接口类型,那么可以使用接口名和类体组合创建一个匿名对象传递给方法的参数,类体必须要实现接口中的全部方法。

参考资料

  • 实验楼:Java编程语言(新版)
  • Java核心技术 卷Ⅰ基础知识 原书第8版
  • Java2实用教程 (第三版)_ 耿祥义,张跃平