Effective Java 第2版 笔记

Item 1;Consider static factoriy moehtods instead of constructors

             考虑使用静态工厂方法代替构造函数

 

Item 2:Consider a builder when faced with many constructor parameters

             当构造函数参数过多时,是否可以使用Builder

             一个builder的例子:

             医生需要开一个只包含维生素(Vitamin)的处方(Prescription),处方一定包括A,可能包括B1、B2、C、D、E等,可能这个列表还会变化。这个例子用builder pattern实现就是:

             Prescription prescriotion = new Prescription.builder(100/**mg*/).vitaminB1(20/**mg*).vitaminE(1000/**mg*/).build(); //开了一个包含100mg维生素A、20mg维生素B1、1000mg维生素E的处方(可能这个患者比较需要维生素E)。vitaminB1(20/**mg*).vitaminE(1000/**mg*/) 这种串联的方式来创建对象是一个特色,让我想起了设计模式里的decorator模式,不过decorator是把一种类型的对象不断地包装,直到得到所需要的对象。

            Sandwich sanwich = new MeatSandwich(new VegetableSandwich(new CreamSandwich()));最后我们得到了一个有肉、蔬菜和奶油的三明治。O(∩_∩)O哈哈~

 

Item 3:Enforce the singleon property with a private constructor or an enum type

            实现单例的两种方式——private的构造函数或者使用枚举(enum)? 枚举实现单例倒还没用过- -

 

Item 4:Enforce noninstantiability with a private constructor

            将构造函数设为private来防止实例化,而不是简单讲类声明为abstract,后者允许被继承,子类同样可以被实例化

 

Item 5:Avoid creating unnecessary objects

            避免创建多余的对象,比如 new String("A"); new Integer(1) // insteading using Integer.valueOf(1);

 

Item 6:Eliminate obsolete object references

             释放对象引用

 

Item 7:Avoid finalizers

            避免使用finailizer方法,原因很简单,这个方法一定会执行,但你不知道何时这个方法到底何时执行。

 

Item 8:Obey the general contact when overriding equals

            重写euqals方法时,记得遵守它的每一条规则,具体见http://salever.iteye.com/blog/733705

 

Item 9:Always override hashCode when you override equals

            永远记得在你重写equals时也重写hashCode

 

Item 10:Always override toString

             总是重写toString方法,这会使用的类更人性化

 

Item 11:Override clone judiciously

              在适当的时候重写clone方法

 

Item 12:Consider implementing Comparable

              考虑实现Comparable接口,它提供了一个排序方法,使得对象具有一定的顺序。在对象作为集合类元素的时候,实现这个接口是一个不错的选择。

 

Item 13:Minimize  the accessibility of classes and members

              最大程度的控制类和成员的访问权限,能用private的就不用protected,能用protected的就不用public

 

Item 14:In public classes, use accessor menthods, not public fields

              在public的类中,采用通过访问器来访问成员变量

 

Item 15:Minimize mutablility

              最大程度地减小可变性,让对象一旦创建就不可更改,比如String,这样的类更简单,而且天生就是线程安全的。在某些场合下,使用静态工厂方法返回经常使用的常量对象,可以避免重复创建。

              总之尽可能的减小类的成员的可变性,能用final的就用final。

 

Item 16:Favor composition over inheritance

              组合优先于继承,如果A、B之间不是is-a的关系,那么不要使用继承,组合往往更加合适。另外,分布在不同的package下的class之间最好也能避免继承。要知道,继承实际上破坏了封装性。

 

Item 17:Design and document for inheritance or else prohibit it

              要么好好的设计继承关系并书写良好的说明文档,要么禁用继承。很多情况下,继承方式成为扩展现有类的首要选择,关于继承,有几点需要注意和提高警惕:

             A:构造函数不要调用可能会重写的方法,否则将出现难以预料的逻辑错误;

             B:在类中不要轻易调用可能会重写的方法,因为这样会加大子类重写时的复杂度,使用private的帮助方法来代替它们;

             C:在遇见Cloneable和Serializable时请绕行,非要实现它们的话,请遵守A、B规则,不要在相关方法内调用可能会重写的方法;

             D:好好的制定说明文档吧

             其实Item16说的已经说的很明白了,不要万不得已,不要轻易使用继承。

 

Item 18:Prefer interfaces to abstract classes

             优先使用interface,这个item主要讲了interface与抽象类在使用中的优缺点,并非某些参考书上一成不变的什么这个可以有变量,那个只能是有常量。

             接口提供多种实现的可能,但是相对抽象类来说,它更“死板”,也更稳定,公共接口一般不允许修改,而且实现接口不会破坏类之间的结构关系,它们之间没有继承关系。当你选择使用抽象类的时候,你就要面临it 17中讲得继承问题了。另外,给接口一个基本实现(Skeletal implementation)是一个不错的选择。

 

