EffectiveJava-类和接口

来源:互联网 发布:网络群发软件 编辑:程序博客网 时间:2024/05/20 09:08
/* * 13 * 使类和成员的可访问性最小化 * 要区别设计良好的模块和设计不好的模块,最重要的因素在于,这个模块对于外部的模块而言,是否隐藏其内部实现和其它实现细节 * 信息隐藏:降低模块之间的耦合度,使得模块可以独立的开发、测试、优化、使用、理解、修改,提高软件的可重用性 * 实体的可访问性:实体声明的所在位置 和 访问修饰符 *  * 对于顶层(非嵌套)的类和接口,只有两种可能的访问级别:public 和 default 公共和包级私有 * default类:如果把类或者接口作为包级私有,它实际上成为包的实现的一部分而不是该包导出的API的一部分,在以后的发行版本中, * 进行修改、替换和删除不会影响到现有的客户端程序。 * public类:导出的API的一部分,就有责任永远支持他以保证其兼容性。 * protected类:导出的API的一部分,必须永远支持,导出的类的受保护成员代表了该类对于某个实现细节额公开承诺。(少使用) *  * 总之,设计一个最小的共有API后,应该防止把任何散乱的类、接口、成员变成API的一部分。 * 除了共有的静态final域,共有类不应该包含共有域。并确保共有静态final域所引用的对象都是不可变。 *  *  * 14 * 在共有类中使用访问方法而非共有域 *  *  * */public class Item13_14 {private class B1{}protected class C1{}}class A{}/*private class B{}报错protected class C{}*/class Point{private int x;private int y;public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}}

/* * 15 * 使可变性最小化 * 不可变类:其实例不能被修改的类,每个实例中包含的所有信息都必须在创建该实例的时候就提供,并在对象的整个生命周期内固定不变。 * Java平台不可变类:String,基本类型包装类,BigInteger,BigDecimal *  * 不可变性 * 不可变对象比较简单:不可变对象只有一种状态,即创建时状态,无需维护。可变对象可以有人以复杂的状态空间。 * 不可变对象本质上是线程安全的,它们不要求同步。 * 可以共享不可变对象及其内部信息。 * 不可变对象为其它对象提供了大量的构件。 * 缺点:对每个不同的值都需要一个单独的对象 *  * 总之,坚决不要为每个get方法编写相应的set方法。 * 除非有很好的理由让类成为可变的类,否则,应该是不可变的。 * 除非有很好的理由让域成为非final的域,否则,应该是final域的。 * */public class Item15 {}//不可变类方法1final class Complex{private final double re;private final double im;public Complex(double re, double im) {super();this.re = re;this.im = im;}public double getRe() {return re;}public double getIm() {return im;}public Complex add(Complex c){/* * 创建一个新的Complex对象,而并非修改其实例。 * 函数的做法:返回一个函数的结果,这些函数对操作数进行运算但不修改它。---不可变性 * 过程的做法(命令的做法):将一个过程作用在它们的操作数上,导致其状态发生改变。 * */return new Complex(re+c.getRe(),im+c.getRe());}public Complex div(Complex c){return new Complex(re-c.getRe(),im-c.getRe());}@Overridepublic String toString() {return "Complex [re=" + re + ", im=" + im + "]";}@Overridepublic int hashCode() {final int prime = 31;int result = 1;long temp;temp = Double.doubleToLongBits(im);result = prime * result + (int) (temp ^ (temp >>> 32));temp = Double.doubleToLongBits(re);result = prime * result + (int) (temp ^ (temp >>> 32));return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Complex other = (Complex) obj;if (Double.doubleToLongBits(im) != Double.doubleToLongBits(other.im))return false;if (Double.doubleToLongBits(re) != Double.doubleToLongBits(other.re))return false;return true;}}//不可变类-方法2class Complex1{private final double re;private final double im;private Complex1(double re,double im){this.re=re;this.im=im;}public static Complex1 valueOf(double re,double im){return new Complex1(re,im);}}

