20200611
第六章:访问权限控制
好文章是改出来的,好的代码也是如此(至少对于我来说一定是)。
“重构即重写代码,以使代码变得更可读,更易理解,并因此而更具可维护性。”
“对于项目所需的时间和资金来说,最大的部分并非投入到了最初的代码编写上,而是投入到了代码的维护上。因此,使代码变得更加易于理解就意味着节省了大量的金钱。”
“重构时的基本问题是如何把变动的事物和保持不变的事物区分开来。”
“比如,类库开发者要怎样才能知道究竟都有哪些域已经被客户端程序员所调用了呢?”
于是Java提供了访问控制权限
“从最大权限到最小权限依次为:public、protected、包访问权限、和private”
???这句话不太懂
“如何将构件捆绑到一个内聚的类库单元中的问题。”
当然这里说的是package,但是依然不太明白。包:库单元
6.1 包:库单元
“当编写一个Java源代码文件时,此文件通常被称为编译单元(有时也称转译单元)。。。。。每个编译单元只能有一个public类,否则编译器就不会接受。”
“package名称的第一部分是类的创建者的反顺序的Internet的域名。”
Java解释器的运行过程如下,首先:找出环境变量CLASSPATH,。。。CLASSPATH包含一个或多个目录,用作查找class文件的根目录。从根目录开始,解释器获取包的名称并将每个句点替换成反斜杠(具体的文件目录形式依赖于具体的操作系统)
package语句必须是文件中的第一行非注释程序代码。
在导入已有的类的时候,由于导入的多个类库中中仍然会有重名的类为你所用,所以在导入时一定要格外小心。导入的问题IDEA已经帮你搞定了,需要的就只是
1.在看别人的代码的时候,要确定一个导入的类属于哪个类库
2.自己在写的时候,一定要清楚自己需要导哪个。有必要的话可以写个注释进行说明
已有的库方法,不管是你的还是别人的,只要你需要的功能对你开,那么你就可以将其封装做为自己的类库提供给别人使用。
C会用import来改变行为,条件编译功能。但是Java是跨平台的,所以不太依赖这个功能。
6.2 Java访问权限修饰符
“不要错误的认为java总是将当前目录视作是查找行为的起点之一。如果你的CLASSPATH之中缺少一个“.”(英文的点)作为路径之一的话,Java就不会查找那里。。。。。。为了文件可以被编译,在你的CLASSPATH之中一定要有“.”
默认的包访问权限通常已经提供了充足的隐藏措施。请记住,客户端程序员是无法访问包访问权限成员的。
使用private的示例:
//:access/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();
}
}
在上面的例子中,Sundae的构造器使用了private后,只有Sundae类内部的方法才可以使用构造器=才可以new,除此之外,额外定义的一个封装构造器的静态方法,才可以提供给外部成员使用。
因此,不能因为在类中的某个对象的引用是private,就认为其他的对象无法拥有这个对象的public引用。(参见本书的补充材料,显然我还没参见)
6.3 接口和实现
访问权限的控制常被称为是具体实现的隐藏。
把数据和方法包装进类中,以及具体实现的隐藏,常被称作是”封装“。
在以功能作为首次目标时,其实只要读对应的public部分就好。等到遇见作为内部实现类的实现细节的非public成员时停止阅读。
6.4 类的访问权限
有一个限制没整明白
???
3.虽然不是很常用,但编译单元内完全不带public类也是可能的。在这种情况下,可以随意对文件命名(尽管随意命名会使得人们在阅读和维护代码时产生混淆。)
请注意,类既不可以是private的(这样会使得除了该类之外,其他任何类都不可以访问他),也不可以是protected的。所以对于类的访问权限,仅有两个选择:包访问权限或public.如果不希望其他任何人对该类拥有访问权限,可以把所有的构造器都指定为private,从而阻止任何人创建该类的对象。
但是,有一个例外,就是你在该类的static成员内部可以创建。示例如下:
//:acess/Lunch.java
//Demonstrates class access specifiers. Make a class
//effectively private with private constructors:
class Soup1{
private Soup1(){}
//(1) Allow creation via static method:
public static Soup1 makeSoup(){
return new Soup1;
}
}
class Soup2{
private Soup2(){}
//(2)Create a static object and return a reference
//upon request.(The "Singleton" pattern):
private static Soup2 ps1 = new Soup2;
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();
}
}
在上面的例子中,看class soup2 ,当该类的构造器被设置为private之后,且只能用private static来获得单一对象,外部再由static方法来获得这个单一对象,被称为单例模式。(Singleton)
如果该类的某个static成员时public的话,则客户端程序员仍旧可以调用该static成员,尽管他们不能生成该类的对象。
6.5 总结
如果接口和实现可以被明确的隔离和加以保护,那么就可以实现这一目的,而不必强制客户端程序员重写代码。。。。只要不删除任何客户端程序员在他们的程序中已经用到的东西,就可以在以后添加更多的方法。