Item 19:Use interfaces only to define types

             不要用接口干其他的事,其中最常见的就是用它来定义常量,多方便,可以省略public static 几个关键字。但是作者不建议这么做,因为实现了这个接口的类将会用到这些常量,在未来的版本中,如果这些常量被废弃了,它让然要继续实现它,以保证程序的语法正确,这显然不合适。

            选用utility class 或者枚举来代替它吧,接口还是用来定义允许多种实现的类型吧。

 

Item 20:Prefer class hierarchies to tagged classes

             限定一个类只能创建一种实例对象,不要尝试通过添加tag来标记不同类型的实例,如果真的需要在类中使用tag 来区分不同类型的实例,那就使用继承结构。

             Tagged class,顾名思义,就是在class中使用一个或多个tag,然后

switch(tag){
    case TAG_1:
          instance = new TaggedClass(TAG_1):
    case TAG_2:
          instance = new TaggedClass(TAG_2):
    ...
}

 

Item 21:Use function objects to represent strategies

              使用对象引用来实现策略模式,看了一遍无甚感想

 

Item 22:Favor satic member classes over nonstatic

              优先使用静态内部类作为成员,这一节讲得非常好,将四种内部类分析的很透彻。

public class NestedClass {

	//static member class
	private static class StaticNested {
	}

	//nonstatic member class
	private class NonstaticNested {
	}

	protected void doSth() {
		StaticNested sn = new StaticNested();
		NonstaticNested nn = new NonstaticNested();
		//anonymous class 匿名类
		Runnable runable = new Runnable(){
			@Override
			public void run() {	}		
		};
		// local class 局部类
		class LocalClass implements Runnable, Comparable{

			@Override
			public void run() {				
			}

			@Override
			public int compareTo(Object o) {
				return 0;
			}
		}	
		LocalClass lc = new LocalClass();		
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		StaticNested nsn = new NestedClass.StaticNested();
		StaticNested sn = new StaticNested();
		NonstaticNested nn = new NestedClass().new NonstaticNested();
	}

}

上述四种内部类,从使用上说:

A,如果内部类需要从外部访问并且不要求与包含类的实例挂上关系,那么选择静态内部类,它与包含类的实例对象没有关联,可以看成一个稍微复杂一些的静态成员;

B,如果内部类的实例与包含类的示例息息相关,那么使用非静态内部类,

 new NestedClass().new NonstaticNested(); //outside
NonstaticNested nn = new NonstaticNested();//inside

注意非静态内部类因为与其包含类实例之间的关系,在资源和时间消耗上都远远超过静态类,请慎用;

C,在类不会与外界打交道,很简短而且可以确定不会拿类的名字干点啥的 ,可以选择匿名类,注意一定不要影响了代码可读性,而且匿名类不能有静态成员,只能同时实现一个接口或者继承一个基类;

D,如果匿名类很长,而且可能类名有潜在的作用,那么可以考虑使用局部类,它避免了匿名类的的一些短项,比如可以同时实现二个接口。

 

Item 23:Don't use raw types in new code

             不要使用原始类型参数,比如List,建议使用List<Object> List<?> List<String>

 

Item 24:Eliminate unchecked warnings

             尽可能的减少unchecked 警告信息,对于raw 类型的使用上,如果确信是类型安全的,可以使用@SuppressWarnings("unchecked")来避免警告。

 

Item 25:Prefer lists to arrays

              优先使用list。这一节对于list和array分析的很不错,主要包括以下几个方面:

              A,行为上的不同:array在运行时才确定元素的类型,而list(参数化的)在编译的时候就需要检查类型,以保证类型的安全。

              B,协同变化性(covariant),指的是array之间因存储元素的不同也会存在父子类型的关系,比如int[]是Object[]的一个子类,那么可以将int[]赋给Object[],而list<Integer>与list<Object>则是两个完全不同的集合。

              因此,无法创建泛型l的list类型的数组。

              示例:

		Object[] objs = new String[1];
		String[] strings = new String[1];
		int [] ints = new int[1];		
		objs = strings;
		objs[0] = 1; //java.lang.ArrayStoreException
		
		List<String>[] strs = new List<String>[1]; //Error:Cannot create a generic array of List<String>
		List<Long> longs = new ArrayList<Long>();
		longs.add(10L);
		Object[] objects = strs;
		objects[0] = longs;
		String element = strs[0].get(0);

            第一段代码就是针对数组的协同变化性和运行时类型检查,编译完全正确,运行时抛出java.lang.ArrayStoreException,第二段代码针对泛型list的数组,编译即出错。若不出错,想想后面的代码,strs[0].get(0)返回的是Long,而不是String,一个潜在的问题就出现了,ClassCastException。

           这里面还讲到一个概念——non-reifiable types:简单的讲一个non-reifiable type就是在运行时包含的信息要少于编译时,比如泛型的list,运行时它不会进行类型检查,而编译时则需要,当然一些特殊的list除外——List<?>。non-reifiable types都不能用来创建数组。

 

