这是小题目的系列之四
之一:http://topic.csdn.net/u/20070828/10/7aa61fbc-8575-4212-85c4-582c08f81535.html
之二:http://topic.csdn.net/u/20070917/10/928cdd3b-0ec6-4236-a89d-7c3ddba8eaba.html
之三:http://topic.csdn.net/u/20080130/17/7fdd8b93-bdd6-467a-863e-fc3c9731bc52.html
做题规则:老规矩,不允许上机操作,全部完成后可以将代码复制自行检测一下,需采用 JDK 5.0 或以上版本
1,诡异的 Set
看看下面的这段程序,输出的是_____。
A. 4
B. 5
C. 6
D. 以上都不是
import java.net.MalformedURLException; import java.net.URL; import java.util.HashSet; import java.util.Set; public class Test1 { private static final String[] URL_NAMES = { "http://javapuzzlers.com", "http://apache2-snort.skybar.dreamhost.com", "http://www.google.com", "http://javapuzzlers.com", "http://findbugs.sourceforge.net", "http://www.cs.umd.edu" }; public static void main(String[] args) throws MalformedURLException { Set<URL> favorites = new HashSet<URL>(); for (String urlName : URL_NAMES) favorites.add(new URL(urlName)); System.out.println(favorites.size()); } }
=====★===我===是===题===目===间===的===小===分===隔===符===★=====
2,Number 惹的祸
下面是一个三目运算符的小题目,看看程序运行后,在控制台上会输出_____。
A. 3
B. 1.0
C. 抛出异常
D. 以上都不是
import java.util.Random; public class Test2 { public static void main(String[] args) { Random rnd = new Random(); boolean toBe = rnd.nextBoolean(); Number result = (toBe || !toBe) ? new Integer(3) : new Float(1); System.out.println(result); } }
到目前为止,我们就结束带有迷惑性质的题目,包括前三期我们共有 19 道此类性质的题目了。
=====★===我===是===题===目===间===的===小===分===隔===符===★=====
接下来是一些有趣而偏向于实用的题目,需要自行来动手设计,可以看看您对面向对象、Java 语言,以
及 JDK 类库的了解程度。
下面的题目也没有什么统一标准的答案(因为条条大路通罗马呗),请大家各抒己见,结帖前我会贴一些
代码以供参考。
以下题目在没有 JDK 版本要求时,均采用 JDK 5.0。
3,限定参数范围
某个方法有一个参数,这个参数只能接受 1~10 之间的值(含 1 和 10),在此范围之外的参数都被视
为非法。现在需要设计一个方法,在传入非法参数时在编译期报错。
注意:要求在编译期报错,而不是在运行期。JDK 版本限定为 1.4。
=====★===我===是===题===目===间===的===小===分===隔===符===★=====
4,对象复制
现在需要设计一个这样的工具方法,使用这个方法来复制一个对象字段中的值到别外一个对象中去,基本
的方法签名:public static void copyFields(Object src, Object dist); 但是这样的方法不
是很健壮,经不起考验。
我们知道要拷贝对象属性时 src 和 dist 应该具有相同的类型,或者是 dist 是 src 的子类型这样做
才有意义。现在要重新对这个方法进行设计,并能满足上面的要求,在 src 和 dist 不是同一类型时,需
要在编译期报错。
5,懒人的提议
在一般实体类对应的 DAO 中都有 CRUD 操作,也就是最基本的四个增查改删。
以 StudentDao 为例,可能会有以下五个最基本的方法:
public Student get(Serializable id) { return (Student)getHibernateTemplate().load(Student.class, id); } public List<Student> getAll() { return (List<Student>)getHibernateTemplate().loadAll(Student.class); } public void save(Student stu) { getHibernateTemplate().saveOrUpdate(stu); } public void remove(Student stu) { getHibernateTemplate().delete(stu); } public void update(Student stu) { getHibernateTemplate().update(stu); }
但在 TeacherDao 中,也要会有这几个方法,只是传入的参数不同而已。如果在每个 DAO 里都写上
这么几个方法就显示很拖杳,重复的代码就会很多。
以大家常用的 Spring + Hibernate 组合来说,Spring 提供了一个操作 Hibernate 的抽象类
——HiernateDaoSupport,只要继承它就可以很方便地实现一些 DAO 操作,通常采用 Hibernate
实现类的签名为:
public StudentHibernateDao extends HibernateSupportDao implements StudentDao; +-------------------------------+ class of Spring --> | <<abstract>> | | HibernateDaoSupport | +-------------------------------+ A | | <------ DAO Interface Package ------->|<- Hibernate Impleme|ntation Package -> | | +-------------------------------+ | +-------------------------------+ | <<interface>> | | | | | StudentDao | | | StudentHibernateDao | +-------------------------------+ | +-------------------------------+ | + get(Serializable) : Student | | | + get(Serializable) : Student | | + getAll() : List<Student> |<- - - - -| + getAll() : List<Student> | | + save(Student) : void | | | + save(Student) : void | | + remove(Student) : void | | | + remove(Student) : void | | + update(Student) : void | | | + update(Student) : void | | + method1() | | | + method1() | | + method2() | | | + method2() | | + ... | | | + ... | +-------------------------------+ | +-------------------------------+ | <- - - - 表示实现接口(不表示依赖哦,因为在半角状态下我找了好久都没找到向左的空心三角啦, 将究着看看,不要要求太高哈) A | 表示继承(就把 A 的两个脚去掉,看成向上的空心三角哈) |
这样我们只要在客户端配置一下具体的实现类,采用 StudentDao 进行面向接口的编程就可以完成
DAO 操作了,从而大大降低了耦合程度。
但是这样做,HibernateSupportDao 中并没有提供那几个基本的 CRUD 操作,在这种情况下这个
类的签名并不能满足我们的要求,需要重新进行设计(仍然需要 HibernateSupportDao 提供的功
能),不改变客户端的行为(与普通的实现采用同样的配置、同样的调用),在实现时不需要每个
DAO 里重复劳动地去写那几个方法,以降低 DAO 层的工作量。你该如何进行设计?
当然了,这里仅仅只是举一个以 Spring + Hibernate 为代表的例子,这样的设计也可以用于其
他方面。
=====★===我===是===题===目===间===的===小===分===隔===符===★=====
6,如何关闭?
我们都使用过数据库连接池,即在连接池中保存了多个数据库连接 Connection 对象,需要连接数
据库时从池中取出一个 Connection 对象进行操作,用完后将这个对象归还到池中。一般来说连接
池采用一个集合来存放这些连接对象,在调用 getConnection 方法时从集合中取中一个,用完后
采用 con.close() 把这个连接归还到池中。
嘿嘿,现在问题来了,我们都知道 con.close() 是关闭与数据库之间的连接,但是在连接池的状态
下我们并不能真正地将其关闭掉(如果真的关掉的话,这个连接就不能再重用了)。现在有个办法,
就是不调用 con.close(),同样地也就不让连接关闭,在使用完后用 releaseConnection(Connection con)
的方法将其归还到池中。但是这样做问题又来了,Connection 中的 close() 方法是公开的,我们
并不能阻止使用者调用它。现在我们要设计这个连接池,不采用 releaseConnection 的方法,我们
要改变原有 con.close() 中的行为,不让其关闭,而是把它归还到池中。
当然了,这只是连接池中一个很小的问题,要设计一个功能完善的连接池,至少还需要连接参数的可配
置化、连接异常的检测和处理等,而且问题远不止这些,问题可能会多得超出我所能想到的:(
这里并不是需要大家去实现一个连接池,只是提出一个小问题,拓展一下思路,发表一下您对这个问题
的看法,或者是您将会怎么做?解决这个问题的话,我们就可以自己实现一个很很简单的连接池哦:)
注意:Connection 仅仅是个接口
曾经看过一些网友实现的连接池,基本上都是采用 releaseConnection 的形式来将连接归还到池中去
的,并没有解决 con.close() 的问题,使用者的行为我们是无法加以干涉的,如果使用者不习惯去调用
releaseConnection,而是照常用的习惯去调用 con.close() 的话,这个连接池就是形同虚设,因为这
样一个连接都得不到重用。
=================================================