《TIJ4》访问权限控制 练习 E08 拓展:创建一个更复杂的ConnectionManager
题目
创建一个名为ConnectionManager的类,该类管理一个元素为Connection对象的固定数组。客户端程序员不能直接创建Connection对象,而只能通过ConnectionManager的某个static方法获取它们。当ConnectinManager不再有对象时,它会返回null引用,要允许客户端程序员使用完Connection之后归还它。在main()中检测这些类。
我的解答
刚开始是没有思路的,在参考了答案之后,自己默写出来的代码如下。
package access;
import access.connection2.my.Connection;
import access.connection2.my.ConnectionManager;
public class E08_ConnectionManager2_My {
public static void main(String[] args) {
System.out.println("Get 5 connections.");
Connection[] connections = new Connection[5];
for (int i = 0; i < connections.length; i++) {
connections[i] = ConnectionManager.getConnection();
System.out.println(connections[i].toString());
}
System.out.println("Check in 2 connections");
System.out.println("Check in " + connections[1].toString());
connections[1].checkIn();
System.out.println("Check in " + connections[4].toString());
connections[4].checkIn();
System.out.println("Get remaining connections.");
Connection[] remainingConnections = new Connection[7];
for (int i = 0; i < remainingConnections.length; i++) {
remainingConnections[i] = ConnectionManager.getConnection();
System.out.println(remainingConnections[i].toString());
}
}
}
/* Output:
Get 5 connections.
Connection 0
Connection 1
Connection 2
Connection 3
Connection 4
Check in 2 connections
Check in Connection 1
Check in Connection 4
Get remaining connections.
Connection 1
Connection 4
Connection 5
Connection 6
Connection 7
Connection 8
Connection 9
*/
package access.connection2.my;
public class Connection {
private static int counter = 0;
private int id = counter++;
Connection(){}
@Override
public String toString() {
return "Connection " + id;
}
public void doSomething(){
//Todo
}
public void checkIn(){
ConnectionManager.checkIn(this);
}
}
package access.connection2.my;
public class ConnectionManager {
private static Connection[] pool = new Connection[10];
static {
for (int i = 0; i < pool.length; i++) {
pool[i] = new Connection();
}
}
public static Connection getConnection() {
for (int i = 0; i < pool.length; i++) {
if (pool[i] != null) {
Connection c = pool[i];
pool[i] = null; //表示被取出
return c;
}
}
return null; //都被取出
}
public static void checkIn(Connection c) {
for (int i = 0; i < pool.length; i++) {
if (pool[i] == null) {
pool[i] = c;
return;
}
}
}
}
而参考答案代码如下:
package access;
import access.connection2.bruce.Connection;
import access.connection2.bruce.ConnectionManager;
public class E08_ConnectionManager2_Bruce {
public static void main(String[] args) {
Connection[] ca = new Connection[10];
// Use up all the connections
for (int i = 0; i < 10; i++) {
ca[i] = ConnectionManager.getConnection();
// Should produce "null" since there are no more connections:
}
System.out.println(ConnectionManager.getConnection());
// Return connections, then get them out:
for (int i = 0; i < 5; i ++){
ca[i].checkIn();
Connection c = ConnectionManager.getConnection();
System.out.println(c);
c.doSomething();
c.checkIn();
}
}
}
/* Output:
null
Connection 0
Connection 0
Connection 0
Connection 0
Connection 0
*/
package access.connection2.bruce;
public class Connection {
private static int counter = 0;
private int id = counter++;
Connection(){}
public String toString() {
return "Connection " + id;
}
public void doSomething(){}
public void checkIn(){
ConnectionManager.checkIn(this);
}
}
package access.connection2.bruce;
public class ConnectionManager {
private static Connection[] pool = new Connection[10];
static {
for (int i = 0; i < pool.length; i++) {
pool[i] = new Connection();
}
}
// Produce the first available connection
public static Connection getConnection() {
for (int i = 0; i < pool.length; i++) {
if (pool[i] != null) {
Connection c = pool[i];
pool[i] = null; // Indicates "in use"
return c;
}
}
return null; // None left
}
public static void checkIn(Connection c) {
for (int i = 0; i < pool.length; i++) {
if (pool[i] == null) {
pool[i] = c; // Check it back in
return;
}
}
}
}
容易犯错的地方:
- private int id = counter++; 由于counter是static变量,因此,所有类的对象共享1个counter,而每个对象生成时,成员变量id要初始化,这句代码依次做了两件事:一、id被初始化为0, 1, 2, 3, ... 。二、counter自增1。
- Connection(){} 这里显示声明了构造方法,而访问权限是默认的包访问权限,只有同一个包下的类能调用,对于客户端程序员是不可用的。
- private static Connection[] pool = new Connection[10]; 要注意new Connection[10]与new Connection()的区别,这里在初始化pool时只是初始化了空的引用,而每个引用并不指向实际的对象。
- 注意学习作者测试方法main()的思路,先取出所有connection, 然后依次归还5个的connection,分别是Connection 0, Connection 1, Connection 2, Connection 3, Connection 4,在每次归还后都要再取一个可用的Connection,第一次归还的是Connection 0,取出的也是Connection 0, 使用之后再次把Connection 0 归还,因此第二趟循环,归还的是Connection 1,在取时由于pool[0]的位置是可以取Connection的,所以取出的依旧是Connection 0;