《On Java 8》读书笔记007_封装

https://github.com/LingCoder/OnJava8

1、封装

Java 提供了访问修饰符(access specifier)供类库开发者指明哪些对于客户端程序员是可用的,哪些是不可用的。访问控制权限的等级,从“最大权限”到“最小权限”依次是:public,protected,包访问权限(package access)(没有关键字)和 private。

2、包的概念

包内包含一组类,它们被组织在一个单独的命名空间(namespace)下。
一个 Java 源代码文件称为一个编译单元(compilation unit)(有时也称翻译单元(translation unit))。每个编译单元的文件名后缀必须是 .java。在编译单元中可以有一个 public 类,它的类名必须与文件名相同(包括大小写,但不包括后缀名 .java)。每个编译单元中只能有一个 public 类,否则编译器不接受。如果这个编译单元中还有其他类,那么在包之外是无法访问到这些类的,因为它们不是 public 类,此时它们为主 public 类提供“支持”类 。

3、代码组织

当编译一个 .java 文件时,.java 文件的每个类都会有一个输出文件。每个输出的文件名和 .java 文件中每个类的类名相同,只是后缀名是 .class。因此,在编译少量的 .java 文件后,会得到大量的 .class 文件。如果你使用过编译型语言,那么你可能习惯编译后产生一个中间文件(通常称为“obj”文件),然后与使用链接器(创建可执行文件)或类库生成器(创建类库)产生的其他同类文件打包到一起的情况。这不是 Java 工作的方式。在 Java 中,可运行程序是一组 .class 文件,它们可以打包压缩成一个 Java 文档文件(JAR,使用 jar 文档生成器)。Java 解释器负责查找、加载和解释这些文件。
类库是一组类文件。每个源文件通常都含有一个 public 类和任意数量的非 public 类,因此每个文件都有一个 public 组件。如果把这些组件集中在一起,就需要使用关键字 package。

如果你使用了 package 语句,它必须是文件中除了注释之外的第一行代码。当你如下这样写:

package hiding;

意味着这个编译单元是一个名为 hiding 类库的一部分。换句话说,你正在声明的编译单元中的 public 类名称位于名为 hiding 的保护伞下。任何人想要使用该名称,必须指明完整的类名或者使用 import 关键字导入 hiding 。(注意,Java 包名按惯例一律小写,即使中间的单词也需要小写,与驼峰命名不同)

4、创建独一无二的包名

你可能注意到,一个包从未真正被打包成单一的文件,它可以由很多 .class 文件构成,因而事情就变得有点复杂了。为了避免这种情况,一种合乎逻辑的做法是将特定包下的所有 .class 文件都放在一个目录下。也就是说,利用操作系统的文件结构的层次性。

5、冲突

如果通过 * 导入了两个包含相同名字类名的类库,会发生什么?例如,假设程序如下:

import com.mindviewinc.simple.*;
import java.util.*;

因为 java.util.* 也包含了 Vector 类,这就存在潜在的冲突。但是只要你不写导致冲突的代码,就不会有问题——这样很好,否则就得做很多类型检查工作来防止那些根本不会出现的冲突。

现在如果要创建一个 Vector 类,就会出现冲突:

Vector v = new Vector();

这里的 Vector 类指的是谁呢?编译器不知道,读者也不知道。所以编译器报错,强制你明确指明。对于标准的 Java 类 Vector,你可以这么写:

java.util.Vector v = new java.util.Vector();

这种写法完全指明了 Vector 类的位置(配合 CLASSPATH),那么就没有必要写 import java.util.* 语句,除非使用其他来自 java.util 中的类。

或者,可以导入单个类以防冲突——只要不在同一个程序中使用有冲突的名字(若使用了有冲突的名字,必须明确指明全名)。

6、访问权限修饰符

6.1、包访问权限

本章之前的所有示例要么使用 public 访问修饰符,要么就没使用修饰符(默认访问权限(default access))。默认访问权限没有关键字,通常被称为包访问权限(package access)(有时也称为 friendly)。这意味着当前包中的所有其他类都可以访问那个成员。对于这个包之外的类,这个成员看上去是 private 的。由于一个编译单元(即一个文件)只能隶属于一个包,所以通过包访问权限,位于同一编译单元中的所有类彼此之间都是可访问的。

6.2、private访问权限:你无法访问

// hiding/IceCream.java
// Demonstrates "private" keyword

class Sundae {
    private Sundae() {}
    static Sundae makeASundae() {
        return new Sundae();
    }
}

public class IceCream {
    public static void main(String[] args) {
        //- Sundae x = new Sundae();
        Sundae x = Sundae.makeASundae();
    }
}

以上展示了 private 的用武之地:控制如何创建对象,防止别人直接访问某个特定的构造器(或全部构造器)。例子中,你无法通过构造器创建一个 Sundae 对象,而必须调用 makeASundae() 方法创建对象。

6.3、protect访问权限:继承访问权限

有时,基类的创建者会希望某个特定成员能被继承类访问,但不能被其他类访问。这时就需要使用 protected。protected 也提供包访问权限,也就是说,相同包内的其他类可以访问 protected 元素。

7、类访问权限

// hiding/Lunch.java
// Demonstrates class access specifiers. Make a class
// effectively private with private constructors:

class Soup1 {
    private Soup1() {}

    public static Soup1 makeSoup() { // [1]
        return new Soup1();
    }
}

class Soup2 {
    private Soup2() {}

    private static Soup2 ps1 = new Soup2(); // [2]

    public static Soup2 access() {
        return ps1;
    }

    public void f() {}
}
// Only one public class allowed per file:
public class Lunch {
    void testPrivate() {
        // Can't do this! Private constructor:
        //- Soup1 soup = new Soup1();
    }

    void testStatic() {
        Soup1 soup = Soup1.makeSoup();
    }

    void testSingleton() {
        Soup2.access().f();
    }
}

Soup1 和 Soup2 展示了如何通过将你所有的构造器声明为 private 的方式防止直接创建某个类的对象。记住,如果你不显式地创建构造器,编译器会自动为你创建一个无参构造器(没有参数的构造器)。如果我们编写了无参构造器,那么编译器就不会自动创建构造器了。将构造器声明为 private,那么谁也无法创建该类的对象了。但是现在别人该怎么使用这个类呢?上述例子给出了两个选择。在 Soup1 中,有一个 static 方法,它的作用是创建一个新的 Soup1 对象并返回对象的引用。如果想要在返回引用之前在 Soup1 上做一些额外操作,或是记录创建了多少个 Soup1 对象(可以用来限制数量),这种做法是有用的。

Soup2 用到了所谓的设计模式(design pattern)。这种模式叫做单例模式(singleton),因为它只允许创建类的一个对象。Soup2 类的对象是作为 Soup2 的 static private 成员而创建的,所以有且只有一个,你只能通过 public 修饰的 access() 方法访问到这个对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值