??xml version="1.0" encoding="utf-8" standalone="yes"?>
String的特D之?/strong>
String是Java~程中很常见的一个类,q个cȝ实例是不可变?immutable ).Z提高效率,JVM内部对其操作q行了一些特D处?本文旨在于帮助大家辨析q些Ҏ的地?
在进入正文之?你需要澄清这些概?
1) 堆与?br />
2) 相同与相{?==与equals
3) =的真实意?
栈与?/strong>
1. ?stack)与堆(heap)都是Java用来在内存中存放数据的地斏V与C++不同QJava自动理栈和堆,E序员不能直接地讄栈或堆。每个函数都有自q?而一个程序只有一个堆.
2. 栈的优势是,存取速度比堆要快Q仅ơ于直接位于CPU中的寄存器。但~点是,存在栈中的数据大与生存期必L定的,~Z灉|性。另外,栈数据可以共享,详见W?炏V堆的优势是可以动态地分配内存大小Q生存期也不必事先告诉编译器QJava的垃圾收集器会自动收走这些不再用的数据。但~点是,׃要在q行时动态分配内存,存取速度较慢?3. Java中的数据cd有两U? 一U是基本cd(primitive types), 共有8U,即int, short, long, byte, float, double, boolean, char(注意Qƈ没有string的基本类?。这U类型的定义是通过诸如int a = 3; long b = 255L;的Ş式来定义的,UCؓ自动变量。值得注意的是Q自动变量存的是字面|不是cȝ实例Q即不是cȝ引用Q这里ƈ没有cȝ存在。如int a = 3; q里的a是一个指向intcd的引用,指向3q个字面倹{这些字面值的数据Q由于大可知,生存期可?q些字面值固定定义在某个E序块里面,E序块退出后Q字D值就消失?Q出于追求速度的原因,存在于栈中? 另外Q栈有一个很重要的特D性,是存在栈中的数据可以共享。假设我们同时定? int a = 3; int b = 3Q? ~译器先处理int a = 3Q首先它会在栈中创徏一个变量ؓa的引用,然后查找有没有字面gؓ3的地址Q没扑ֈQ就开辟一个存?q个字面值的地址Q然后将a指向3的地址。接着处理int b = 3Q在创徏完b的引用变量后Q由于在栈中已经?q个字面|便将b直接指向3的地址。这P出Ca与b同时均指?的情c? 特别注意的是Q这U字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了q个对象的内部状态,那么另一个对象引用变量也卛_反映个变化。相反,通过字面值的引用来修改其|不会D另一个指向此字面值的引用的g跟着改变的情c如上例Q我们定义完a?b的值后Q再令a=4Q那么,b不会{于4Q还是等?。在~译器内部,遇到a=4Q时Q它׃重新搜烦栈中是否?的字面|如果没有Q重新开辟地址存放4的|如果已经有了Q则直接a指向q个地址。因此a值的改变不会影响到b的倹{? 另一U是包装cL据,如Integer, String, Double{将相应的基本数据类型包装v来的cR这些类数据全部存在于堆中,Java用new()语句来显C地告诉~译器,在运行时才根据需要动态创建,因此比较灉|Q但~点是要占用更多的时间?
相同与相{?==与equals
在Java?相同指的是两个变量指向的地址相同,地址相同的变量自然值相?而相{是指两个变量值相{?地址可以不同.
相同的比较?=,而相{的比较使用equals.
对于字符串变量的值比较来?我们一定要使用equals而不?=.
=的真实意?/strong>
=卌值操?q里没有问题,关键是这个值有时是真正的?有的是地址,具体来说会根据等号右边的部分而变?
如果是基本类?八种),则赋g递的是确定的?x双变量的g递给左边的变?
如果是类cd,则赋g递的是变量的地址,x{号左边的变量地址指向{号双的变量地址.
指出下列代码的输?/strong>
String andy="andy";
String bill="andy";
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
String str=“andy”的机制分?/strong>
上页代码的输出是andy和bill地址相同.
当通过String str=“andy”;的方式定义一个字W串?JVM先在栈中L是否有gؓ“andy”的字W串,如果有则str指向栈中原有字符串的地址;如果没有则创Z?再将str的地址指向? String andy=“andy”q句代码走的是第二步,而String bill=“andy”走的是第一?因此andy和bill指向了同一地址,故而andy==bill,andy和bill地址相等,所以输出是andy和bill地址相同.
q样做能节省I间—少创徏一个字W串;也能节省旉—定向L创徏要省?
指出下列代码的输?/p>
String andy="andy";
String bill="andy";
bill="bill";
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
输出及解?/strong>
上页代码的输出是:andy和bill地址不同
当执行bill=“bill”一句时,外界看来好像是给bill变换了一个新值bill,但JVM的内部操作是把栈变量bill的地址重新指向了栈中一块gؓbill的新地址,q是因ؓ字符串的值是不可变的,要换?赋值操?只有变量地址重新转向. q样andy和bill的地址在执行bill=“bill”一句后׃一样了,因此输出是andy和bill地址不同.
指出下列代码的输?/strong>
String andy=new String("andy");
String bill=new String("andy");
// 地址比较
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
// 值比?br />
if(andy.equals(bill)){
System.out.println("andy和bill值相{?);
}
else{
System.out.println("andy和billg{?);
}
输出及机制分?/strong>
andy和bill地址不同
andy和bill值相{?br />
我们知道new操作新徏出来的变量一定处于堆?字符串也是一?
只要是用new()来新建对象的Q都会在堆中创徏Q而且其字W串是单独存值的,x个字W串都有自己的?自然地址׃会相?因此输出了andy和bill地址不同.
equals操作比较的是D不是地址,地址不同的变量值可能相?因此输出了andy和bill值相{?
指出下列代码的输?/strong>
String andy=new String("andy");
String bill=new String(andy);
// 地址比较
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
// 值比?br />
if(andy.equals(bill)){
System.out.println("andy和bill值相{?);
}
else{
System.out.println("andy和billg{?);
}
输出
andy和bill地址不同
andy和bill值相{?/p>
道理仍和W八늛?只要是用new()来新建对象的Q都会在堆中创徏Q而且其字W串是单独存值的,x个字W串都有自己的?自然地址׃会相?
指出下列代码的输?/strong>
String andy="andy";
String bill=new String(“Bill");
bill=andy;
// 地址比较
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
// 值比?br />
if(andy.equals(bill)){
System.out.println("andy和bill值相{?);
}
else{
System.out.println("andy和billg{?);
}
输出及解?/strong>
andy和bill地址相同
andy和bill值相{?br />
String bill=new String(“Bill”)一句在栈中创徏变量bill,指向堆中创徏?#8221;Bill”,q时andy和bill地址和值都不相?而执行bill=andy;一句后,栈中变量bill的地址指向了andy,q时bill和andy的地址和值都相同?而堆中的”Bill”则没有指向它的指?此后q块内存等待被垃圾攉.
指出下列代码的输?/p>
String andy="andy";
String bill=new String("bill");
andy=bill;
// 地址比较
if(andy==bill){
System.out.println("andy和bill地址相同");
}
else{
System.out.println("andy和bill地址不同");
}
// 值比?br />
if(andy.equals(bill)){
System.out.println("andy和bill值相{?);
}
else{
System.out.println("andy和billg{?);
}
输出
andy和bill地址相同
andy和bill值相{?/p>
道理同第十二?/p>
l论
使用诸如String str = “abc”Q的语句在栈中创建字W串时时Qstr指向的字W串不一定会被创建!唯一可以肯定的是Q引用str本n被创Z。至于这个引用到底是否指向了一个新的对象,必须Ҏ上下文来考虑Q如果栈中已有这个字W串则str指向?否则创徏一个再指向新创建出来的字符? 清醒地认识到q一点对排除E序中难以发现的bug是很有帮助的?br /> 使用String str = “abc”Q的方式Q可以在一定程度上提高E序的运行速度Q因为JVM会自动根据栈中数据的实际情况来决定是否有必要创徏新对象。而对于String str = new String(“abc”)Q的代码Q则一概在堆中创徏新对象,而不其字符串值是否相{,是否有必要创建新对象Q从而加重了E序的负担?br /> 如果使用new()来新建字W串的,都会在堆中创建字W串Q而且其字W串是单独存值的,x个字W串都有自己的?且其地址l不会相?br /> 当比较包装类里面的数值是否相{时Q用equals()ҎQ当试两个包装cȝ引用是否指向同一个对象时Q用==?br /> ׃Stringcȝimmutable性质Q当String变量需要经常变换其值如SQL语句拼接,HTML文本输出Ӟ应该考虑使用StringBufferc,以提高程序效率?
Java集合cM最基础的接口是CollectionQ它定义了两个基本方法:
Public interface Collection<E>{
boolean add(E element);
Iterator<E> iterator();
}
add是向Collection中添加一个元素,当添加的内容实对Collection发生了有效变更的话addҎq回真,否则q回假,比如你向一个Setd重复的元素时QSet内容不会变化QaddҎ会返回假?br />
iteratorҎq回实现了Iterator接口的对象,你可以借此对Collection中的内容q行挨个遍历?/p>
2.Iterator接口
Iterator有三个方法:
Public interface Iterator<E>{
E next();
boolean hasNext();
void remove();
}
通过重复调用nextҎQ你可以挨个遍历Collection中的元素。然而,当遍历到Collection末端Ӟ此方法会抛出一个NoSuchElementException异常Q因此在遍历时你需要hasNextҎ和nextҎ配合使用?hasNextҎ在当前遍历位|后仍有元素时会q回真。配合例子如下:
Collection<String> c=….;
Iterator<String> iterator=c.iterator();
While(iterator.hasNext()){
String str=iterator.next();
…….
}
removeҎ能删除上一ơ调用next时指向的元素,注意不能q箋两次调用removeҎ,否则会抛出IllegalStateException.
3.Collection接口的其它方?/strong>
int size():q回当前存储的元素个?br />
boolean isEmpty():当集合中没有元素时返回真
boolean contains(Object obj):当集合中有元素和obj值相{时q回?
boolean containsAll(Collection<?> other):当集合包含另一集合的全部元素时q回?
bBoolean addAll (Collection<? extends E> other):把其它集合中的元素添加到集合中来,当此集合实发生变化时返回真.
boolean remove(Object obj):删除一个和obj值相{的元素,当吻合的元素被删除时q回?
boolean removeAll(Collection<?> other) :从本集合中删除和另一集合中相{的元素,当本集合实发生变化时返回真.(差集)
void clear():清除集合中的所有元?br />
boolean retainAll(Collection<?> other) :从本集合中删除和另一集合中不相等的元?当本集合实发生变化时返回真.(交集)
Object[] toArray()
q回由集合中元素l成的数l?/p>
4.实现了Collection接口的具体类
ArrayList:带下标的队列,增加和收~时都是动态的.
LinkedList:有序队列,在Q意位|插入和删除都是高效?
HashSet:不存在重复的非排序集?
TreeSet:自动排序的不存在重复的集?
LinkedHashSet:保持了插入时序的哈希表
PriorityQueue:优先U队?能有效的删除最元?
5.没有重复元素存在的集合HashSet
HashSet通过哈希码来查找一个元?q比链表的整体查找要q速得?但是由此带来的缺h它不能保持插入时的顺?
׃HashSet靠hash码来识别元素,因此它不能包含重复元?当集合中已经存在值相{的元素?再次d同样的元素HashSet不会发生变化.
Set<String> hashSet=new HashSet<String>();
hashSet.add("Andy");
hashSet.add("Andy");
hashSet.add("Bill");
hashSet.add("Cindy");
hashSet.add("Bill");
hashSet.add("Cindy");
Iterator<String> iter=hashSet.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
输出:
Cindy
Andy
Bill
6.自动排序的集?TreeSet
TreeSet和HashSetcM但它值得一提的一Ҏ无论你以何顺序插入元?元素都能保持正确的排序位|?q时因ؓTreeSet是以U黑树的形式存储数据,在插入时p扑ֈ正确的位|?注意插入TreeSet的元素都要实现Comparable接口.
?
SortedSet<String> treeSet=new TreeSet<String>();
treeSet.add("Andy");
treeSet.add("Andy");
treeSet.add("Bill");
treeSet.add("Cindy");
treeSet.add("Bill");
treeSet.add("Cindy");
Iterator<String> iter=treeSet.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
输出:
Andy
Bill
Cindy
7.优先U队列PriorityQueue
PriorityQueue使用一U名为堆的二叉树高效的存储数?它检索数据是按排序的序而插入则随意,当你调用removeҎ?你总能得到最的元素.但PriorityQueueq不按序排列它的元素,当你遍历时它是不会排序的,q也没有必要. 在制作一个按优先U执行日E安排或事务安排时你应该首先惛_PriorityQueue?br />
?
PriorityQueue<String> pq=new PriorityQueue<String>();
pq.add("Cindy");
pq.add("Felix");
pq.add("Andy");
pq.add("Bill");
Iterator<String> iter=pq.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
while(!pq.isEmpty()){
System.out.println(pq.remove());
}
8.保持插入序的哈希表LinkedHashMap
?.4起Java集合cM多了一个LinkedHashMap,它在HashMap的基上增加了一个双向链?由此LinkedHashMap既能以哈希表的Ş式存储数?又能保持查询时的序.
Map<String,String> members=new LinkedHashMap<String,String>();
members.put("001", "Andy");
members.put("002", "Bill");
members.put("003", "Cindy");
members.put("004", "Dell");
Iterator<String> iter=members.keySet().iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
Iterator<String> iter2=members.values().iterator();
while(iter2.hasNext()){
System.out.println(iter2.next());
}
9.自动按键q行排序的哈希表TreeMap
Map<String,String> members=new TreeMap<String,String>();
members.put("001", "Andy");
members.put("006", "Bill");
members.put("003", "Cindy");
members.put("002", "Dell");
members.put("004", "Felex");
for(Map.Entry<String,String> entry:members.entrySet()){
System.out.println("Key="+entry.getKey()+" Value="+entry.getValue());
}
10.1 集合工具cCollections的方法unmodifiable
此方法构Z个不可更改的集合视图Q当使用其修Ҏ法时会抛Z个UnsupportedOperationException
static Collection<E> unmodifiableCollection(Collection<E> c)
static List<E> unmodifiableList (List<E> c)
static Set<E> unmodifiableSet (Set<E> c)
static SortedSet<E> unmodifiableSortedSet (SortedSet<E> c)
static Map<KQV> unmodifiableMap (Map<KQV> c)
static SortedMap<KQV> unmodifiableSortedMap (SortedMap<KQV> c)
10.2 集合工具cCollections的方法synchronized
此方法会q回一个线E安全的集合视图
static Collection<E> synchronizedCollection(Collection<E> c)
static List<E> synchronizedList (List<E> c)
static Set<E> synchronizedSet (Set<E> c)
static SortedSet<E> synchronizedSortedSet (SortedSet<E> c)
static Map<KQV> synchronizedMap (Map<KQV> c)
static SortedMap<KQV> synchronizedSortedMap (SortedMap<KQV> c)
集合c静态类?/p>
泛型cLC++模版(Template)cL想在java新版?1.5)中的应用体现.当对cd相同的对象操作时泛型是很有用?但其中对象的具体cd直到对类实例化时才能知道.q种方式非常适合于包含关联项目的集合或设计查扄c?
泛型cȝ使用CZ一
/**
* 泛型cȝ例一,成员变量为链?T可以指代Lcȝ?
* @author sitinspring
*
* @date 2007-12-28
*/
public class Service<T>{
// 元素为T的链?br />
private List<T> elements;
/**
* 构造函?q里无须指定cd
*
*/
public Service(){
elements=new ArrayList<T>();
}
/**
* 向链表中dcd为T的元?br />
* @param element
*/
public void add(T element){
elements.add(element);
}
/**
* 打印链表中元?br />
*
*/
public void printElements(){
for(T t:elements){
System.out.println(t);
}
}
/**
* 使用CZ
* @param args
*/
public static void main(String[] args){
// 创徏ServicecȝCZmemberService
Service<Member> memberService=new Service<Member>();
// 向memberService中添加元?br />
memberService.add(new Member("Andy",25));
memberService.add(new Member("Bill",24));
memberService.add(new Member("Cindy",55));
memberService.add(new Member("Felex",35));
// 打印memberService中诸元素
memberService.printElements();
}
}
泛型cȝ使用CZ?/strong>
/**
* 泛型cȝ例二,成员变量为哈希表,k,v可以指代Lcȝ?
* @author sitinspring
*
* @date 2007-12-28
*/
public class ServiceHt<K,V>{
private Map<K,V> elements;
/**
* 向elements中添加元?br />
* @param k
* @param v
*/
public void add(K k,V v){
// 如果elements为空则创建元?br />
if(elements==null){
elements=new Hashtable<K,V>();
}
// 向elements中添加键值对
elements.put(k, v);
}
/**
* 打印哈希表中的元?br />
*
*/
public void printElements(){
Iterator it=elements.keySet().iterator();
while(it.hasNext()){
K k=(K)it.next();
V v=elements.get(k);
System.out.println("?"+k+" ?"+v);
}
}
/**
* 使用CZ
* @param args
*/
public static void main(String[] args){
// 创徏ServicecȝCZmemberService
ServiceHt<String,Member> memberService=new ServiceHt<String,Member>();
// 向memberService中添加元?br />
memberService.add("Andy",new Member("Andy",25));
memberService.add("Bill",new Member("Bill",24));
memberService.add("Cindy",new Member("Cindy",55));
memberService.add("Felex",new Member("Felex",35));
// 打印memberService中诸元素
memberService.printElements();
}
}
字符串比较是javaE序帔R到的问题,新手常用==q行两个字符串比?实际上这时进行的地址比较,不一定会q回正确l果.在java?正确的进行字W串比较的函数Stringcȝequals()函数,q才是真正的值比?
==的真正意?/strong>
Java?==用来比较两个引用是否指向同一个内存对?对于String的实?q行时JVM会尽可能的确保Q何两个具有相同字W串信息的String实例指向同一个内部对?此过E称?#8221;ȝ”(interning),但它不助于每个String实例的比?一个原因是垃圾攉器删除了ȝ?另一个原因是String所在的位置可能被别的String实例所取代.q样的话,==不会返回预想的l果.
下页的示例说明了q个问题:
==和equals比较的示?br />
l论
从上面的例子可以看出,==比较的是地址,在驻留机制的作用?也许q回正确的结?但ƈ不可?q种不确定性会隐藏在阴暗的角落?在你以ؓ万事大吉时给你致命一?
而equal始终q行值比?它一定会q回正确的结?无论在什么情况下.
我们应该C:Z保证E序的正?q行字符串比较时一定要使用equals,而一定不能?=.
异常的体pȝ?/strong>
毫无疑问,在java中异常是对象,它必定承Throwable及其子类.Throwable中含有一个用于描q异常的字符?Exception是Throwable的一个最常用子类,另一个子cLError.而RuntimeExceptionl承自Exception.
异常的种c?/strong>
非检查型异常(Unchecked Exception):
非检查型异常反映了程序中的逻辑错误,不能从运行中合理恢复.
标准的运行时异常和错误构成非查型异常,它们l承自RuntimeException和Error.
非检查型异常不用昄q行捕获.
查型异常(Checked Exception):
q种异常描述了这U情?虽然是异常的,但被认ؓ是可以合理发生的,如果q种异常真的发生?必须调用某种Ҏ处理.
Java异常大多是检查型异常,l承自Exceptionc?你自己定义的异常必须是承Exception的检查型异常.
查型异常必须q行昄捕获.
自定义异?/strong>
l承Exception卛_定义自己的异?以下是一U常见写?br />
public class DBXmlFileReadException extends Exception{
public DBXmlFileReadException(String msg){
super(msg);
}
}
抛出异常
在Java语句?可以用throw语句抛出异常,如throw new NoSuchElementException();
抛出的对象必LThrowablecȝ子类?
抛出异常的策?
1) 如果抛出后不可能得到处理,可以抛出Error.
2) 如果你想让其它类自由选择是否处理q个异常,可以抛出RuntimeException.
3) 如果你要求类的用户必d理这个异?则可以抛出Exception.
异常抛出后的控制权{U?/strong>
一旦发生异?异常发生点后的动作将不会发生.此后要发生的操作不是在catch块和finally?
当异常抛出时,D异常发生的语句和表达式就被称为突然完?语句的突然完成将D调用N渐展开,直到该异常被捕获.
如果该异常没有捕?执行U程中?
Try,catch和finally
异常由包含在try块中的语句捕?
try{
正常执行语句
}
catch(XException e){
异常执行语句一
}
catch(XXException e){
异常执行语句?br />
}
catch(XXXException e){
异常执行语句?br />
}
finally{
中止语句
}
Try中的语句体要么顺利完?要么执行到抛出异?
如果抛出异常,p扑և对应于异常类或其父类的catch子句,如果未能扑ֈ合适的catch子句,异常׃try语句中扩散出?q入到外层可能对它进行处理的try语句.
Catch子句可以有多?只要q些子句捕获的异常类型不?
如果在try中有finally子句,其代码在try把所有其它处理完成之后执?
无论是正常完成或是出现异?甚至是通过return或者breakq样的控制语句结?finally子句L被执?
Catch子句和finally子句在try语句之后臛_有一?不要求全部出?
More…
在catch语句中捕获通用的异常Exception通常不是最佳策?因ؓ它会所有异常进行等同处?
不能把基cd常的catch语句攑ֈ子类异常的catch语句之前,~译器会在运行之前就查出q样的错?
Try…catchҎ个catch语句都从头到检?如果扑ֈ处理同类异常的catch子句,此catch块中的语句将得以执行,而不再处理同层次的其它catch?
如果catch或finally抛出另一个异?E序不会再L查try的catch子句.
Try...catch语句可以嵌套,内层抛出的异常可被外层处?
Throws子句
函数能抛出的查型异常用throws声明,它后面可以是带用逗号隔开的一pd异常cd.仅仅那些在方法中不被捕获的异常必d?
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic
s.defaultReadObject();
// Read in size
int size = s.readInt();
// Initialize header
header = new Entry<E>(null, null, null);
header.next = header.previous = header;
// Read in all elements in the proper order.
for (int i=0; i<size; i++)
addBefore((E)s.readObject(), header);
}
}
More…
Throws子句的约定是严格强制性的,只能抛出throws子句中声明的异常cd,抛出其它cd的异常是非法?不管是直接利用throw,q是调用别的Ҏ间接的抛?
RuntimeException和Error是仅有的不必由throws子句列出的异?
调用函数的函数要么处理对声明的异常进行处?要么也声明同L异常,收到的异常抛向上层.
Ҏ查型异常通常q行的几U处?/strong>
1) 用e.printStackTrace()输出异常信息.
2) 异常记录到日志中以备查,如logger.error(e.getMessage()).
3) 试图q行异常恢复.
4) 告知l护者和用户发生的情?
内部cȝ出现
当进行Java开发时,有时需要实C个仅包含1-2个方法的接口.在AWT和Swing开发中l常出现q种情况,例如当一个displaylg需要一个事件回调方法如一个按钮的ActionListener? 如果使用普通的cL实现此操?最l会得到很多仅在单个位置上用的型c?
内部cȝ于处理这U情?java允许定义内部c?而且可在Gui外用内部类.
内部cȝ定义和实?/strong>
内部cL指在另一个类内部定义的一个类.可以内部类定义Z个类的成?
public class Linker{
public class LinkedNode{
private LinkedNode prev;
private LinkedNode next;
private String content;
public LinkedNode(String content){
this.content=content;
}
}
public Linker(){
LinkedNode first=new LinkedNode("First");
LinkedNode second=new LinkedNode("Second");
first.next=second;
second.prev=first;
}
}
定义在一个类Ҏ中的内部c?/strong>
public class Hapiness{
interface Smiler{
public void smile();
}
public static void main(String[] args){
class Happy implements Smiler{
public void smile(){
System.out.println(":-}");
}
}
Happy happy=new Happy();
happy.smile();
}
}
匿名c?/strong>
对很多情况而言,定义在方法内部的cd意义不大,它可以保持ؓ匿名?E序员关心的只是它的实例?
?
Runnable runner=new Runnable(){
public void run(){
// Run statememnt
}
}
理解匿名c?/strong>
匿名cdƈ不难理解,它只是把cȝ定义q程和实例的创徏q程混合而已,上页的语句实际上相当于如下语?
// 定义c?br />
Public class Runner implements Runnable{
public void run(){
// do sth
}
}
// 创徏实例
Runner runner=new Runner();
使用匿名cȝ{选解耦过E?/p>
需?从公司的职员列表?扑ևh且q龄大于22的成?
传统写法:
List allmembers=company.getMembers();// 取得所有成?br />
List results=new ArrayList();// l果列表
for(Iterator it=allmembers.iterator();it.hasNext();){
Member member=(Member)it.next();
if(member.getAge()>22 && member.isMale()){ // {?q里是把查询条g和遴选过E融合在一?条g一变立卛_得加个分?
results.add(member);
}
}
传统Ҏ的缺?/strong>
q种写法没有?但是不是面向对象的写?它有以下~陷:
1.查询条g和筛选过E没有分?
2.q样写的后果使Company变成了一个失血模型而不是领域模?
3.换查询条件的?上面除了"{?一句有变化外其它都是模板代?重复性很?
使用匿名cd现的OO化查?/p>
真正W合OO的查询应该是q样:
MemberFilter filter1=new MemberFilter(){
public boolean accept(Member member) {
return member.isMale() && member.getAge()>22;
}
};
List ls=company.listMembers(filter1);
q段代码成功的把查询条g作ؓ一个接口分M出去,接口代码如下:
public interface MemberFilter{
public boolean accept(Member member);
}
查询函数的变?/strong>
而类Company增加了这样一个函?
public List searchMembers(MemberFilter memberFilter){
List retval=new ArrayList();
for(Iterator it=members.iterator();it.hasNext();){
Member member=(Member)it.next();
if(memberFilter.accept(member)){
retval.add(member);
}
}
return retval;
}
q就把模板代码归l到了类内部,外面不会重复书写?Company也同时拥有了数据和行?而不是原来的数据容器?
匿名cȝ例子?/strong>
用匿名类处理分类汇ȝҎ 分类汇Ll计中常?举例来说如统计学生成l?及格不及格的归类,分优良中差等U归cȝ,每个单项代码很好?但是如果分类汇ȝ目多了,能一U汇d一个函数吗? 比如说有些科?0分才及?有些U目50分就?有些老师喜欢分优良中差四{?有些老师却喜Ƣ分ABCD;不一而,如果每个都写一个函数无疑是个编写和l护恶梦. 如果我们用匿名类把分cLȝ规则和分cLȝq程分别抽象出来,代码清晰灵zd?以下代码讲述了这个过E?
基本cStudent
public class Student{
private String name;
private int score;
public Student(String name,int score){
this.name=name;
this.score=score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
用于分类汇ȝc?/strong>
它强制子cd现getKey和getvalue两个Ҏ:
public abstract class ClassifyRule {
public Student student;
public ClassifyRule(){
}
public void setStudent(Student student) {
this.student = student;
}
abstract public String getKey();
abstract public int getValue();
}
对Studentq行l计处理的StudentServicec?/strong>
注意getSumҎ,它保留了{选过E?{选规则则不在其中:
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
public class StudentService {
private List<Student> students;
public StudentService() {
students = new ArrayList<Student>();
}
public void add(Student student) {
students.add(student);
}
public Hashtable<String, Integer> getSum(ClassifyRule rule) {
Hashtable<String, Integer> ht = new Hashtable<String, Integer>();
for (Student student : students) {
rule.setStudent(student);
String key = rule.getKey();
int value = rule.getValue();
if (ht.containsKey(key)) {
Integer oldValue = ht.remove(key);
oldValue += value;
ht.put(key, oldValue);
} else {
ht.put(key, value);
}
}
return ht;
}
}
试代码,注意其中{选规则的创徏
public class Test {
public static void main(String[] args) {
// 初始?br />
StudentService service = new StudentService();
service.add(new Student("Andy", 90));
service.add(new Student("Bill", 95));
service.add(new Student("Cindy", 70));
service.add(new Student("Dural", 85));
service.add(new Student("Edin", 60));
service.add(new Student("Felix", 55));
service.add(new Student("Green", 15));
// 60分及格筛?br />
ClassifyRule rule60 = new ClassifyRule() {
public String getKey() {
return student.getScore() >= 60 ? "及格" : "不及?;
}
public int getValue() {
return 1;
}
};
System.out.println("60分及格筛?);
printHt(service.getSum(rule60));
// 50分及格筛?br />
ClassifyRule rule50 = new ClassifyRule() {
public String getKey() {
return student.getScore() >= 50 ? "及格" : "不及?;
}
public int getValue() {
return 1;
}
};
System.out.println("\n50分及格筛?);
printHt(service.getSum(rule50));
// ?优良中差"{
ClassifyRule ruleCn = new ClassifyRule() {
public String getKey() {
String retval = "";
int score = student.getScore();
if (score >= 90) {
retval = "?;
} else if (score >= 80) {
retval = "?;
} else if (score >= 60) {
retval = "?;
} else if (score > 0) {
retval = "?;
}
return retval;
}
public int getValue() {
return 1;
}
};
试代码
System.out.println("\n分优良中差等U筛?);
printHt(service.getSum(ruleCn));
// ?ABCD"{
ClassifyRule ruleWest = new ClassifyRule() {
public String getKey() {
String retval = "";
int score = student.getScore();
if (score >= 90) {
retval = "A";
} else if (score >= 80) {
retval = "B";
} else if (score >= 60) {
retval = "C";
} else if (score > 0) {
retval = "D";
}
return retval;
}
public int getValue() {
return 1;
}
};
System.out.println("\n分ABCD{{?);
printHt(service.getSum(ruleWest));
}
private static void printHt(Hashtable ht) {
for (Iterator it = ht.keySet().iterator(); it.hasNext();) {
String key = (String) it.next();
Integer value = (Integer) ht.get(key);
System.out.println("Key=" + key + " Value=" + value);
}
}
}
试l果如下:
60分及格筛?br />
Key=及格 Value=5
Key=不及?Value=2
50分及格筛?br />
Key=及格 Value=6
Key=不及?Value=1
分优良中差等U筛?br />
Key=?Value=2
Key=?Value=1
Key=?Value=2
Key=?Value=2
分ABCD{{?br />
Key=A Value=2
Key=D Value=2
Key=C Value=2
Key=B Value=1
后记
内部cM叫嵌套类,一般不提倡书?但它在java核心cM都存?如接口Map中的Entry,我们应该了解q能解读q种Ҏ.
匿名cȝ对而言有用得多,在解耦合和事件回调注册中很常?大家应该对它的运用融会诏?
Socket概述
Socket的重要API
一个Socket通信的例?/p>
Socket是什么?
Socket通常也称?#8220;套接?#8221;Q用于描qIP地址和端口,是一个通信铄句柄。应用程序通常通过“套接?#8221;向网l发求或者应{网l请求?
在java中,Socket和ServerSocketcd位于java.net包中。ServerSocket用于服务器端QSocket是徏立网l连接时使用的。在q接成功Ӟ应用E序两端都会产生一个Socket实例Q操作这个实例,完成所需的会话?br />
对于一个网l连接来_套接字是q等的,q没有差别,不因为在服务器端或在客户端而生不同别?
Socket的直观描q?/strong>
Socket的英文原义是“?#8221;?#8220;插”。在q里作ؓq程通信机制Q取后一U意义。socket非常cM于电话插座。以一个国家电话|ؓ例。电话的通话双方相当于相互通信?个进E,区号是它的网l地址Q区内一个单位的交换机相当于一C机,L分配l每个用L局内号码相当于socket受Q何用户在通话之前Q首先要占有一部电话机Q相当于甌一个socketQ同时要知道Ҏ的号码,相当于对Ҏ一个固定的socket。然后向Ҏ拨号呼叫Q相当于发出q接h(假如Ҏ不在同一区内Q还要拨Ҏ区号Q相当于l出|络地址)。对方假如在场ƈI闲(相当于通信的另一L开Z可以接受q接h)Q拿L话话{,双方可以正式通话Q相当于q接成功。双斚w话的过E,是一方向电话机发Z号和Ҏ从电话机接收信号的过E,相当于向socket发送数据和从socket接收数据。通话l束后,一ҎL话机相当于关闭socketQ撤消连接?br /> 在电话系l中Q一般用户只能感受到本地电话机和Ҏ电话L的存在,建立通话的过E,话音传输的过E以及整个电话系l的技术细节对他都是透明的,q也与socket机制非常怼。socket利用|间|通信设施实现q程通信Q但它对通信设施的细节毫不关心,只要通信设施能提供够的通信能力Q它满了?br /> xQ我们对socketq行了直观的描述。抽象出来,socket实质上提供了q程通信的端炏V进E通信之前Q双斚w先必d自创Z个端点,否则是没有办法徏立联pdƈ怺通信的。正如打电话之前Q双方必d自拥有一台电话机一栗?/p>
socket 是面向客?服务器模型而设计的
socket 是面向客?服务器模型而设计的Q针对客户和服务器程序提供不同的socket pȝ调用。客户随机申请一个socket (相当于一个想打电话的人可以在M一台入|电话上拨号呼叫)Q系lؓ之分配一个socketP服务器拥有全局公认?socket QQ何客户都可以向它发出q接h和信息请?相当于一个被呼叫的电话拥有一个呼叫方知道的电话号??br /> socket利用客户/服务器模式y妙地解决了进E之间徏立通信q接的问题。服务器socket为全局所公认非常重要。读者不妨考虑一下,两个完全随机的用戯E之间如何徏立通信Q假如通信双方没有M一方的socket 固定Q就好比打电话的双方彼此不知道对方的电话LQ要通话是不可能的?/p>
Socket的应?/strong>
Socket 接口是访?Internet 使用得最q泛的方法?如果你有一台刚配好TCP/IP协议的主机,其IP地址?02.120.127.201Q?此时在另一C机或同一CZ执行ftp 202.120.127.201Q显然无法徏立连接。因"202.120.127.201" q台L没有q行FTP服务软g。同P 在另一台或同一CZq行览软g 如NetscapeQ输?http://202.120.127.201"Q也无法建立q接。现在,如果在这CZq行一个FTP服务软gQ该软g打开一个SocketQ?q将其绑定到21端口Q,再在q台L上运行一个Web 服务软gQ该软g打开另一个SocketQƈ其l定?0端口Q。这P在另一C机或同一CZ执行ftp 202.120.127.201QFTP客户软g通过21端口来呼叫主Z由FTP 服务软g提供的SocketQ与其徏立连接ƈ对话。而在netscape中输?http://202.120.127.201"Ӟ通过80端口来呼叫主Z由Web服务软g提供的SocketQ与其徏 立连接ƈ对话?在Internet上有很多q样的主机,q些L一般运行了多个服务软gQ同时提供几U服务。每U服务都打开一个SocketQƈl定C个端口上Q不同的端口对应于不同的服务。Socket正如其英文原意那P象一个多孔插座。一C机犹如布满各U插座的戉KQ每个插座有一个编P有的插提供220伏交电Q?有的提供110伏交电Q有的则提供有线电视节目?客户软g插头插C同编L插Q就可以得到不同的服务?
重要的Socket API
acceptҎ用于产生“d”Q直到接受到一个连接,q且q回一个客L的Socket对象实例?#8220;d”是一个术语,它ɽE序q行暂时“停留”在这个地方,直到一个会话生,然后E序l箋Q通常“d”是由循环产生的?br />
getInputStreamҎ获得|络q接输入Q同时返回一个IutputStream对象实例?
getOutputStreamҎq接的另一端将得到输入Q同时返回一个OutputStream对象实例?注意Q其中getInputStream和getOutputStreamҎ均会产生一个IOExceptionQ它必须被捕P因ؓ它们q回的流对象Q通常都会被另一个流对象使用?
一个Server-Client模型的程序的开发原?/strong>
服务器,使用ServerSocket监听指定的端口,端口可以随意指定Q由?024以下的端口通常属于保留端口Q在一些操作系l中不可以随意用,所以徏议用大?024的端口)Q等待客戯接请求,客户q接后,会话产生Q在完成会话后,关闭q接?br /> 客户端,使用Socket对网l上某一个服务器的某一个端口发接请求,一旦连接成功,打开会话Q会话完成后Q关闭Socket。客L不需要指定打开的端口,通常临时的、动态的分配一?024以上的端口?
服务器端代码
public class ResponseThread implements Runnable {
private static Logger logger = Logger.getLogger(ResponseThread.class);
// 用于与客L通信的Socket
private Socket incomingSocket;
/**
* 构造函?用以incomingSocket传入
* @param incomingSocket
*/
public ResponseThread(Socket incomingSocket) {
this.incomingSocket = incomingSocket;
}
public void run() {
try {
try {
// 输入?br />
InputStream inStream = incomingSocket.getInputStream();
// 输出?br />
OutputStream outStream = incomingSocket.getOutputStream();
// 文本扫描?br />
Scanner in = new Scanner(inStream);
// 输出打印器
PrintWriter out = new PrintWriter(outStream,true);
while (in.hasNextLine()) {
String line = in.nextLine();
logger.info("从客L获得文字:"+line);
String responseLine=line+" 门朝大v 三河合水万年?;
out.println(responseLine);
logger.info("向客L送出文字:"+responseLine);
}
} finally {
incomingSocket.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
try {
// 建立一个对2009端口q行监听的ServerSocketq开始监?br />
ServerSocket socket=new ServerSocket(2009);
logger.info("开始监?);
while(true){
// 产生d,直到客户端连接过来才会往下执?br />
logger.info("d?{待来自客户端的q接h");
Socket incomingSocket=socket.accept();
// 执行到这里客L已经q接q来?incomingSocket是创徏出来和远E客LSocketq行通信的Socket
logger.info("获得来自"+incomingSocket.getInetAddress()+"的请?");
// 开辟一个线E?q把incomingSocket传进?在这个线E中服务器和客户机开始通信
ResponseThread responseThread=new ResponseThread(incomingSocket);
// 启动U程
Thread thread=new Thread(responseThread);
thread.start();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
客户端代?/strong>
/**
* Socket客户端类
* @author sitinspring
*
* @date 2008-2-26
*/
public class SocketClient{
private static Logger logger = Logger.getLogger(ResponseThread.class);
public static void main(String[] args){
try {
// 建立一个Socket,试图q接C?27.0.0.1的主机的2009端口,如果服务器已l在监听则会接收到这个请?acceptҎ产生一个和q边通信的Socket
Socket socket=new Socket("127.0.0.1",2009);
logger.info("客户端向服务器发赯?");
try {
// 输入?br />
InputStream inStream = socket.getInputStream();
// 输出?br />
OutputStream outStream = socket.getOutputStream();
/**
* 向服务器发送文?br />
*/
// 输出打印器
PrintWriter out = new PrintWriter(outStream);
out.println("地震高岗 一z溪山千古秀");
out.flush();
/**
* 接收服务器发送过来的文字
*/
// 文本扫描?br />
Scanner in = new Scanner(inStream);
while (in.hasNextLine()) {
String line = in.nextLine();
logger.info("客户端获得响应文?"+ line);
}
} finally {
// 关闭Socket
socket.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
1.Date转化为常见的日期旉字符?br />
q里我们需要用到java.text.SimpleDateFormatcȝformatҎQ其中可以指定年月日时分U的模式字符串格式?br />
Date date = new Date();
Format formatter = new SimpleDateFormat("yyyyqMM月dd日HH时mm分ssU?);
System.out.println("转化的时间等?"+formatter.format(date));
其中
yyyy表示四位数的q䆾
MM表示两位数的月䆾
dd表示两位数的日期
HH表示两位数的时
mm表示两位数的分钟
ss表示两位数的U钟
2.文本日期{化ؓDate以方便比?/em>
文本日期的优势在于便于记忆,Ҏ处理Q但~点是不方便比较Q这时我们需要借助SimpleDateFormat的parseҎ得到Date对象再进行比较,实例如下Q?br />
String strDate1="2004q???;
String strDate2="2004q?0??;
SimpleDateFormat myFormatter = new SimpleDateFormat("yyyyqMM月dd?);
java.util.Date date1 = myFormatter.parse(strDate1);
java.util.Date date2 = myFormatter.parse(strDate2);
// Date比较能得出正结?br />
if(date2.compareTo(date1)>0){
System.out.println(strDate2+">"+strDate1);
}
// 字符串比较得不出正确l果
if(strDate2.compareTo(strDate1)>0){
System.out.println(strDate2+">"+strDate1);
}
3.文本日期{化ؓDate以方便计?/em>
文本日期的另一个大问题是不方便计算Q比如计?008q??日的100天后是那一天就不容易,此时我们q是需要把文本日期转化为Dateq行计算Q再把结果{化ؓ文本日期Q?br />
SimpleDateFormat myFormatter = new SimpleDateFormat("yyyyqMM月dd?);
java.util.Date date = myFormatter.parse("2008q???);
date.setDate(date.getDate()+100);
Format formatter = new SimpleDateFormat("yyyyqMM月dd?);
// 得到2008q?4?8?br /> System.out.println("100天后?+formatter.format(date));
在运行过E中,应用E序可能遭遇各种严重E度不同的问?异常提供了一U在不弄q序的情况下检查错误的巧妙方式.它也提供了一U直接报告错误的机制,而不必检查标志或者具有此作用的域.异常把方法能够报告的错误作ؓҎU定的一个显式部?
异常能够被程序员看到,q译器?q且由重载方法的子类保留.
如果遇到意外的错误将抛出异常,然后异常被方法调用栈上的子句捕获.如果异常未被捕获,导致执行线E的l止.
异常的体pȝ?/strong>
毫无疑问,在java中异常是对象,它必定承Throwable及其子类.Throwable中含有一个用于描q异常的字符?Exception是Throwable的一个最常用子类,另一个子cLError.而RuntimeExceptionl承自Exception.
异常的种c?/strong>
非检查型异常(Unchecked Exception):
非检查型异常反映了程序中的逻辑错误,不能从运行中合理恢复.
标准的运行时异常和错误构成非查型异常,它们l承自RuntimeException和Error.
非检查型异常不用昄q行捕获.
查型异常(Checked Exception):
q种异常描述了这U情?虽然是异常的,但被认ؓ是可以合理发生的,如果q种异常真的发生?必须调用某种Ҏ处理.
Java异常大多是检查型异常,l承自Exceptionc?你自己定义的异常必须是承Exception的检查型异常.
查型异常必须q行昄捕获.
自定义异?/strong>
l承Exception卛_定义自己的异?以下是一U常见写?br />
public class DBXmlFileReadException extends Exception{
public DBXmlFileReadException(String msg){
super(msg);
}
}
抛出异常
在Java语句?可以用throw语句抛出异常,如throw new NoSuchElementException();
抛出的对象必LThrowablecȝ子类?
抛出异常的策?
1) 如果抛出后不可能得到处理,可以抛出Error.
2) 如果你想让其它类自由选择是否处理q个异常,可以抛出RuntimeException.
3) 如果你要求类的用户必d理这个异?则可以抛出Exception.
异常抛出后的控制权{U?/strong>
一旦发生异?异常发生点后的动作将不会发生.此后要发生的操作不是在catch块和finally?
当异常抛出时,D异常发生的语句和表达式就被称为突然完?语句的突然完成将D调用N渐展开,直到该异常被捕获.
如果该异常没有捕?执行U程中?
Try,catch和finally
异常由包含在try块中的语句捕?
try{
正常执行语句
}
catch(XException e){
异常执行语句一
}
catch(XXException e){
异常执行语句?br />
}
catch(XXXException e){
异常执行语句?br />
}
finally{
中止语句
}
Try中的语句体要么顺利完?要么执行到抛出异?
如果抛出异常,p扑և对应于异常类或其父类的catch子句,如果未能扑ֈ合适的catch子句,异常׃try语句中扩散出?q入到外层可能对它进行处理的try语句.
Catch子句可以有多?只要q些子句捕获的异常类型不?
如果在try中有finally子句,其代码在try把所有其它处理完成之后执?
无论是正常完成或是出现异?甚至是通过return或者breakq样的控制语句结?finally子句L被执?
Catch子句和finally子句在try语句之后臛_有一?不要求全部出?
More…
在catch语句中捕获通用的异常Exception通常不是最佳策?因ؓ它会所有异常进行等同处?
不能把基cd常的catch语句攑ֈ子类异常的catch语句之前,~译器会在运行之前就查出q样的错?
Try…catchҎ个catch语句都从头到检?如果扑ֈ处理同类异常的catch子句,此catch块中的语句将得以执行,而不再处理同层次的其它catch?
如果catch或finally抛出另一个异?E序不会再L查try的catch子句.
Try...catch语句可以嵌套,内层抛出的异常可被外层处?
Throws子句
函数能抛出的查型异常用throws声明,它后面可以是带用逗号隔开的一pd异常cd.仅仅那些在方法中不被捕获的异常必d?
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic
s.defaultReadObject();
// Read in size
int size = s.readInt();
// Initialize header
header = new Entry<E>(null, null, null);
header.next = header.previous = header;
// Read in all elements in the proper order.
for (int i=0; i<size; i++)
addBefore((E)s.readObject(), header);
}
}
More…
Throws子句的约定是严格强制性的,只能抛出throws子句中声明的异常cd,抛出其它cd的异常是非法?不管是直接利用throw,q是调用别的Ҏ间接的抛?
RuntimeException和Error是仅有的不必由throws子句列出的异?
调用函数的函数要么处理对声明的异常进行处?要么也声明同L异常,收到的异常抛向上层.
Ҏ查型异常通常q行的几U处?br />
1) 用e.printStackTrace()输出异常信息.
2) 异常记录到日志中以备查,如logger.error(e.getMessage()).
3) 试图q行异常恢复.
4) 告知l护者和用户发生的情?
当进行Java开发时,有时需要实C个仅包含1-2个方法的接口.在AWT和Swing开发中l常出现q种情况,例如当一个displaylg需要一个事件回调方法如一个按钮的ActionListener? 如果使用普通的cL实现此操?最l会得到很多仅在单个位置上用的型c?
内部cȝ于处理这U情?java允许定义内部c?而且可在Gui外用内部类.
内部cȝ定义和实?/strong>
内部cL指在另一个类内部定义的一个类.可以内部类定义Z个类的成?
public class Linker{
public class LinkedNode{
private LinkedNode prev;
private LinkedNode next;
private String content;
public LinkedNode(String content){
this.content=content;
}
}
public Linker(){
LinkedNode first=new LinkedNode("First");
LinkedNode second=new LinkedNode("Second");
first.next=second;
second.prev=first;
}
}
定义在一个类Ҏ中的内部c?/p>
public class Hapiness{
interface Smiler{
public void smile();
}
public static void main(String[] args){
class Happy implements Smiler{
public void smile(){
System.out.println(":-}");
}
}
Happy happy=new Happy();
happy.smile();
}
}
匿名c?/strong>
对很多情况而言,定义在方法内部的cd意义不大,它可以保持ؓ匿名?E序员关心的只是它的实例?
?
Runnable runner=new Runnable(){
public void run(){
// Run statememnt
}
}
理解匿名c?/strong>
匿名cdƈ不难理解,它只是把cȝ定义q程和实例的创徏q程混合而已,上页的语句实际上相当于如下语?
// 定义c?br />
Public class Runner implements Runnable{
public void run(){
// do sth
}
}
// 创徏实例
Runner runner=new Runner();
使用匿名cȝ{选解耦过E?/strong>
需?从公司的职员列表?扑ևh且q龄大于22的成?
传统写法:
List allmembers=company.getMembers();// 取得所有成?br />
List results=new ArrayList();// l果列表
for(Iterator it=allmembers.iterator();it.hasNext();){
Member member=(Member)it.next();
if(member.getAge()>22 && member.isMale()){ // {?q里是把查询条g和遴选过E融合在一?条g一变立卛_得加个分?
results.add(member);
}
}
传统Ҏ的缺?/strong>
q种写法没有?但是不是面向对象的写?它有以下~陷:
1.查询条g和筛选过E没有分?
2.q样写的后果使Company变成了一个失血模型而不是领域模?
3.换查询条件的?上面除了"{?一句有变化外其它都是模板代?重复性很?
使用匿名cd现的OO化查?/strong>
真正W合OO的查询应该是q样:
MemberFilter filter1=new MemberFilter(){
public boolean accept(Member member) {
return member.isMale() && member.getAge()>22;
}
};
List ls=company.listMembers(filter1);
q段代码成功的把查询条g作ؓ一个接口分M出去,接口代码如下:
public interface MemberFilter{
public boolean accept(Member member);
}
查询函数的变?/p>
而类Company增加了这样一个函?
public List searchMembers(MemberFilter memberFilter){
List retval=new ArrayList();
for(Iterator it=members.iterator();it.hasNext();){
Member member=(Member)it.next();
if(memberFilter.accept(member)){
retval.add(member);
}
}
return retval;
}
q就把模板代码归l到了类内部,外面不会重复书写?Company也同时拥有了数据和行?而不是原来的数据容器?
匿名cȝ例子?/strong>
用匿名类处理分类汇ȝҎ 分类汇Ll计中常?举例来说如统计学生成l?及格不及格的归类,分优良中差等U归cȝ,每个单项代码很好?但是如果分类汇ȝ目多了,能一U汇d一个函数吗? 比如说有些科?0分才及?有些U目50分就?有些老师喜欢分优良中差四{?有些老师却喜Ƣ分ABCD;不一而,如果每个都写一个函数无疑是个编写和l护恶梦. 如果我们用匿名类把分cLȝ规则和分cLȝq程分别抽象出来,代码清晰灵zd?以下代码讲述了这个过E?
基本cStudent
public class Student{
private String name;
private int score;
public Student(String name,int score){
this.name=name;
this.score=score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
用于分类汇ȝc?/p>
它强制子cd现getKey和getvalue两个Ҏ:
public abstract class ClassifyRule {
public Student student;
public ClassifyRule(){
}
public void setStudent(Student student) {
this.student = student;
}
abstract public String getKey();
abstract public int getValue();
}
对Studentq行l计处理的StudentServicec?/p>
注意getSumҎ,它保留了{选过E?{选规则则不在其中:
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
public class StudentService {
private List<Student> students;
public StudentService() {
students = new ArrayList<Student>();
}
public void add(Student student) {
students.add(student);
}
public Hashtable<String, Integer> getSum(ClassifyRule rule) {
Hashtable<String, Integer> ht = new Hashtable<String, Integer>();
for (Student student : students) {
rule.setStudent(student);
String key = rule.getKey();
int value = rule.getValue();
if (ht.containsKey(key)) {
Integer oldValue = ht.remove(key);
oldValue += value;
ht.put(key, oldValue);
} else {
ht.put(key, value);
}
}
return ht;
}
}
试代码,注意其中{选规则的创徏
public class Test {
public static void main(String[] args) {
// 初始?br />
StudentService service = new StudentService();
service.add(new Student("Andy", 90));
service.add(new Student("Bill", 95));
service.add(new Student("Cindy", 70));
service.add(new Student("Dural", 85));
service.add(new Student("Edin", 60));
service.add(new Student("Felix", 55));
service.add(new Student("Green", 15));
// 60分及格筛?br />
ClassifyRule rule60 = new ClassifyRule() {
public String getKey() {
return student.getScore() >= 60 ? "及格" : "不及?;
}
public int getValue() {
return 1;
}
};
System.out.println("60分及格筛?);
printHt(service.getSum(rule60));
// 50分及格筛?br />
ClassifyRule rule50 = new ClassifyRule() {
public String getKey() {
return student.getScore() >= 50 ? "及格" : "不及?;
}
public int getValue() {
return 1;
}
};
System.out.println("\n50分及格筛?);
printHt(service.getSum(rule50));
// ?优良中差"{
ClassifyRule ruleCn = new ClassifyRule() {
public String getKey() {
String retval = "";
int score = student.getScore();
if (score >= 90) {
retval = "?;
} else if (score >= 80) {
retval = "?;
} else if (score >= 60) {
retval = "?;
} else if (score > 0) {
retval = "?;
}
return retval;
}
public int getValue() {
return 1;
}
};
试代码
System.out.println("\n分优良中差等U筛?);
printHt(service.getSum(ruleCn));
// ?ABCD"{
ClassifyRule ruleWest = new ClassifyRule() {
public String getKey() {
String retval = "";
int score = student.getScore();
if (score >= 90) {
retval = "A";
} else if (score >= 80) {
retval = "B";
} else if (score >= 60) {
retval = "C";
} else if (score > 0) {
retval = "D";
}
return retval;
}
public int getValue() {
return 1;
}
};
System.out.println("\n分ABCD{{?);
printHt(service.getSum(ruleWest));
}
private static void printHt(Hashtable ht) {
for (Iterator it = ht.keySet().iterator(); it.hasNext();) {
String key = (String) it.next();
Integer value = (Integer) ht.get(key);
System.out.println("Key=" + key + " Value=" + value);
}
}
}
试l果如下:
60分及格筛?br />
Key=及格 Value=5
Key=不及?Value=2
50分及格筛?br />
Key=及格 Value=6
Key=不及?Value=1
分优良中差等U筛?br />
Key=?Value=2
Key=?Value=1
Key=?Value=2
Key=?Value=2
分ABCD{{?br />
Key=A Value=2
Key=D Value=2
Key=C Value=2
Key=B Value=1
结
内部cM叫嵌套类,一般不提倡书?但它在java核心cM都存?如接口Map中的Entry,我们应该了解q能解读q种Ҏ.
匿名cȝ对而言有用得多,在解耦合和事件回调注册中很常?大家应该对它的运用融会诏?
Boolean function:布尔函数
Bytecode:字节?/p>
Casting:cd强制转换
Channel:频道
ClassCastException:当一个对象引用强制{换程一个不兼容的类型时出现的异?
Collection:一个表C对象组或集合的接口
CSV(Comma-separated values):一U用于存储表格数据的文g形式
Complier:~译?br />
Compose:合成
Composite function:复合函数,通过多个函数创徏的一个函?/p>
Decimal:十进?br />
Deep:深度
DOM(Document Object Model):文对象模型,一U采用树形表C来处理XML数据的API.
Database:数据?/p>
Edge:?br />
Element:元素,XML文档中的一个节?
Encapsulation:装
End tag:l束标签
Enum:枚D
Escaping:转义
Function:函数
Fuzzy search:模糊搜烦
Generic:泛型
Graph:?br />
GUI:用户囑Ş界面
Grid computing:|格计算
Group:l?/p>
HashMap:一个将键值映到值的查找对象
Heap memory:堆内?br />
HTML(Hyper Text Markup Language):文本标记语a
HTTP(HyperText Tranfer Protocol):文本传输协?/p>
Inheritance:l承
Inner class:内部c?br />
Iterator:允许q代CQ何Collectioncȝ一个接?/p>
JDBC(Java Database Connectivity):java数据库连?一U属于Java核心库的用于操作关系数据库的API.
JDK(Java Development Kit):java开发工具包
JRE(Java Runtime Environment):javaq行时环?br />
JSP(Java Server Page):java服务?br />
JVM(Java Virtual machine):Java虚拟?br />
JavaDoc:属于JDK的一U文生成工?br />
JavaScript:q行于客L,用于HTML处理的一U轻量教本语言,语法部分cM于Java.
Layout:布局
Lexical analysis:词法分析
Linked List:链表
Matcher:一个用于正则表辑ּ模式匚w的Javac?br /> Metadata:元数?br /> Millisecond:微妙
Namespace:命名I间
Neural network:经|络
Node:节点
Object-oriented programmming:面向对象~程
Object pool:可以从中获得对象的一个实例池
Origin:原点
Override:子类覆写父类的方?/p>
Parser:分析?br />
Patch:补丁
Pattern:模式
Polymorphism:多态?br />
Port:端口
Predicate:谓词
Prefix:前缀
Procedural language:q程式语a,如C
Property:属?/p>
Real time:实时
Recursive:递归
Reference:引用
Reflection:反射
Regular expression:正则表达?br />
Relative:相对
Resource:资源
Runnable:多线E编E用的一个接?
Syntax:语法
Screen scraping:屏幕抓取
Split:分割
State:状?br />
Static:静?br />
Sequence:序列
Swing:构徏在AWT上更高的图形用L?br />
Synchronized:同步,用于U程安全协作的技?/p>
Tag:标签
Thread:q程
Tiger : SunlJava1.5的代?br />
Token:标记
Translation:q移
Triple:三元l?br />
Type:cd
Unicode:l一字符界面
Unit testing:单元试
Visitor pattern:讉K者模?/p>
WAR(Web Application Archive):Web应用E序归
Web Service:Web服务
Weight:?br />
Well-formed:格式良好?br />
Whitespace:I白W?/p>
XML(Extensible Markup Language):一U描q分U数据结构的文本标记语言
Java2中包含了6个集合接?q些接口的通用目的实现c?以及一个集合实用类Collections,共同l成了集合框架的核心.
6个集合接口如?
Collection及其以下的List,Set,以及Set下的SortedSet
Map及其以下的SortedMap
链表的通用实现
ArrayList:U程不安全的动态数l类,扚w查询速度?单个查找速度?
Vector:U程安全的动态数l类,效率比ArrayList低下.
LinkedList:动态链表类,适于在队列首NJ增删成员的场合.
链表的创?/strong>
List<Member> ls=new ArrayList<Member>();// 1.5版本及以?/p>
List ls=new ArrayList();// 1.5版本以下
之所以将lscd指定为List<Member>而不是ArrayList<Member>是因?如果情况变化, ArrayList需要修ҎVector或LinkedList时无M改其它代?仅修改实例类型即?
向List中添加元?/p>
d单个元素
ls.add(new Member("Andy",21));
从别的链表中d多个元素
List<Member> ls2=new ArrayList<Member>();
ls2.add(new Member("Felex",21));
ls2.add(new Member("Gates",23));
ls.addAll(ls2);
注意:
1.5及其以上版本?d的元素必d定义时一?如ls的类型是List<Member>,那么向其中添加的元素必须是Member或其子类.
1.5以下版本?Ҏ加的元素不作?只要是Object卛_,如果是基本类型则需装箱成类cd.如ls.add(new Integer(8));
删除链表中元?/strong>
ls.remove(member); // 直接删除对象,member=new Member("Edin",28)
ls.remove(2); // 删除W三个元?br />
ls.clear(); // 已有数据全部清?/p>
寚w表进行遍?/strong>
1) 1.5中独有的遍历Ҏ,代码最?使用最方便
for(Member member:ls){
// member是依次取出的每个元?br />
}
2) 常规Ҏ,多用于需要取得下标的场合,各版本均适用
for(int i=0;i<ls.size();i++){
Member member=ls.get(i);// member是依次取出的每个元? 1.5及其以上版本适用, ls.size()为链表长?br />
Member member=(Member)ls.get(i);// 1.5以下版本适用
}
3) 使用Iterator寚w表进行遍历的Ҏ,各版本均适用
for(Iterator it=ls.iterator();it.hasNext();){
Member member=(Member)it.next();
}
链表的其它常用的Ҏ
ls.contains(Object o);// q回链表中是否包含某元素
ls.indexOf(Object o);// q回对象o是链表中的第几号元素
isEmpty();// q回链表中是否有元素
寚w表进行排?br />
1Q让List中元素必dl实现Comparable接口:
public class Member implements Comparable {
private String name;
private int age;
public Member(String name, int age) {
this.name = name;
this.age = age;
}
public int compareTo(Object obj) {
Member another = (Member) obj;
return this.name.compareTo(another.name);// 按名U排?如果是this.age-another.age则按q龄排序
}
public String toString(){
return "Member name="+name+" age="+age;
}
}
2Q排序过E?br /> List<Member> ls=new ArrayList<Member>();
ls.add(new Member("Felex",21));
ls.add(new Member("Gates",23));
ls.add(new Member("Andy",21));
ls.add(new Member("Bill",23));
ls.add(new Member("Cindy",24));
ls.add(new Member("Dell",27));
Collections.sort(ls);
for(Member member:ls){
System.out.println(member);
}
输出:
Member name=Andy age=21
Member name=Bill age=23
Member name=Cindy age=24
Member name=Dell age=27
Member name=Felex age=21
Member name=Gates age=23
// 如果需要逆序可以使用Collections.reverse(ls);
链表与数l之间的转换
1) List转换成数l?br /> List<String> ls=new ArrayList<String>();
ls.add("Felex");
ls.add("Gates");
ls.add("Andy");
ls.add("Bill");
ls.add("Cindy");
ls.add("Dell");
Object[] arr=ls.toArray();
for(Object obj:arr){
System.out.println((Object)obj);
}
输出?
Felex
Gates
Andy
Bill
Cindy
Dell
2) 数组转换成List
String[] arr={"Andy","Bill","Cindy","Dell"};
List<String> ls=Arrays.asList(arr);
for(String str:ls){
System.out.println(str);
}
输出:
Andy
Bill
Cindy
Dell
以哈希表的Ş式存储数?数据的Ş式是键值对.
特点:
查找速度?遍历相对?br />
键g能有I指针和重复数据
创徏
Hashtable<Integer,String> ht=new Hashtable<Integer,String>();
d?/strong>
ht.put(1,"Andy");
ht.put(2,"Bill");
ht.put(3,"Cindy");
ht.put(4,"Dell");
ht.put(5,"Felex");
ht.put(6,"Edinburg");
ht.put(7,"Green");
取?/strong>
String str=ht.get(1);
System.out.println(str);// Andy
寚wq行遍历
Iterator it = ht.keySet().iterator();
while (it.hasNext()) {
Integer key = (Integer)it.next();
System.out.println(key);
}
对D行遍?/strong>
Iterator it = ht.values().iterator();
while (it.hasNext()) {
String value =(String) it.next();
System.out.println(value);
}
取Hashtable记录?/strong>
Hashtable<Integer,String> ht=new Hashtable<Integer,String>();
ht.put(1,"Andy");
ht.put(2,"Bill");
ht.put(3,"Cindy");
ht.put(4,"Dell");
ht.put(5,"Felex");
ht.put(6,"Edinburg");
ht.put(7,"Green");
int i=ht.size();// 7
删除元素
Hashtable<Integer,String> ht=new Hashtable<Integer,String>();
ht.put(1,"Andy");
ht.put(2,"Bill");
ht.put(3,"Cindy");
ht.put(4,"Dell");
ht.put(5,"Felex");
ht.put(6,"Edinburg");
ht.put(7,"Green");
ht.remove(1);
ht.remove(2);
ht.remove(3);
ht.remove(4);
System.out.println(ht.size());// 3
Iterator it = ht.values().iterator();
while (it.hasNext()) {
// Get value
String value =(String) it.next();
System.out.println(value);
}
输出:
3
Green
Edinburg
Felex
c?抽象cM接口都是Java中实现承和多态的手段.
cd调的是?br />
接口的是规范
抽象cd而有?/p>
什么是接口
接口是一U特D的c?它只有方法定义而没有实?实现的Q务完全交l子cd?
接口以interface标志.
l承接口用implements关键字实?
接口可以l承接口.
接口可以有成?但成员全是public static finalcd?
接口没有构造函?
接口lJava提供了多l承机制
接口例子—Knockable
public interface Knockable{
public static final String Sound="Bang!";
public void knock();
}
接口例子-实现接口
public class Hammer implements Knockable{
public void knock(){
System.out.println(Sound);
}
}
接口例子-实现多个接口
public interface Knockable{
public static final String Sound="Bang!";
public void knock();
}
public interface Clampable {
public void clamp();
}
public class Pliers implements Knockable,Clampable{
public void clamp(){
// do sth
}
public void knock(){
System.out.println(Sound);
}
}
接口l承接口例子
public interface Knockable{
public static final String Sound="Bang!";
public void knock();
}
public interface Hitable extends Knockable{
public void hit();
}
public class Stick implements Hitable{
public void knock(){
// do sth
}
public void hit(){
// do sth
}
}
什么叫抽象c?/strong>
cMh抽象Ҏ的类为抽象类.抽象Ҏ以abstract在函数前修饰,只有定义没有实现,q一点和接口一?
抽象cdcd前需加上abstract修饰W以标识.
抽象cM能生成实?
抽象cȝl承性和cM?
抽象cȝ实现
public abstract class Gun{
protected String cannon;
protected List<Bullet> bullets;
public abstract void shoot();
public void addBullet(Bullet bullet){
if(bullets==null){
bullets=new LinkedList<Bullet>();
}
bullets.add(bullet);
}
}
l承抽象c?/strong>
public class Rifle extends Gun{
public void shoot(){
// Shoot Sth
}
public void reload(){
if(bullets!=null){
bullets.clear();
}
addBullet(new Bullet());
addBullet(new Bullet());
addBullet(new Bullet());
addBullet(new Bullet());
addBullet(new Bullet());
addBullet(new Bullet());
}
}
l承抽象cdƈ实现接口
public abstract class Gun{
protected String cannon;
protected List<Bullet> bullets;
public abstract void shoot();
public void addBullet(Bullet bullet){
if(bullets==null){
bullets=new LinkedList<Bullet>();
}
bullets.add(bullet);
}
}
public interface Thornable{
public void thorn();
}
public class SpringFieldRifle extends Gun implements Thornable{
public void thorn(){
// thorn sth
}
public void shoot(){
// shoot sth
}
}
抽象cȝ承抽象类实现接口的例?/strong>
public abstract class Gun{
protected String cannon;
protected List<Bullet> bullets;
public abstract void shoot();
public void addBullet(Bullet bullet){
if(bullets==null){
bullets=new LinkedList<Bullet>();
}
bullets.add(bullet);
}
}
public interface Handable{
public void hold();
}
public abstract class HandGun extends Gun implements Handable{
}
public class BlackStar extends HandGun{
public void hold(){
// Hold the gun
}
public void shoot(){
// Shoot Sth
}
}
抽象c?接口,cȝ区别
l承好比家学渊源,所?忠厚传家?诗书l世?,安M潜移默化的媄响下一?下一代也会在不经意中学习前辈的特?但因为年分辨能力不高加上世易时UL些优点已l不再是有点甚至会变成缺?下一代会把前辈的优缺点不分良莠的l承下来.q也是日后出现问题的Ҏ.
接口好比拜师学艺,"入了q个?得说这行话",比如相声界说学逗唱四门是必要学的,但是"师傅领进?修行在个?,学得怎么栯全看自己,指望不费力的l承什么是不可能的,具体功夫q得个h来过. 因ؓ是自己来,具体实现成什么样自由度也很大,比如四门功课中的"?,原指唱太qx?但因为爱听的?现在相声演员已经不要求这个了,改ؓ唱歌唱戏的唱,其实严格界定的话??的一U?q也无所谓对?郭d刚坚持唱太^歌词也行,W林唱流行歌曲也不错,M实现了就可以,实现得怎么样则留给实践来检?一个类可以同时实现多个接口,和Zh拜几个师傅是没有问题?郭d刚就同时实现了大鼓和相声两个接口.
抽象cd介于l承和接口之?既可不费力的从上一代?也可强制实现某接?有如某大师收自己的孩子ؓ?当然相声界不让这么干,其它曲艺行业q是可以?比如京剧界的梅兰芛_其子梅葆?既有a传n?也有强制实现,l合了承和接口的特?
抽象c?接口,cȝ详细区别
接口
抽象c?/td>
c?/td>
可以l承?/td>
接口
抽象c?c?/td>
抽象c?c?/td>
可以实现?/td>
?/td>
一个或多个接口
一个或多个接口
有否成员
只有static final成员
均可
均可
是否有构造函?/td>
?/td>
?/td>
?/td>
可否实例?/td>
不可
不可
?/td>
意图
规范行ؓ
l承成员+规范行ؓ
l承成员
抽象c?接口和类在承体pM的位|?/strong>
抽象c?接口一般来说都是从一般类ȝ归纳出来的抽象共性的东西,cd是实际具体的东西.
一般来?应该把合理抽象出的抽象类,接口攑֜cȝ承体pȝ上层,子类依靠cL实现.