EffectiveJava-4】的更多相关文章

先看一个栗子,看看能不能找出来里面的错误: /** * 请不要在新代码中使用原生态类型 * @author weishiyao * */ public class Test { public static void main(String[] args) { List<String> strings = new ArrayList<>(); unsafeAdd(strings, new Integer(42)); String string = strings.get(0); Sy…
有些语言支持函数指针.代理.lambda表达式,或者支持类似的机制,允许程序把“调用特殊函数的能力”储存起来并传递这种能力.这种机制通常用于允许函数的调用者通过传入第二个函数,来指定自己的行为.比较器函数有两个参数,都是指向元素的指针.如果第一个参数所指的元素小于第二个参数所指的元素,则返回一个负整数:如果两个元素相等则返回零:如果第一个参数所指的元素大雨第二个,则返回一个正整数.通过传递不同的比较器函数,就可以获得各种不同的排列顺序.这正是策略模式的一个例子.比较器函数代表一种为元素排列的策略…
标签类: 有时候,可能会遇到带有两种甚至更多钟风格的类的实例的类,并包含表示实例风格的(tag)域.例如下面这个类,它能够表示圆形或者矩形: /** * 类层次优先与标签类 * @author weishiyao * */ // Tagged class - vastly inferior to a class hierarchy public class Figure1{ enum Shape { RECTANGLE, CIRCLE } // Tag field - the shape of…
Java程序设计语言提供两种机制,可以用来定义允许多个实现的类型:接口和抽象方法,这两者直接醉为明显的区别在于,抽象类允许某些方法的实现,但接口不允许,一个更为重要的区别在于,为了实现由抽象类定义的类型,类必须成为抽象类的一个子类.任何一个类,只要定义了所有必要的方法,并且遵守通用约定,它就被允许实现一个借口,而不管这个类是处于类层次的哪个位置.因为Java只允许单继承,所有抽象类作为类型定义受到类极大的限制. 现有的类很容易被更新,以实现新的接口. 如果你希望让两个类扩展同一个抽象类,就必须把…
继承时实现代码重用的重要手段,但它并非永远是完成这项工作的最佳工具,不恰当的使用会导致程序变得很脆弱,当然,在同一个程序员的控制下,使用继承会变的非常安全.想到了很有名的一句话,你永远不知道你的用户是如何使用你写的程序的,一个程序员继承另一个程序员写的类也是同样的危险. 于方法调用不同的是,继承打破的封装性.换句话说,子类依赖于其超类中特定功能的实现细节.超类的实现有可能随着发行版本的不同而变化,如果真的发生了变化,子类可能会遭到破坏,即使它的代码完全没有修改过.因而,子类有必要随着超类的更新而…
考虑用静态构造方法代替构造器的好处: 1.静态构造方法有名字     BigInteger.probablePrime(int, int, Random)比 new BigInteger(int, int, Random)更加清楚,从名字知道返回可能是素数.     如果没有名字,将来给别人调用时,对方往往不知道该用哪个. 2.可以不必在每次调用时重新创建一个新对象     其实就是享元模式和单例模式 3.可以返回原类型的任何子类型对象.     这样可以使API变得更加简洁     这里可以引…
1, java中可以申明泛型类型的数组引用; 2, 但是不能实例化一个泛型数组对象; 3, 针对第二点, 可以曲线救国, 实例化一个Object数组, 再进行类型强转; 见代码如下: public class TestGeneric1<E> { //可以声明一个泛型数组的引用 private E[] array1; //编译报错,不能直接实例化一个泛型数组 //private E[] array2 = new E[10]; //实例化一个object数组,再进行类型转换 private E[]…
1, 父类的构造器方法中不能调用能够被子类重写的方法. 分析: 当初始化一个子类时, 首先要初始化父类, 即调用父类的构造方法; 如果父类的构造方法中调用了可被重写的其它方法, 那么此时调用的其实是该子类中重写的方法; 因此子类还没有初始化, 所以可能会造成一些问题. 示例代码如下: 父类: public class Father1 { public Father1() { overRide1(); } public void overRide1(){ System.out.println("父…
考虑用静态工厂方法代替构造器 一.概述 二.使用静态工厂的优势 获取类对象的两种方式: 使用公有构造方法 静态工厂方法 1.介绍 有名称 不必每次调用时创建一个新对象 可以返回原类型的任何子类型对象 在创建参数化类型实例的时候,它们使代码变得简洁 2.优势详解 优势一:有名称 一个常见的例子,并发库中的Executors工具类.Executor的静态工厂方法有不同的名字,更能清晰地表达要返回哪种类型的线程池对象. public class Executors { public static Ex…
--在大多数项目中,我们会经常使用int类型来声明final类型的常量,它在不考虑安全的情况下确实能满足我们绝大多数的需求.但是在JDK1.5版本发布之后,声明一组固定的常量组成合法值的类型就建议使用enum(枚举)类型代替.原因有三: – - -1.int类型对安全性和使用方便性没有任何帮助.就像你可以用==/=将不同类型进行对比甚至赋值,而这违背了它的final特性 - - - 2.如果与枚举常量关联的int发生了变化,客户端就必须重新编译.如果没有重新编译,它就会带着不确定的行为运行,你无…
当你的泛型集合需要更多的灵活性,你可以将键进行参数化而不是将容器进行参数化.然后将参数化的键提交给容器,来插入或者获取值.用泛型系统来确保值得类型与它的键相符. 我们创建一个Favorite类来模拟这种情况 public class Favorites { //不像普通的Map,它的所有键都是不同类型的.(异构) private Map<Class<?>, Object> favoties = new HashMap<Class<?>, Object>();…
有时候,我们需要的灵活性要比不可变类型所能提供的更多.所以针对一些通用性的方法,通常用泛型代替固定的数据类型,特别是当你要将某个方法打包成Jar的时候. 结合之前的例子,我们增加尝试用有限制的通配符类型来加大方法的灵活性 public class Stack<E> { public void pushAll(Iterable<? entends E> src){ for(E e:src){ //push为一个将元素加入到数组中的方法 push(e); } } } 这个方法按顺序将一…
泛型方法也可以从泛型类中获得同等收益,泛型方法的转换也十分简单,只需将原生态类型改为泛型,基本就可以解决问题 如:一个返回两个集合的联合 public static Set union(Set s1,Set s2){ Set result = new HashSet(s1); result.addAll(s2); return result; } 它的编译虽然会通过,但是会有两条类型转换警告,要消除这些警告,将他们转换成泛型集合即可. ----->>>>> public st…
使用泛型编写类比使用需要在客户端代码中进行转换的类型更加安全,并且对去其他程序员来说更加容易扩展,我们应该将可以用泛型代替的非泛型类优化 那么,如何将类泛型化呢? 这很简单.首先,给他的声明添加一个或者多个类型参数;然后,用相应的类型参数替换所有的Object类型 如:将第六条中的Stack类优化为泛型类 第六条链接:http://blog.csdn.net/jacxuan/article/details/56851123 public class StackGeneric<E> { priv…
less, but is more. 创建和销毁对象 避免创建不必要对象 消除过期的对象引用 使可变性最小 泛型 用标记接口定义类型 检查参数有效性 返回零长度的数组或集合,而不是null 需要精确答案时,避免使用float和double 接口优先于反射机制 可恢复情况使用受检异常,编程错误使用运行时异常 慎用延迟初始化及双重检查 创建和销毁对象 静态工厂方法代替构造器 优点 有名称 重用对象,考虑Flyweight模式 可返回子类型,多态 参数化类型实例,代码更简洁.右侧类型推导 Java7支…
泛型和数组 泛型:1.泛型是不可变的.对于任意两个不同类型Type1,type2;List既不是List的子类型,也不是List的超类型 2.泛型是通过擦除来实现的.故泛型只在编译时强化它们的信息,并在运行时丢弃(擦除)他们的元素类型信息 2.a:擦除:使泛型可以与没有使用泛型的代码随意进行互用 数组:1.数组是协变的.如果Sub为Super的子类型,那么Sub[]就是Super[]的子类型 2.数组是具体化的,这表明数组会在运行时才知道并检查他们的元素类型约束 因此,泛型和数组不能很好的进行结…
-..使用泛型编程时,会遇到许多编译器警告,如:非受检强制转化警告,非受检方法调用警告,非受检普通数组创建警告,费受精转换警告.这次的内容就是遇到这些警告的时候你该怎么办. PS:非受检警告就是代码上黄色的感叹号 1.首先,要尽可能地通过泛型控制消除每一个非受检警告.这意味着你将不会在运行时出现ClassCastException异常 2.如果无法消除警告,同时可以证明引起警告的代码类型是安全的,可以用一个@SuppressWarnings("unchecked")注解来禁止这条警告.…
泛型类和泛型接口 声明一个或者多个类型参数的类或者接口. 为什么不要在新代码中使用原生态类型 原生态类型,即泛型不带参数的类型 如List的list,list就是其原生态类型 1.使用原生态类型,插入数据时,IDE会绕过编译,从将错误升级成运行时错误.而此时如果你写的代码已经离原生态类型很远,那么错误将很难调试. 如: private final Collection stamps = ...; stamps.add(new Coin(...)); 我们知道尝试取出这个类型时才会显示错误 for…
嵌套类: 1.静态成员类 静态成员类是外围类的一个静态成员,遵守同样的可访问性规则 用法:a.作为公有的辅助类 内部类: 2.非静态成员类 语法上只和静态成员类的唯一区别是少一个static修饰符 a.它的每个实例都隐含着与外围类的一个实例相关联 b.在其实例方法内部可以调用外围实例上的方法,或者利用this构造获得外围实例的引用 用法:a.定义一个Adapter public class MySet<E> extends AbstractSet<E>{ public Iterat…
**调用对象上的方法通常是执行该对象上的某项操作**. 如果一个对象的方法执行其他对象的操作,一个类仅仅导出这个方法(它的实例相当于一个指向该方法的指针),这样的实例被称为函数对象 例如: /** * 如果一个类的所有实例在功能上都是相互等价的,那么他应该被设计为一个singleton public class StringLengthComparator { private StringLengthComparator() { } public static final StringLengt…
标签类:其中有许多样板代码,包括枚举声明,标签域和条件语句 如果要给它添加风格,除了有权限修改源码之外,你还得给每个条件语句都添加一个条件,否则就会在运行时失败 标签类过于冗长,容易出错,并且效率低下 我们可以用类层次类代替标签类 – 子类型化 public class Figure { enum Shape{RECTANGLE,CIRCLE}; final Shape shape; double width; double length; double radius; Figure(Doubl…
package com.classinteface.finalinterface; /** * 常量接口模式 java.io.ObjectStreamConstants * 这种模式会导致实现其的类将实现细节泄露到该类导出的API中 * 如果将来的发行版本改动了这个类,它不再需要常量接口中的常量,却依然必须实现这个接口以保证二进制兼容性 * @author JacXuan * */ public interface PhysicalConstants { static final double…
***接口和抽象类同样可以用来定义多个实现的类型,然而,接口通常是最佳途径.*** 这条规则有个例外 – 当演变的容易性比灵活性和功能性更为重要的时候,应该用抽象来定义类型 ,但前提是必须理解并且可以接受这些局限性. 接口 1.现在的类可以很容易被更新,以实现新的接口 2.接口式定义mixin的理想选择 3.接口允许我们构造非层次结构的类型框架 public interface ISinger { AudioClip sing(Song song); } public interface ISo…
1.如果为了继承而设计类,那么该类必须有文档说明它可覆盖的方法的自用性.对于每个公有的 或受保护的方法或者构造器,它的文档必须指明该方法或者构造器调用了那些可覆盖的方法,是以 什么顺序调用的,每个调用的结果又是如何影响后续的处理过程的 –类必须通过某种形式提供适当的钩子,以便能够进入到它的内部工作流程中,这种形式可以是 精心选择的受保护的方法,也可以是受保护的域 –尽可能的减少暴露的成员 –对于为了继承而设计的类,唯一的测试方法就是编写子类 –构造器绝不能调用可被覆盖的方法,无论直接还是间接:超…
为什么复合优先于继承? 1.继承违反了封装原则,打破了封装性 2.继承会不必要的暴露API细节,称为隐患.比如通过直接访问底层使p.getProperty(K,V)的键值对可以不是String类型 3.继承限定了类的性能,它会把它的缺陷传递给子类 1.复合:不必扩展现有的Set类,而是在此类中加一个私有域,它引用现有类的一个实例 2.它的封装特性使得它更加健壮灵活 3.复合允许设计新的API隐藏父类的缺点 在继承中的例子 public class InstrumentedHashSet<E>…
概念: 不可变类是其实例不能被修改的类,不可变类比可变类更加易于设计 实现和使用.它们不容易出错,而且更加安全. 优点 1.不可变对象只有创建时状态. 2.不可变对象本质上是线程安全的,它们不要求同步 3.不可变对象和其内部信息可以被自由共享.这条导致的结果是不可变类永远也不需要进行任何拷贝(拷贝对象始终为原始对象). public static final Complex ZERO = new Complex(0.0); 4.不可变对象为其他对象提供了大量构件,其他对象无论是否可变. 缺点:…
1.公有类永远都不应该暴露可变的域.如果域是不可变的,暴露公有类的危害就要小一些. 但是,有时候需要用包级私有的或者私有的嵌套类来暴露域,无论这个类是否可变 2.如果公有类暴露了它的访问域,要想在将来改变其内部表示法是不可能的,因为公有类的客户端代码已经遍布隔出来 当域被读取的时候,强加约束 public final class TimeManager { private static final int HOURS_PER_DAY = 24; private static final int…
1.为什么要使类和成员可访问性最小化 它可以有效地解除组成系统的各模块之间的耦合关系,使得这些模块可以独立的开发 测试 优化 使用 理解和修改.提高软件的可重用性 2.成员的访问级别 私有(private):只有在声明该成员的顶层类内部才可以访问这个成员 包级私有(package-private):声明该成员的包内部的任何类都可以访问这个成员(缺省访问级别) 受保护的(protected):声明该成员的类的子类可以访问该成员 公有的(public)在任何地方都可以访问该成员 3.类具有公有的静态…
考虑实现Comparable接口 compareTo方法 Comparable接口的唯一方法,允许进行简单的等同性比较,允许执行顺序比较 Comparable接口被所有值类实现.所以如果一个值类有非常明显的内在排序关系,应该考虑实现该接口 public interface Comparable{ int compareTo(T t); } 它的通用约定与equals相似 -- 自反性:sgn(x.compareTo(y))==-sgn(y.compareTo(x)) 传递性:(x.compare…
java中的clone clone构造器及其静态工厂的变形 优点:它们不依赖于某一种很有风险的,语言之外的对象创建机制; 它们不要求遵守尚未制定好文档的规范 他们不会于final域的正常使用发生冲突 它们不会抛出不必要的受检异常 它们不需要进行类型转换 /** * 1.必须继承Cloneable接口 * 2.必须重写Object类中的clone()方法 – * Cloneable接口改变了接口的通用规范,它改变了超类中受保护的方法的行为 * –无需构造器就可以创建对象 * a.clone对象分配…