/* * 16 * 复合优先于继承(inheritance) * 在包的内部使用继承是非常安全的,在那里,子类和超类 的实现都处在同一个程序员的控制之下;对专门为了继承而设计 * 并且具有很好的文档类来说,使用继承也是非常安全的。 * 然而,对于普通类的跨包边界的继承,是非常危险的。 *  * 继承打破了封装性,超类的实现可能随着发行版本的不同而有所变化,此时,子类可能会遭到破坏,即使其代码没变。子类脆弱 * 如果在超类的后续发行版本中获得了一个新方法,并且不幸的是,你给子类提供了一个签名相同但是返回类型不同的方法,这样的子类将无法通过编译。 *  * 复合:不用扩展现有的类,而是在新的类中增加一个私有域,它引用现有类的一个实例。 * 转发:新类中的每个实例方法都可以调用被包含的现有类实例中对应的方法,返回其结果。 *  * 继承功能强大,但是存在许多问题,因为它破坏了封装性。 * 只有当超类和子类之间存在is-a关系时,使用继承才恰当。即便如此,若处在不同的包中,并且超类不是为继承设计的,那么继承会导致脆弱性。 * 为避免脆弱性,可使用复合转发机制来避免这种脆弱性,尤其是当存在适当的接口可以实现包装类的时候。包装类比子类更健壮,功能更强大。 * */public class Item16 {public static void main(String [] args){InstrumentedHashSet<String> set = new InstrumentedHashSet<String>();set.add("a");set.addAll(Arrays.asList("b","c","d"));System.out.println(set.getCount());//7/* * 在hashSet内部,addAll方法是基于其Add方法实现的---自用性(self-use) * */InstrumentedHashSet1<String> set1 = new InstrumentedHashSet1<String>(new HashSet());set1.add("a");set1.addAll(Arrays.asList("b","c","d"));System.out.println(set1.getCount());//4}}class InstrumentedHashSet<Object> extends HashSet<Object>{private int addCount=0;public InstrumentedHashSet(){}@Overridepublic boolean add(Object e) {// TODO Auto-generated method stubaddCount++;return super.add(e);}@Overridepublic boolean addAll(Collection<? extends Object> c) {// TODO Auto-generated method stubaddCount+=c.size();return super.addAll(c);}public int getCount(){return addCount;}}class ForwardingSet<Object> implements Set<Object>{private final Set<Object> s;public ForwardingSet(Set<Object> s){this.s=s;}@Overridepublic int size() {// TODO Auto-generated method stubreturn s.size();}@Overridepublic boolean isEmpty() {// TODO Auto-generated method stubreturn s.isEmpty();}@Overridepublic boolean contains(java.lang.Object o) {// TODO Auto-generated method stubreturn s.contains(o);}@Overridepublic Iterator<Object> iterator() {// TODO Auto-generated method stubreturn s.iterator();}@Overridepublic java.lang.Object[] toArray() {// TODO Auto-generated method stubreturn s.toArray();}@Overridepublic <T> T[] toArray(T[] a) {// TODO Auto-generated method stubreturn s.toArray(a);}@Overridepublic boolean add(Object e) {// TODO Auto-generated method stubreturn s.add(e);}@Overridepublic boolean remove(java.lang.Object o) {// TODO Auto-generated method stubreturn s.remove(o);}@Overridepublic boolean containsAll(Collection<?> c) {// TODO Auto-generated method stubreturn s.containsAll(c);}@Overridepublic boolean addAll(Collection<? extends Object> c) {// TODO Auto-generated method stubreturn s.addAll(c);}@Overridepublic boolean retainAll(Collection<?> c) {// TODO Auto-generated method stubreturn s.retainAll(c);}@Overridepublic boolean removeAll(Collection<?> c) {// TODO Auto-generated method stubreturn s.removeAll(c);}@Overridepublic void clear() {// TODO Auto-generated method stubs.clear();}}class InstrumentedHashSet1<Object> extends ForwardingSet<Object>{private int addCount=0;public InstrumentedHashSet1(Set<Object> s) {super(s);// TODO Auto-generated constructor stub}@Overridepublic boolean add(Object e) {// TODO Auto-generated method stubaddCount++;return super.add(e);}@Overridepublic boolean addAll(Collection<? extends Object> c) {// TODO Auto-generated method stubaddCount+=c.size();return super.addAll(c);}public int getCount(){return addCount;}}

/* * 17 * 要么为继承而设计,并提供文档说明,要么禁止继承 *  * 禁止子类化:final类私有的构造方法和共有的静态工程 *  *  * 18 * 接口优于抽象类 * 不严格的讲,mixin是指这样的类型:类除了实现它的基本类型之外,还可以实现这个mixin类型,以表明它提供了某些可供选择的行为。 * 接口一般被公开放行,并且已经被广泛实现,再想改变这几接口几乎是不可能的。初次设计时保证接口的正确性。 *  * 19 * 接口只用于定义类型,不应该用来导出常量 * 当类实现接口时,接口充当可以引用这个类实例的类型(type).因此,类实现了这个接口,表明客户端可以对类实例实施某些动作。 *  * 常量接口模式:对接口的不良使用 * */public class Item17_18_19 {public static void main(String [] aegs){Sub s =new Sub();s.overrideMe();//Sub^^^null//Sub^^^Sat Jun 25 21:44:48 CST 2016}}class Super{/* * 构造器绝不能调用可被覆盖的方法 * 超类的构造器在子类的构造器之前运行,所以,子类中覆盖版本的方法将会在子类的构造器运行之前就先被调用。 * 如果该覆盖版本的方法依赖于子类构造器所执行的任何初始化工作,该方法将不会如期执行 * */public Super(){overrideMe();}public void overrideMe(){}}final class Sub extends Super{private final Date  date;public Sub(){date = new Date();}@Overridepublic void overrideMe() {// TODO Auto-generated method stubSystem.out.println("Sub" + "^^^"+date);//date.getTime();报错:超类构造器中,date域还没机会进行初始化}} class Super1{public Super1(int a){}}class Sub1 extends Super1{public Sub1(int a) {super(a);//必须调用父类构造方法// TODO Auto-generated constructor stub}}class Super2{public Super2(int a){}public Super2(){}}class Sub2 extends Super2{}//常量接口interface inA{double ERRWEW_QWEWE=1.123244234e-21;int ASD_QWE=12;}

/* * 20 * 类层次优于标签类 * 标签类:冗长、易出错、效率低 *  * */public class Item20 {public static void main(String [] args){}}class Figure{enum Shape{Rectangle,Circle}final Shape shape;double width;double height;double radius;Figure(double width,double height){shape = Shape.Rectangle;this.width=width;this.height=height;}Figure(double radius){shape = Shape.Circle;this.radius=radius;}double area(){switch(shape){case Rectangle:return width*height;case Circle:return Math.PI*radius*radius;default:throw new AssertionError();}}}abstract class Figure1{abstract double area();}class Rectangle extends Figure1{double width;double height;Rectangle(double width,double height){this.width=width;this.height=height;}double area(){return width*height;}}class Circle extends Figure1{double radius;Circle(double radius){this.radius=radius;}double area(){return Math.PI*radius*radius;}}
/* * 21 * 用函数对象表示策略 * 有些语言支持函数指针,代理,lambda表达式,或者支持类似的机制,允许程序把“调用特殊函数的能力”存储起来并传递这种能力。 * 这种机制允许函数的调用者通过传入第二个函数,来制定自己的行为。 *  * 函数指针的主要用途是实现策略模式。 * 为了在java中实现这种模式,声明一个接口表示该模式,并为每个具体策略声明一个实现了该接口的类 *  *  * 22 * 优先考虑静态成员类 * 嵌套类(nested class):制定在另一个类的内部的类,其目的应该只是为其外部类提供服务。 * 静态成员类非静态成员类局部类匿名类 * 非静态成员类:非静态成员类的每个实例都隐含着与外围类的一个外围实例相关联。在没有外围类的情况下,不能创建非静态成员类 * */public class Item21_22 {public static void main(String [] args){Comparator c = new StringLengthComparator();c.compare("asd", null);}}//策略接口interface Comparator<Object>{ int compare(Object t1,Object t2);}//具体策略实例1class StringLengthComparator implements Comparator<String>{@Overridepublic int compare(String t1, String t2) {// TODO Auto-generated method stubif( t1 == null || t2 == null) throw new AssertionError();return t1.length()-t2.length();}}//具体策略实例2class Host{private static class StrLenCmp implements Comparator<String>{@Overridepublic int compare(String t1, String t2) {// TODO Auto-generated method stubif( t1 == null || t2 == null) throw new AssertionError();return t1.length()-t2.length();}}public static final Comparator STRING_LENGTH_COMPARATOR = new StrLenCmp();}


0 0
原创粉丝点击