[读书笔记]Java编程思想第6章之访问权限控制
Posted Spring-_-Bear
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[读书笔记]Java编程思想第6章之访问权限控制相关的知识,希望对你有一定的参考价值。
- 当编写一个Java源代码文件时,此文件通常被称为编译单元。每一个编译单元都必须有一个后缀名.java,而在编译单元内有一个public类,该类的名称必须与文件的名称相同。
- Java可运行程序是一组可以打包并压缩为一个Java文档文件(JAR,使用Java的jar文档生成器)的.class文件。Java解释器负责这些文件的查找、装载和解释。
- Java包的名称命名规则全部使用小写字母。
- 既然构造器是唯一定义的构造器,并且它是private的,那么它将阻止对此类的继承。
package thinkinjava.charpenter6;
/**
* @author Spring-_-Bear
* @version 2021/9/24 16:24
*/
public class IceCream {
public static void main(String[] args) {
// ! Sundae x = new Sundae();
Sundae x = Sundae.makeASundae();
}
}
class Sundae{
private Sundae(){
System.out.println("Sundae();");
}
static Sundae makeASundae(){
return new Sundae();
}
}
- 虽然不是很常用,但编译单元内完全不带public类也是可能的。在这种情况下,可以随意对文件命名。
- 类既不可以是private的(这样会使得处该类之外,任何其他类都不可以访问它),也不可以是protected的。所以对于类的访问权限,仅有两个选择:包访问权限或public。如果不希望其它任何人对该类拥有访问权限,可以把所有的构造器都指定为private,从而阻止任何人创建该类的对象,但有一个例外,就是你在该类的static成员内部可以创建。注意:一个内部类可以是private或是protected的,但那是一个特例。
package thinkinjava.charpenter6;
/**
* @author Spring-_-Bear
* @version 2021/9/24 16:42
*/
public class Lunch {
public static void main(String[] args) {
Soup1.makeSoup();
Soup2.access();
}
}
class Soup1 {
/* Allow creation via static method */
private Soup1() {
System.out.println("Soup1();");
}
public static Soup1 makeSoup() {
return new Soup1();
}
}
class Soup2 {
/* Allow creation via a static object and return a reference */
private Soup2() {
System.out.println("Soup2();");
}
private static Soup2 ps1 = new Soup2();
public static Soup2 access() {
return ps1;
}
}
以上的例子给出了两种选择:在Soup1中,创建一个static方法,它创建了一个新的Soup1对象并返回一个对它的引用。如果想要在返回引用之前在Soup1上做一些额外的工作,或是如果想要记录到底创建了多少个Soup1对象(可能要限制其数量);Soup2类的对象是作为Soup2的一个static privaate成员而创建的,所以有且仅有一个,而且只能通过access()方法访问到它。
练习1: 在某个包中创建一个类,在这个类所处的包的外部创建该类的一个实例。
/* In another directory:
* /access/mypackage/MyPackagedClass.java
* The most important thing is to add environment variables to the operating system.
* package access.mypackage;
*
* public class MyPackagedClass {
* public MyPackagedClass() {System.out.println("MyPackagedClass()");}
* }
*/
public class UnpackagedMyClass {
public static void main(String[] args) {
access.mypackage.MyPackagedClass m = new access.mypackage.MyPackagedClass();
}
}
练习2: 将本节中的代码片段改写为完整的程序,并校验实际所发生的冲突。
import net.mindview.simple.*;
import java.util.*;
public class Collision {
public static void main(String[] args) {
// Vector v = new Vector(); // ambiquous collision
net.mindview.simple.Vector v1 = new net.mindview.simple.Vector();
java.util.Vector v2 = new java.util.Vector();
}
}
练习3: 创建两个包:debug和debugoff,它们都包含一个相同的类,该类有一个debug()方法。第一个版本显示发送给控制台的String参数,而第二个版本什么也不做。使用静态import语句将该类导入到一个测试程序中,并示范条件编译效果。
/* In directory access/debugoff:
* // access/debugoff/Debug.java
* package access.debugoff;
*
* public class Debug {
* public static void debug(String s) { }
* }
*/
package access.debug;
public class Debug {
public static void debug(String s) {
System.out.println(s);
}
}
练习4: 展示protected方法具有包访问权限,但是它仍旧不是public的。
package access.cookie2;
public class CookieMonster {
public static void main(String[] args) {
Cookie x = new Cookie();
x.bite(); // package access to protected method
}
}
import access.cookie2.*;
public class CookieThief {
public static void main(String[] args) {
Cookie x = new Cookie();
//! x.bite(); // access protected
}
}
练习5: 创建一个带有public,private,protected和包访问权限域以及方法成员的类。创建该类的一个对象,看看在你试图调用所有类成员时,会得到什么类型的编译信息。请注意,处于同一个目录中的所有类都是默认包的一部分。
/* in same directory:
* package access;
*
* public class FourWays {
* int a = 0;
* public int b = 1;
* protected int c = 2;
* private int d = 3;
* FourWays() { System.out.println("FourWays() constructor"); }
* void showa() { System.out.println(a); }
* public void showb() { System.out.println(b); }
* protected void showc() { System.out.println(c); }
* private void showd() { System.out.println(d); }
* }
*/
package access;
public class AccessTest {
public static void main(String[] args) {
FourWays fw = new FourWays();
fw.showa();
fw.showb();
fw.showc();
fw.a = 10;
fw.b = 20;
fw.c = 30;
fw.showa();
fw.showb();
fw.showc();
//! fw.showd(); // private access, compiler can't touch
}
}
练习6: 创建一个带有protected数据的类。运用第一个类中处理protected数据的方法在相同的文件中创建第二个类。
class SomeData {
protected int a = 13;
}
class DataChanger {
static void change(SomeData sd, int i) { sd.a = i; }
}
public class ProtectedData {
public static void main(String[] args) {
SomeData x = new SomeData();
System.out.println(x.a);
DataChanger.change(x, 99);
System.out.println(x.a);
}
}
练习7: 根据描述access和Widget的代码片段创建类库。在某个不属于access类库的类中创建一个Widget实例。
/* in access package:
* // access/Widget.java
* package access;
*
* public class Widget {
* public Widget() { System.out.println("Widget()"); }
* }
*/
import access.*;
public class MakeWidget {
public static void main(String[] args) {
Widget w = new Widget();
}
}
练习8: 效仿示例Lunch.java的形式,创建一个名为ConnectionManager的类,该类管理一个元素为Connection对象的固定数组。客户端程序员不能直接创建Connection对象,而只能通过ConnectionManager中的某个static方法来获取它们。当ConnectionManaget之中不再有对象时,它会返回null引用。在main()之中检测这些类。
package thinkinjava.charpenter6;
import java.util.Random;
/**
* @author Spring-_-Bear
* @version 2021/9/25 17:25
*/
public class ConnectionManager {
static int leftObject = 5;
static Connection[] connections = new Connection[leftObject];
/* Initial the object's reference */
static {
for (Connection c : connections) {
c = Connection.makeConnection();
}
}
/* If the number of objects is greater than zero, return its reference,
* otherwise return null
*/
public Connection getConnection() {
if (leftObject > 0) {
return connections[--leftObject];
} else {
System.out.println("NO MORE CONNECTIONS!");
return null;
}
}
public static void main(String[] args) {
ConnectionManager connectionManager = new ConnectionManager();
Random random = new Random(47);
int randomNum = random.nextInt(10);
for (int i = 0; i < randomNum; i++) {
System.out.println("The number of left objects: " + leftObject);
connectionManager.getConnection();
}
}
}
class Connection {
static int cnt = 0;
/* avoid directly creating the object of Connection */
private Connection() {
cnt++;
System.out.println("Connection(): " + cnt);
}
/* create a method to create the object of Connection
* and return the reference of the object
*/
static Connection makeConnection() {
return new Connection();
}
}
练习9: 在access/local目录下编写以下问价(假定access/local在你的CLASSPATH中):
package access.local;
class PackagedClass{
public PackagedClass(){
System.out.println("Creating a packaged class.")
}
}
然后在access/local之外的另一目录下创建下列文件:
package access.foreign;
import access.local.*;
public class Foreign{
public static void main(String[] args){
PackagedClass pc = new PackagedClass();
}
}
解释一下为什么编译器会产生错误。如果将Foreign置于access.local包之中的话,会有所改变吗?
/* Compiler Error Reason: PackagedClass in not public, so no access outside of package. Moving Foreign to local would allow package access to PackagedClass.
*/
以上是关于[读书笔记]Java编程思想第6章之访问权限控制的主要内容,如果未能解决你的问题,请参考以下文章