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