Item 26:Favor generic types

             优先考虑泛型的类和接口

 

Item 27:Favor generic methods

             优先考虑泛型的方法

 

Item28:Use bounded wildcards to increase API flexibility

             使用绑定的通配符提升API的灵活性

             读完这三个已经内牛满面了,作者Joshua Bloch不愧是Java Collection Framework的创始人,也只有他才能把泛型这个问题分析的如此透彻,很多概念和用法都还不是很了解,哎。。。。

 

Item 29:Consider typesagfe heterogeneous containers

              考虑使用类型安全的混杂容器

 

Item 30:Use enums to instead of int constants

              使用枚举代替整形常量

 

Item 31:Use instance fields instead of ordinals

              使用成员变量来代替使用自然顺序的枚举,特别是ordinal()方法的使用上,尤其要注意。

 

Item 32:Use EnumSet instead of bit fields

              使用EnumSet 代替bit类型的成员变量,就像SWT.NONE,SWT.READ_ONLY。我猜为什么SWT的实现很多都是用bit类型的成员组合,比如new Text(composite, SWT.BORDER | SWT.READ_ONLY),也许是SWT的出现比EnumSet要早缘故,先在我们就可以使用EnumSet.of(Style.BORDER, Style.READ_ONLY)来代替了。

 

Item 33:Use EnumMap instead of ordinal indexing

              EnumMap代替ordinal()方式的索引,他举了一个例子,就是液固气之间的转换,先用二维数组实现,然后用EnumMap<State, EnumMap<State, Transition>>实现,后者的确简洁很多,不过这个例子突然是我想起State模式,好像它用EnumMap实现真实绝配。

 

Item 34:Emulate extensiable enums with interfaces

             看了这一节,唯一的收获是发现enum也可以实现接口,不知道它能不能继承类呢?好像不能,只能实现接口。。。

 

Item 35:Prefer annotations to naming patterns

              优先使用注解(annotation),jdk1.5里添加了annotation这个功能,它的使用和实现与反射(reflect)关系紧密,Junit就是用annotation实现的。至于naming patterns就是说使用命名规则来区分某些特殊功能,比如test开头的函数为测试函数等。

              说道反射,突然想起一个问题,Class.forName("XX"),经常发现找不到class,为什么(联系Java Class loader机制)

 

Item 36:Consistently use the Override annotation

              随时给重写的方法加上“Override”

 

Item 37:User Marker interfaces to define types

              Marker interface 指的是没有扩展新方法的新类型,仅仅声明一下它是一个新的类型,但没有扩展行为,比如Cloneable、Serializable等,书中还提到了使用annotation添加类型说明,但是与Marker interface相比,后者的优势是,它显示定义了一种新的类型。

 

Item 38:Check parameters for validity

              检查参数的合法性

 

Item 39:Make defensive copies when needed

              使用defensive copy保护对象的不变性。对于Java来说,引用类型的常量仅限定了其不能被重新赋值,但是仍然有可能修改其属性,调用修改状态的方法,因此对于这种常量,注意使用防御性质的复制来保护其不变性。

              注意defensive copy 与 clone()方法的区别

 

Item 40:Design method signatures carefully

              函数签名设置的原则:

              1,取名,按照公认的规则取名

              2,不要在一个类中放置太多的方法

              3,避免太多的参数, 可以通过几种方法来减少参数的个数:子方法,辅助子类,build模式

              4,优先使用interface类型的参数,比如对于HashMap,使用Map就行了

              5,对于boolean类型的参数,考虑用枚举代替

 

Item 41:Use overloading judiciously

              适当的使用方法重载

 

Item 42:Use varargs judiciously

               明智的使用变长参数           

 

Item 43:Return empty arrays or collections, not nulls

              使用空集合代替null返回值,以避免额外的null检查或错误

 

Item 44:Write doc comments for all exposed API elements

             这个是关于API注释的,其中{@code} 和 {@literal} 标签比较有用,其他的暂时用不着呢。。。

 

Item 45:Minimize the scope of local variables

              缩小局部变量的作用域

 

Item 46:Prefer for-each loops to traditional for loops

              使用for-each循环代替传统的for循环

 

Item 47:Know and use the libraries

              理解和使用库,这个作者建议开发者至少熟悉java.lang.*、java.utl.*以及部分的java.io.*下的内容

(待续)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值