java编程思想 第 6 章 访问权限控制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012417380/article/details/79884552

更新类库时为了让开发人员知道哪些类是被其它类引用的,不能被修改而引人了访问权限控制。

public > protect >(默认) > private

一、包:库单元

包内包含一组类、它们在单一的名称空间下被组织到了一起:

java.utils.ArrayList使用,使用全限定名:

//: access/FullQualification.java

public class FullQualification {
  public static void main(String[] args) {
    java.util.ArrayList list = new java.util.ArrayList();
  }
} ///:~

使用import导入

//: access/SingleImport.java
import java.util.ArrayList;

public class SingleImport {
  public static void main(String[] args) {
    ArrayList list = new java.util.ArrayList();
  }
} ///:~

同一包下全导入

import java.util.*;

未指明包名为,位于默认包下。

一个*.java 文件为一个编译单元。该编译单元有且只有一个public类且与*.java文件名相同 和多个非public 类。编译成功后生成以类为单位的多个*.class文件

1.1 代码组织

在文件中第一行为类指定包名(包名

必须小写):

package access;

创建一个MyClass.java 文件,有且只有一个同名的public 类。

//: access/mypackage/MyClass.java
package access.mypackage;

public class MyClass {
  // ...
} ///:~

MyClass类受access.mypackage包保护,如果MyClass类和该包下其它公共类,使用全限定名或者import关键字导入
全限定名:

//: access/QualifiedMyClass.java

public class QualifiedMyClass {
  public static void main(String[] args) {
    access.mypackage.MyClass m =
      new access.mypackage.MyClass();
  }
} ///:~

import导入:

//: access/ImportedMyClass.java
import access.mypackage.*;

public class ImportedMyClass {
  public static void main(String[] args) {
    MyClass m = new MyClass();
  }
} ///:~

package 和 import 将单一的全局名称空间割开,防止出现名称冲突。

1.2 创建独一无二的包名

创建一个名为simple的类库

包名:net.mindview.simple

该名称下才两个字文件

Vector.java

//: net/mindview/simple/Vector.java
// Creating a package.
package net.mindview.simple;

public class Vector {
  public Vector() {
    System.out.println("net.mindview.simple.Vector");
  }
} ///:~

List.java

//: net/mindview/simple/List.java
// Creating a package.
package net.mindview.simple;

public class List {
  public List() {
    System.out.println("net.mindview.simple.List");
  }
} ///:~

两个文件都位于K:\研二\Java\thindinjava\code1\net\mindview\simple路径下

而向ClassPath添加了K:\研二\Java\thindinjava\code1路径。

LibTest.java 文件可以位于任何目录:

//: access/LibTest.java
// Uses the library.
import net.mindview.simple.*;

public class LibTest {
  public static void main(String[] args) {
    Vector v = new Vector();
    List l = new List();
  }
} /* Output:
net.mindview.simple.Vector
net.mindview.simple.List
*///:~

编译器编译该文件碰到import语句时,会去ClassPath中的目录中查找子目录\net\mindview\simple,然后编译出相应的类文件。

练习二:冲突

// access/Collision.java
// TIJ4 Chapter Access, Exercise 2, page 217
/* Take the code fragments in this section and turn them into a program and 
* verify that collisions do occur.
*/
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();
    }
}

第一行取消注释时提示:

K:\研二\Java\thindinjava\code2\Access>javac Collision.java
Collision.java:11: 错误: 对Vector的引用不明确
                 Vector v = new Vector(); // ambiquous collision
                 ^
  java.util 中的类 java.util.Vector 和 net.mindview.simple 中的类 net.mindview.simple.Vector 都匹配
Collision.java:11: 错误: 对Vector的引用不明确
                 Vector v = new Vector(); // ambiquous collision
                                ^
  java.util 中的类 java.util.Vector 和 net.mindview.simple 中的类 net.mindview.simple.Vector 都匹配
2 个错误

1.3 定制工具库

创建一个名为Print.java工具库

//: net/mindview/util/Print.java
// Print methods that can be used without
// qualifiers, using Java SE5 static imports:
package net.mindview.util;
import java.io.*;

public class Print {
  // Print with a newline:
  public static void print(Object obj) {
    System.out.println(obj);
  }
  // Print a newline by itself:
  public static void print() {
    System.out.println();
  }
  // Print with no line break:
  public static void printnb(Object obj) {
    System.out.print(obj);
  }
  // The new Java SE5 printf() (from C):
  public static PrintStream
  printf(String format, Object... args) {
    return System.out.printf(format, args);
  }
} ///:~

编译完成后,使用import static静态导入该类,可以使用该类的静态方法

//: access/PrintTest.java
// Uses the static printing methods in Print.java.
import static net.mindview.util.Print.*;

public class PrintTest {
  public static void main(String[] args) {
    print("Available from now on!");
    print(100);
    print(100L);
    print(3.14159);
  }
} /* Output:
Available from now on!
100
100
3.14159
*///:~

