ž®½å¯èƒ½åœ°ä½¿æ¯ä¸ªç±»æˆ–æˆå‘˜ä¸è¢«å¤–界访问ã€?/strong>æ¢å¥è¯è¯´åQŒåº”该ä‹Éç”¨ä¸Žä½ æ£åœ¨ç¼–写的软äšg的对应功能相一致ã€å°½å¯èƒ½æœ€ž®çš„讉K—®¾U§åˆ«ã€?/p>
对于™å¶å±‚çš?éžåµŒå¥—çš„)¾cÕd’ŒæŽ¥å£åQŒåªæœ‰ä¸¤¿Uå¯èƒ½éžè®‰K—®¾U§åˆ«åQŒè¦ä»Žæ˜¯åŒ…çñ”¿U有的也ž®±æ˜¯defaultåQŒè¦ä¹ˆæ˜¯publicçš?包çñ”¿U有ž®±æ„味ç€å®ƒæ˜¯˜q™ä¸ªåŒ?strong>实现的一部分åQŒä¸ä¼šä½œä¸ø™¯¥åŒ…API被导出,˜q™æ ·åœ¨ä»¥åŽçš„å‘型版本ä¸ï¼Œå¯¹å®ƒä¿®æ”¹ã€æ›¿æ¢ã€åˆ 除就ä¸ç”¨æ‹…心会媄å“先有客æˆïL«¯çš„程åºã€?/p>
如果一个包¾U§ç§æœ‰çš„™å¶å±‚¾c?或者接å?åªæ˜¯åœ¨æŸä¸€ä¸ªç±»å†…部被用刎ͼŒž®±åº”è¯¥è€ƒè™‘æŠŠå®ƒå˜æˆå”¯ä¸€ä½¿ç”¨å®ƒçš„那个¾cÈš„¿U有嵌套¾c…R€?/p>
é™ä½Žä¸å¿…è¦å…¬æœ‰ç±»çš„å¯è®‰K—®æ€§ï¼Œæ¯”é™ä½ŽåŒ…¾U§ç§æœ‰çš„™å¶å±‚¾cÀL›´é‡è¦çš„多åQŒå› 为共有类是API的一部分åQŒè€ŒåŒ…¾U§ç§æœ‰çš„™å¶å±‚¾cÕd·²¾l是包实现的一部分了ã€?/p>
å—ä¿æŠ?protected)的类或æˆå‘˜æ˜¯å¯¼å‡ºAPI的一部分åQŒå¿…™åÀL°¸˜qœå¾—到支æŒï¼Œåº”该é¿å…ž®½é‡ž®‘用ã€?/p>
如果å类覆盖了超¾cÈš„一个方法,åç±»ä¸çš„讉K—®¾U§åˆ«ž®×ƒ¸å…许低于‘…ç±»ä¸çš„讉K—®¾U§åˆ«åQŒå¦åˆ™ä¼š¾~–译错误。实çŽîCº†æŽ¥å£çš„æ‰€æœ‰æ–¹æ³•也必须是共有的åQŒå› 为接å£ä¸çš„æ‰€æœ‰æ–¹æ³•都是éšå«ç€å…±æœ‰è®‰K—®¾U§åˆ«ã€?/p>
ä¸ÞZº†ä¾¿äºŽ‹¹‹è¯•åQŒä¸åº”该把其讉K—®¾U§åˆ«æˆäؓ共有的,å–而代之是把测试类æˆäؓ包的一部分åQŒä»Žè€Œèƒ½å¤Ÿè®¿é—®å®ƒçš„包¾U§ç§æœ‰å…ƒç´ ã€?/p>
实例域决ä¸èƒ½æ˜¯å…±æœ‰çš„åQŒåŒ…å«å…¬æœ‰å¯å˜åŸŸçš„ç±»å³ä¾¿æ˜¯finalçš„ä¹Ÿä¸æ˜¯¾U¿ç¨‹å®‰å…¨çš?/strong>åQ?/p>
Note | 长度éžé›¶çš„æ•°¾l„æ€ÀL•°å¯å˜çš„,所以,¾cÕd…·æœ‰å…¬æœ‰çš„陿€final数组域,或者返回这¿U域的访问方法,˜q™å‡ 乎æ€ÀL•°é”™è¯¯çš„ã€?br /> |
public class UnmodifiableArray {
// æ½œåœ¨å®‰å…¨æ¼æ´ž
public static final String[] VALUES = { "RED", "GREEN" };
public static void main(String[] args) {
UnmodifiableArray UF = new UnmodifiableArray();
UF.VALUES[1] = "YELLO";//讄¡½®final数组æˆå‘˜
System.out.println(UF);
}
//使用Guava
@Override
public String toString() {
return Objects.toStringHelper(this).add("VALUES0", UnmodifiableArray.VALUES[0])
.add("VALUES1", UnmodifiableArray.VALUES[1]).toString();
}
}
上é¢çš„例å里åQŒæˆ‘们æˆåŠŸæ›´æ”¹äº†ä¸€ä¸ªä¸å¯å˜æ•°ç»„åQŒæŠŠæˆå‘˜GREEN修改ä¸?tt>YELLOåQŒæ‰§è¡Œè¾“出如下:
UnmodifiableArray{VALUES0=RED, VALUES1=YELLO}
我们å¯ä»¥é€šè¿‡å¢žåŠ ä¸€ä¸ªä¸å¯å˜é›†åˆåˆ—表æ¥è§£å†Œ™¿™ä¸ªå®‰å…¨é—®é¢˜ï¼Œòq¶æŠŠåŽŸæ¥public讉K—®¾U§åˆ«æ”¹äØ“private的:
public class UnmodifiableArrayList {
// æ¶ˆé™¤å®‰å…¨æ¼æ´ž
private static final String[] PRIVATE_VALUES = { "RED", "GREEN" };
public static final List<String> PVALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
public static void main(String[] args) {
UnmodifiableArrayList UF = new UnmodifiableArrayList();
UF.PVALUES.add(1, "YELLO"); //会抛出UnsupportedOperationException异常
System.out.println(UF);
}
//使用Guava
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("PVALUES0", UnmodifiableArrayList.PVALUES.get(0))
.add("PVALUES1", UnmodifiableArrayList.PVALUES.get(1))
.toString();
}
}
æž„å¾ä¸€ä¸ªä¸å¯å˜é›†åˆåQŒGuava¾l™å‡ºäº†æ›´½Ž€‹z的办法åQ?/p>
ImmutableList mmutableList = ImmutableList.of(PRIVATE_VALUES);
å¤šä¸ªæž„é€ å™¨åªèƒ½é€šè¿‡åŒšw…傿•°¾cÕdž‹çš„顺åºä¸åŒæ¥åŒºåˆ†ä½¿ç”¨å“ªä¸€ä¸ªï¼Œ˜q™æ ·å¸¸å¸¸ä¼šå¯¼è‡´ç”¨æˆ¯‚°ƒç”¨é”™è¯¯æž„é€ å™¨åQŒè€Œé™æ€å·¥½E‹æ–¹æ³•则ä¸åŒåQŒå¯ä»¥é€šè¿‡æ–ÒŽ³•忏…晰的指明用æ„ã€?/p>
//本例åªç”¨æ¥è¯´æ˜Žç¬¬ä¸€å¤§ä¼˜åŠ¿ï¼Œè¯·ä¸è¦çº ¾l“其它问é¢?/span>
public class Foo {
Set<Bar> bars;
List<Car> cars;
//æž„é€ å™¨1
private Foo(Set<Bar> bars) {
this.bars = bars;
}
//æž„é€ å™¨2
private Foo(List<Car> cars) {
this.cars = cars;
}
//æž„é€ å™¨3
private Foo(Set<Bar> bars, List<Car> cars) {
this.bars = bars;
this.cars = cars;
}
//陿€å·¥åŽ‚æ–¹æ³?
public static Foo newInstanceByBar(){
return new Foo(new HashSet<Bar>());
}
//陿€å·¥åŽ‚æ–¹æ³?
public static Foo newInstanceByCar(){
return new Foo(new ArrayList<Car>());
}
//陿€å·¥åŽ‚æ–¹æ³?
public static Foo newInstanceByAll(){
return new Foo(new HashSet<Bar>(),new ArrayList<Car>());
}
public static void main(String[] args) {
// é€šè¿‡æž„é€ å™¨åˆ›å¾å®žä¾‹åQŒä¸å¥½åŒºåˆ†å®¹æ˜“ä‹É用错è¯?br /> Foo fbar = new Foo(new HashSet<Bar>());
Foo fcar = new Foo(new ArrayList<Car>());
Foo fall = new Foo(new HashSet<Bar>(),new ArrayList<Car>());
// é€šè¿‡é™æ€å·¥åŽ‚æ–¹æ³•å¯ä»¥æ¸…晰的用方法å识别
Foo fbar_static = Foo.newInstanceByBar();
Foo fcar_static = Foo.newInstanceByCar();
Foo fall_static = Foo.newInstanceByAll();
}
}
class Bar {}
class Car {}
对于GuavaåQŒåƈ没有æä¾›åˆ›å¾é™æ€å·¥åŽ‚æ–¹æ³•çš„å·¥å…·åQŒä½†æ•´ä¸ªGuava APIåˆ°å¤„éƒ½æ˜¯é™æ€æ–¹æ³•的实现åQŒæˆ‘们以Guava Collections Framewrok举例说明ã€?/p>
Guava对于½W¬ä¸€å¤§ä¼˜åŠ¿æœ‰å¾ˆå¤šå®žçŽ°åQ?/p>
List<Type> exactly100 = Lists.newArrayListWithCapacity(100);
List<Type> approx100 = Lists.newArrayListWithExpectedSize(100);
Set<Type> approx100Set = Sets.newHashSetWithExpectedSize(100);
方便对象é‡ç”¨åQŒè¿˜å¯ä»¥¼‹®ä¿ä¸å¯å˜çš„ä¸ä¼šå˜åœ¨ä¸¤ä¸ªç›¸ç‰çš„实例,如果a==b那么a.equals.(b)æ‰ä¼š˜q”回true ,如果能ä¿è¯è¿™ä¸€ç‚¹ï¼Œž®±å¯ä»¥ä‹Éç”?tt>==æ“作½W¦æ¥æ¯”较对象åQŒä¼šæœ‰å¾ˆå¤§çš„æ€§èƒ½æå‡ã€?/p>
˜q™æ˜¯ä¸€ä¸ªéžå¸¸å¼ºå¤§çš„ç‰ÒŽ€§ï¼Œ Effective Javaä¸åˆ—举了APIã€SPIã€æœåŠ¡æä¾›æ¡†æž¶çš„关系æ¥è¯´æ˜Žï¼š
API(Service Interface): æœåŠ¡å…¬å…±æŽ¥å£ SPI(Service Provider Interface)åQ?æœåŠ¡æä¾›å•†æŽ¥å?nbsp;SPF(Service Provider Framework): æœåŠ¡æä¾›æ¡†æž¶
看例å?
// æœåŠ¡æä¾›æ¡†æž¶½Cºæ„模型 - æœåŠ¡API
public interface ServiceAPI {
// ˜q™é‡Œæ˜¯æœåŠ¡æŒ‡å®šçš„æ–ÒŽ³•
}
// æœåŠ¡æä¾›æ¡†æž¶½Cºæ„模型 - æœåŠ¡SPI
public interface ServiceSPI {
ServiceAPI newService();
}
// æœåŠ¡æä¾›æ¡†æž¶½Cºæ„模型实现
// ä¸å¯å®žä¾‹åŒ–çš„¾c»ï¼Œç”¨æ¥æ³¨å†Œåˆ›å¾å’Œæä¾›è®¿é—?/span>
public class ServiceFramework {
private ServiceFramework() {
}// 强制防æ¢å®žä¾‹åŒ–(规则4åQ?br />
// æ˜ å°„æœåŠ¡å到æœåŠ¡
private static final ConcurrentMap<String, ServiceSPI> spis = new MapMaker().makeMap();//使用Guava创å¾
public static final String DEFAULT_SPI_NAME = "<def>";
// 默认SPI注册API
public static void registerDefaultSPI(ServiceSPI spi) {
registerSPI(DEFAULT_SPI_NAME, spi);
}
// 指定SPI注册API
public static void registerSPI(String name, ServiceSPI spi) {
spis.put(name, spi);
}
// æœåŠ¡è®‰K—®API
public static ServiceAPI newInstance() {
return newInstance(DEFAULT_SPI_NAME);
}
public static ServiceAPI newInstance(String name) {
ServiceSPI spi = spis.get(name);
if(spi == null)
throw new IllegalArgumentException(
"No provider registered with name: " + name);
return spi.newService();
}
}
Note | 陿€å·¥½E‹æ–¹æ³•返回的对象所属的¾c»ï¼Œåœ¨ç¼–写这个包å«é™æ€å·¥åŽ‚æ–¹æ³•çš„¾cÀL—¶å¯ä»¥ä¸å¿…å˜åœ¨ã€‚上é¢çš„例å在编写ServiceFramework¾cÀL—¶åQŒServiceAPI的实现类òq¶ä¸å˜åœ¨ã€‚è¿™å¤§å¤§å¢žåŠ äº†æ¡†æž¶çš„ç‰|´»æ€§ã€?/strong> |
现在¾~–写客户端测试程åº?/p>
// ½Ž€å•çš„æœåŠ¡æä¾›æ¡†æž¶‹¹‹è¯•½E‹åº
public class Test {
public static void main(String[] args) {
// æœåŠ¡æä¾›å•†æ‰§è¡Œä¸‹é¢çš„æ³¨å†Œ
ServiceFramework.registerDefaultSPI(DEFAULT_PROVIDER);
ServiceFramework.registerSPI("comp", COMP_PROVIDER);
ServiceFramework.registerSPI("armed", ARMED_PROVIDER);
// 客户端执行下é¢çš„创å¾
ServiceAPI s1 = ServiceFramework.newInstance();
ServiceAPI s2 = ServiceFramework.newInstance("comp");
ServiceAPI s3 = ServiceFramework.newInstance("armed");
System.out.printf("%s, %s, %s%n", s1, s2, s3);
}
private static ServiceSPI DEFAULT_PROVIDER = new ServiceSPI() {
public ServiceAPI newService() {
return new ServiceAPI() {
@Override
public String toString() {
return "默认æœåŠ¡";
}
};
}
};
private static ServiceSPI COMP_PROVIDER = new ServiceSPI() {
public ServiceAPI newService() {
return new ServiceAPI() {
@Override
public String toString() {
return "Complementary æœåŠ¡";
}
};
}
};
private static ServiceSPI ARMED_PROVIDER = new ServiceSPI() {
public ServiceAPI newService() {
return new ServiceAPI() {
@Override
public String toString() {
return "Armed æœåŠ¡";
}
};
}
};
}
//输出如下 �/span>�/span>�/span>�/span>, Complementary �/span>�/span>, Armed �/span>�/span>
在JDK7之å‰åQŒæˆ‘们创å»ÞZ¸€ä¸ªCollections大致是这么åšçš„:
List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<TypeThatsTooLongForItsOwnGood>();
JDK7å‘布以åŽåQŒæˆ‘们å¯ä»¥ç®€åŒ–战q™æ ·åQ?/p>
List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<>();
但是Guava˜q˜æ˜¯å®æ„¿ä½¿ç”¨é™æ€å·¥½E‹æ–¹æ³•ï¼Œå› äØ“çœŸçš„éžå¸¸æ–¹ä¾¿åQ?/p>
Set<Type> copySet = Sets.newHashSet(elements);
List<String> theseElements = Lists.newArrayList("alpha", "beta", "gamma");
¾cÕd¦‚æžœä¸å«å…¬æœ‰çš„æˆ–者å—ä¿æŠ¤çš„æž„é€ å™¨åQŒå°±ä¸èƒ½è¢«å¾cÕdŒ–åQŒè¿™ä¹Ÿè®¸ä¼šå› ¼œ¸å¾—¼›ï¼Œå› äØ“å®ƒé¼“åŠ±å¼€å‘äh员ä‹É用å¤åˆï¼Œè€Œä¸æ˜¯ç‘ôæ‰Ñ€?/p>
ä»–ä»¬ä¸Žå…¶ä»–çš„é™æ€æ–¹æ³•实际上没有ä»ÖM½•区别 如果APIæ–‡æ¡£æ²¡æœ‰æ˜Žç¡®çš„è¯´æ˜Žè¿™æ˜¯ä¸€ä¸ªé™æ€å·¥½E‹æ–¹æ³•,ž®×ƒ¼šå¾ˆéš¾è¯†åˆ«å‡ºæ¥ã€‚éµå¾ªæ ‡å‡†çš„命åè§„èŒƒä¹ æƒ¯åQŒå¯ä»¥å×I补这一劣势åQŒä¸‹é¢åˆ—å‡ÞZ¸€äº›æƒ¯ç”¨å‘½å:
valueOf - ˜q™æ ·çš„陿€å·¥åŽ‚æ–¹æ³•å®žé™…ä¸Šæ˜¯ç±»åž‹è{æ?/p>
of - valueOf的简‹zæ–¹å¼?/p>
getInstance - ˜q”回实例通过æ–ÒŽ³•傿•°æè¿°åQŒå¯¹äºŽå•ä¾‹ï¼Œè¯¥æ–¹æ³•æ²¡æœ‰å‚æ•ŽÍ¼Œòq¶è¿”回唯一的实ä¾?/p>
newInstance - 与getInstanceä¸åŒçš„æ˜¯åQŒå®ƒ˜q”回的实例与所有其它实例都是ä¸åŒçš„
getType - åƒgetInstanceä¸€æ øP¼Œä½†æ˜¯åœ¨å·¥åŽ‚æ–¹æ³•å¤„äºŽä¸åŒçš„¾cÖM¸çš„æ—¶å€™ä‹É用。Type表示i˜q”回对象¾cÕdž‹
newType - åƒnewInstanceä¸€æ øP¼Œä½†æ˜¯åœ¨å·¥åŽ‚æ–¹æ³•å¤„äºŽä¸åŒçš„¾cÖM¸çš„æ—¶å€™ä‹É用。Type表示i˜q”回对象¾cÕdž‹
既然Effective Javaå’ŒGuava都诞生于GoogleåQŒé‚£ä¹ˆå½“他们盔R‡ä¼šä»€ä¹ˆæ ·å‘¢ï¼Œä¸ºæ¤æˆ‘å†³å®šé‡æ¸©Effective Java˜q™éƒ¨è‘—作åQŒåƈ针对æ¯ä¸€æ¡è§„则寻找Guava¾l™å‡ºçš„è§£å†Ïx–¹æ¡ˆï¼Œå¸Œæœ›èƒ½æ›´æ·±å…¥çš„æŽŒæ¡Javaã€?/p>
Effective Java½W?0æ¡è§„则: 始终è¦è¦†ç›?/strong>toStringæ–ÒŽ³•
Effective Java里指出,"廸™®®æ‰€æœ‰çš„å类都覆盖这ä¸?tt>toStringæ–ÒŽ³•"åQŒè¿™æ ·å¯ä»¥ä‹É¾cÈ”¨èµäh¥æ›´åŠ èˆ’é€‚ã€‚æœ€é‡è¦çš„æ˜¯˜q™æ ·çš„åšæ³•对调试éžå¸¸æœ‰å¸®åŠ©ï¼ŒGuava通过 Objects.toStringHelper为我们æä¾›äº†æ–¹ä¾¿åˆ›å¾toString的方法。看下é¢çš„æ ·ä¾‹ï¼š
// Returns "ClassName{x=1}"
Objects.toStringHelper(this)
.add("x", 1)
.toString();
// Returns "MyObject{x=1}"
Objects.toStringHelper("MyObject")
.add("x", 1)
.toString();
Guava关于toString的文档连接: https://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained
䏋颿ˆ‘把Effective Javaçš„æ ·ä¾‹ä»£ç 列出,òq¶ç”¨Guava釿–°äº?tt>toStringæ–ÒŽ³•
// é‡å†™PhoneNumberçš„toStringæ–ÒŽ³• - Effective Java䏿–‡½W¬äºŒç‰ˆç¬¬44™å?/span>
package org.effectivejava.examples.chapter03.item10;
import java.util.HashMap;
import java.util.Map;
import com.google.common.base.Objects;
public final class PhoneNumber {
private final short areaCode;
private final short prefix;
private final short lineNumber;
public PhoneNumber(int areaCode, int prefix, int lineNumber) {
rangeCheck(areaCode, 999, "area code");
rangeCheck(prefix, 999, "prefix");
rangeCheck(lineNumber, 9999, "line number");
this.areaCode = (short) areaCode;
this.prefix = (short) prefix;
this.lineNumber = (short) lineNumber;
}
private static void rangeCheck(int arg, int max, String name) {
if (arg < 0 || arg > max)
throw new IllegalArgumentException(name + ": " + arg);
}
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof PhoneNumber))
return false;
PhoneNumber pn = (PhoneNumber) o;
return pn.lineNumber == lineNumber && pn.prefix == prefix
&& pn.areaCode == areaCode;
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + areaCode;
result = 31 * result + prefix;
result = 31 * result + lineNumber;
return result;
}
//Effective Java原有的toStringæ–ÒŽ³•
/*
* @Override public String toString() { return
* String.format("(%03d) %03d-%04d", areaCode, prefix, lineNumber); }
*/
/**
* 采用Guava实现的toString
*
*/
@Override
public String toString() {
return Objects.toStringHelper(this)
.addValue(String.format("(%03d) %03d-%04d", areaCode, prefix,lineNumber))
.add("areaCode", areaCode)
.add("prefix", prefix)
.add("lineNumber", lineNumber)
.toString();
}
public static void main(String[] args) {
Map<PhoneNumber, String> m = new HashMap<PhoneNumber, String>();
m.put(new PhoneNumber(707, 867, 5309), "Jenny");
System.out.println(m);
}
}
输出å¯Òޝ”
//原输�br />{(707) 867-5309=Jenny}
//Guava实现输出
{PhoneNumber{(707) 867-5309, areaCode=707, prefix=867, lineNumber=5309}=Jenny}
æ’äšg主页åQ?a style="color: #0088cc; text-decoration: initial;">http://eclipsecolorthemes.org/
æ’äšgæä¾›äº†ä¸Šä¸‡ç§é…色æ–ÒŽ¡ˆåQŒéžå¸¸æ¼‚亮,上图看下åQ?/p>
安装很简å•,打开 Eclipse Marketplace
查找 Eclipse Color ThemeåQŒä¼šæ‰‘Öˆ°˜q™ä¸ªæ’äšgã€?/p>
安装完æˆåŽè¿›å…?nbsp;Preferences —> Appearance —> Color Theme ž®±å¯é€‰æ‹©ä¸»é¢˜äº?/p>
首先在Tomcatçš„bin目录下修改catalina.sh,åŠ å…¥JAVA_OPTS傿•°:
JPDA_ADDRESS=20777 JAVA_OPTS='-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=20777'
å…¶ä¸JPDA_ADDRESSè¦æŒ‡å®šä¸€ä¸ªæ²¡æœ‰è¢«å 用的端å?å¦‚æžœä¸æŒ‡å®?默认值是8000
ç„¶åŽç”¨ä¸‹é¢çš„æ–¹å¼å¯åЍtomcatåQ?/p>
catalina.sh jpda start
最åŽå¯åЍEclipseåQŒé€‰æ‹©ä½ 想è¦Debug的类òq¶è®¾¾|®æ–点,然åŽé€‰æ‹©Debug工具æ 下的Debugåèœå?Debug…)åQŒåœ¨å¼¹å‡ºçš„Debug½H—å£ä¸ï¼Œåœ¨å·¦è¾¹çš„èœå•™å¹ä¸é€‰æ‹©˜qœç¨‹è°ƒè¯•(Remote Java Application)åQŒç„¶åŽè¾“入机器å和端å£ï¼Œæ¯”如è¯?92.168.1.1å’?0777åQŒç„¶åŽApplyòq¶ä¸”开始Debug