Rage.java工具类

//: net/mindview/util/Range.java
// Array creation methods that can be used without
// qualifiers, using Java SE5 static imports:
package net.mindview.util;

public class Range {
  // Produce a sequence [0..n)
  public static int[] range(int n) {
    int[] result = new int[n];
    for(int i = 0; i < n; i++)
      result[i] = i;
    return result;
  }
  // Produce a sequence [start..end)
  public static int[] range(int start, int end) {
    int sz = end - start;
    int[] result = new int[sz];
    for(int i = 0; i < sz; i++)
      result[i] = start + i;
    return result;
  }
  // Produce a sequence [start..end) incrementing by step
  public static int[] range(int start, int end, int step) {
    int sz = (end - start)/step;
    int[] result = new int[sz];
    for(int i = 0; i < sz; i++)
      result[i] = start + (i * step);
    return result;
  }
} ///:~

1.4

练习三

// access/debug/Debug.java
// TIJ4 Chapter Access, Exercise 3, page 220
/* Create two packages: debug and debugoff, containing an identical class with a
* debug() method. The first version displays its String argument to the console,
* the second does nothing. Use a static import line to import the class into a test
* program, and demonstrate the conditional compilation effect.
*/

/* 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);
    }
}


1.5 对使用包的忠告

包名对应路径

二、Java访问权限修饰词

public、protect和private 这几个java方法权限修词在使用时,是为于类的成员定义之前,无论是域或方法。
如果不加任何词修饰,则是包访问权限。

2.1 包访问权限

类的成员没有指定修饰词,具有包访问权限。这意味着该类当前包中所有其它类对该成员有访问权限,而该包外的其它类不能够访问。处于同一编译单元中的类是能够彼此方法的。严格的同一个包下才能访问,同一个包下其它子目录中的类无法访问。

取得对该成员的访问权限方式有:
1. 使该成员为public。无论在哪里都能够访问。
2.不加修饰词。同一个包内的其它类都能访问。
3。使用proteced修饰。可以被子类和同一包中的其它类访问
4通过setter和getter访问

2.2 public:接口访问权限

类成员使用 public 关键字修饰,意味着该成员能被其它任何类使用。
下面编译dessert包

//: access/dessert/Cookie.java
// Creates a library.
package access.dessert;



public class Cookie {
  public Cookie() {
   System.out.println("Cookie constructor");
  }
  void bite() { System.out.println("bite"); }
} ///:~

使用Cookie的类:

//: access/Dinner.java
// Uses the library.
import access.dessert.*;

public class Dinner {
  public static void main(String[] args) {
    Cookie x = new Cookie();
    //! x.bite(); // Can't access
  }
} /* Output:
Cookie constructor
*///:~

Cookie类的构造器为public,因此可以访问。Cookie类 dessert() 方法为包访问权限,因此不可以被访问 。

默认包

//: access/Cake.java
// Accesses a class in a separate compilation unit.

class Cake {
  public static void main(String[] args) {
    Pie x = new Pie();
    x.f();
  }
} /* Output:
Pie.f()
*///:~

第二个处于相同目录的文件Pie.java

//: access/Pie.java
// The other class.

class Pie {
  void f() { System.out.println("Pie.f()"); }
} ///:~

可以正常编译的原因是因为它们处于相同的目录并且没有指定包名,编译器认为它们在该目录下的默认包中。

2.3 private: 你无法访问

private 关键字的含义是,除了包含该成员的类外,其它类都无法访问。

Private允许自己随意改变该成员,而不必考虑其它类。
使用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 类构造器私有,防止别的类创建它,只能通过它提供的静态方法makeASundae 创建。还可以阻止其它类继承。

将类的辅助方法设为private,防止其它类使用。

2.4 protected 继承访问权限

如果创建一个新包,并在新包中创建一个继承其它包中类的继承类,那么该继承类只能访问父类public修饰的成员和protected修饰的成员。
protected 关键字提供包访问权限和子类访问权限。

之前例子Cookie.java 不可调用包访问权限bite()。

//: access/ChocolateChip.java
// Can't use package-access member from another package.
import access.dessert.*;

public class ChocolateChip extends Cookie {
  public ChocolateChip() {
   System.out.println("ChocolateChip constructor");
  }
  public void chomp() {
    //! bite(); // Can't access bite
  }
  public static void main(String[] args) {
    ChocolateChip x = new ChocolateChip();
    x.chomp();
  }
} /* Output:
Cookie constructor
ChocolateChip constructor
*///:~

将之前例子Cookie.java 中bite()方法进行修改为protected:

//: access/cookie2/Cookie.java
package access.cookie2;

public class Cookie {
  public Cookie() {
    System.out.println("Cookie constructor");
  }
  protected void bite() {
    System.out.println("bite");
  }
} ///:~

现在Cookie.java 中bite()方法对所有继承它的类是可见的。

//: access/ChocolateChip2.java
import access.cookie2.*;

public class ChocolateChip2 extends Cookie {
  public ChocolateChip2() {
   System.out.println("ChocolateChip2 constructor");
  }
  public void chomp() { bite(); } // Protected method
  public static void main(String[] args) {
    ChocolateChip2 x = new ChocolateChip2();
    x.chomp();
  }
} /* Output:
Cookie constructor
ChocolateChip2 constructor
bite
*///:~

练习四

// access/CookieThief.java
// TIJ4 Chapter Access, Exercise 4, page 227
// Show that protected methods have package access but are not public.
/* In directory Cookie2:
* //access/cookie2/Cookie.java
* //Creates a library
* package access.cookie2;
*
* public class Cookie {
*   public Cookie() {
*       System.out.println("Cookie contstructor");
*   }
*   protected void bite() { System.out.println("bite"); }
* }
*/

import access.cookie2.*;

public class CookieThief {
    public static void main(String[] args) {
        Cookie x = new Cookie();
        //! x.bite(); // access protected
    }   
}

练习五

// access/AccessTest.java
// TIJ4 Chapter Access, Exercise 5, page 227 
/* Create a class with public, private, protected and package-access fields and
* method members. Create an object of this class and see what kind of compiler
* messages you get when you try to access all the class members. Be aware that
* classes in the same directory are part of the "default" package.
*/

/* 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; // run command java access.AccessTest

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
    }   
}

//输出
FourWays() constructor
0
1
2
10
20
30

练习六

// access/ProtectedData.java
// TIJ4 Chapter Access, Exercise 6, page 228
/* Create a class with protected data. Create a second class in the same file with
* a method that manipulates the protected data in the first class.
*/

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);        
    }   
}
//输出

三、接口和实现

将接口和具体实现分离,将public成员 放在最上方

//: access/OrganizedByAccess.java

public class OrganizedByAccess {
  public void pub1() { /* ... */ }
  public void pub2() { /* ... */ }
  public void pub3() { /* ... */ }
  private void priv1() { /* ... */ }
  private void priv2() { /* ... */ }
  private void priv3() { /* ... */ }
  private int i;
  // ...
} ///:~

四、类的访问权限

类的访问权限:
1.每个编译单元(文件)只能有一个public类。
2.public类的名称必须与编译单元文件名相同,包括大小写
3. 编译单元也可以没有public类,这时文件名随意命名。

将类的public属性去掉,该类具有包访问权限。该类只能用于该包中

练习八

// MakeWidget.java
// TIJ4 Chapter Access, Exercise 7, page 230
/* Create the library according to the code fragments describing access and Widget.
* Create a Widget in a class that is not part of the access package.
*/

/* 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();
    }
}

如果将Widget中的public 关键字去掉,编译会提示:

access\MakeWidget.java:20: 错误: Widget在access中不是公共的; 无法从外部程序包中对其进行访问
                Widget w = new Widget();

Widget类具有包访问权限。

类仅有两个选择:包访问权限或public。不能用private或protected修饰。

将类的构造器设为私有阻止其它人创建对象,在类的static方法内部创建该对象。

示例Lunch.java

//: access/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();
  }
} ///:~

练习八

// access/ConnectionManager.java
// TIJ4 Chapter Access, Exercise 8, page 233
/* Following the form of the example Lunch.java, create a class called
* ConnectionManager that manages a fixed array of Connection objects. The client
* programmer must not be able to explicitly create Connection objects, but can
* only get them via a static method in ConnectionManager. When ConnectionManager
* runs out of objects, it returns a null reference. Test the classes in main(). */
package access;

class Connection {
    private static int count = 0;
    private int i = 0;
    private Connection() { System.out.println("Connection()");}
    // Allow creation via static method:
    static Connection makeConnection() {
        count++;
        return new Connection();
    }
    public static int howMany() { return count; } 
    public String toString() {
        return ("Connection " + count);
    }
}

public class ConnectionManager {
    static int howManyLeft = 3;
    static Connection[] ca = new Connection[3]; 
    {
    for(Connection x : ca)
        x = Connection.makeConnection();
    }
    public static Connection getConnection() {
        if(howManyLeft > 0)
            return ca[--howManyLeft];
        else {
            System.out.println("No more connections");
            return null;
        }
    }
    public static void main(String[] args) {        
        ConnectionManager cm = new ConnectionManager();
        System.out.println(cm.howManyLeft);
        cm.getConnection();
        System.out.println(howManyLeft);
        cm.getConnection();
        System.out.println(howManyLeft);
        cm.getConnection();
        System.out.println(cm.getConnection());
        System.out.println(howManyLeft);
    }                   
} 

输出:
Connection()
Connection()
Connection()
3
2
1
No more connections

猜你喜欢

转载自blog.csdn.net/u012417380/article/details/79884552