(1)Java语言支持四种类型:接口、类、数组、基本类型(primitive),前三种为引用类型,而基本类型的值不是对象。java
(2)方法的签名包括它的名称和全部参数的类型,签名不包括它的返回类型。sql
(1)静态工厂有名称数据库
(2)没必要再每次调用都建立一个新的对象数组
public static Boolean valueOf(boolean b){ return b? Boolean.TRUE : Boolean.FALSE; }
(3)能够返回原返回类型的任何子类对象缓存
适用于返回类型为接口/抽象类安全
public interface Service { // Service-specific methods go here } public interface Provider { Service newService(); } public class Services { private Services() { } // Prevents instantiation (Item 4) // Maps service names to services private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>(); public static final String DEFAULT_PROVIDER_NAME = "<def>"; // Provider registration API public static void registerDefaultProvider(Provider p) { registerProvider(DEFAULT_PROVIDER_NAME, p); } public static void registerProvider(String name, Provider p){ providers.put(name, p); } // Service access API public static Service newInstance() { return newInstance(DEFAULT_PROVIDER_NAME); } public static Service newInstance(String name) { Provider p = providers.get(name); if (p == null) throw new IllegalArgumentException( "No provider registered with name: " + name); return p.newService(); } }
客户端
ide
public class Test { public static void main(String[] args) { // Providers would execute these lines Services.registerDefaultProvider(DEFAULT_PROVIDER); Services.registerProvider("comp", COMP_PROVIDER); Services.registerProvider("armed", ARMED_PROVIDER); // Clients would execute these lines Service s1 = Services.newInstance(); Service s2 = Services.newInstance("comp"); Service s3 = Services.newInstance("armed"); System.out.printf("%s, %s, %s%n", s1, s2, s3); } private static Provider DEFAULT_PROVIDER = new Provider() { public Service newService() { return new Service() { @Override public String toString() { return "Default service"; } }; } }; private static Provider COMP_PROVIDER = new Provider() { public Service newService() { return new Service() { @Override public String toString() { return "Complementary service"; } }; } }; private static Provider ARMED_PROVIDER = new Provider() { public Service newService() { return new Service() { @Override public String toString() { return "Armed service"; } }; } }; }
(4)建立参数化实例更简洁性能
public static <K,V> HashMap<K,V> newInstance(){ return new HashMap<K,V)(); }
(5)静态工厂惯用名称ui
valueOf,of,getInstance,newInstance,getType,newType
构造器的参数太多的话,调用方容易混淆,特别是针对相邻的同类型的参数,若是不当心将顺序颠倒,则编译时难以发现,运行时出问题。this
(1) 重叠构造器版本,好处是安全性,坏处是难以阅读
public class NutritionFacts { private final int servingSize; // (mL) required private final int servings; // (per container) required private final int calories; // optional private final int fat; // (g) optional private final int sodium; // (mg) optional private final int carbohydrate; // (g) optional public NutritionFacts(int servingSize, int servings) { this(servingSize, servings, 0); } public NutritionFacts(int servingSize, int servings, int calories) { this(servingSize, servings, calories, 0); } public NutritionFacts(int servingSize, int servings, int calories, int fat) { this(servingSize, servings, calories, fat, 0); } public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) { this(servingSize, servings, calories, fat, sodium, 0); } public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate) { this.servingSize = servingSize; this.servings = servings; this.calories = calories; this.fat = fat; this.sodium = sodium; this.carbohydrate = carbohydrate; } public static void main(String[] args) { NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27); } }
(2)JavaBean版本,好处是可读性,坏处是本身要保证线程安全
public class NutritionFacts { // Parameters initialized to default values (if any) private int servingSize = -1; // Required; no default value private int servings = -1; // " " " " private int calories = 0; private int fat = 0; private int sodium = 0; private int carbohydrate = 0; public NutritionFacts() { } // Setters public void setServingSize(int val) { servingSize = val; } public void setServings(int val) { servings = val; } public void setCalories(int val) { calories = val; } public void setFat(int val) { fat = val; } public void setSodium(int val) { sodium = val; } public void setCarbohydrate(int val) { carbohydrate = val; } public static void main(String[] args) { NutritionFacts cocaCola = new NutritionFacts(); cocaCola.setServingSize(240); cocaCola.setServings(8); cocaCola.setCalories(100); cocaCola.setSodium(35); cocaCola.setCarbohydrate(27); } }
(3)Builder版本,兼容两者好处
public class NutritionFacts { private final int servingSize; private final int servings; private final int calories; private final int fat; private final int sodium; private final int carbohydrate; public static class Builder { // Required parameters private final int servingSize; private final int servings; // Optional parameters - initialized to default values private int calories = 0; private int fat = 0; private int carbohydrate = 0; private int sodium = 0; public Builder(int servingSize, int servings) { this.servingSize = servingSize; this.servings = servings; } public Builder calories(int val) { calories = val; return this; } public Builder fat(int val) { fat = val; return this; } public Builder carbohydrate(int val) { carbohydrate = val; return this; } public Builder sodium(int val) { sodium = val; return this; } public NutritionFacts build() { return new NutritionFacts(this); } } private NutritionFacts(Builder builder) { servingSize = builder.servingSize; servings = builder.servings; calories = builder.calories; fat = builder.fat; sodium = builder.sodium; carbohydrate = builder.carbohydrate; } public static void main(String[] args) { NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8). calories(100).sodium(35).carbohydrate(27).build(); } }
newInstance方法可充当build方法的一部分,可是它老是企图去调用类的无参构造器,若是类没有无参构造器,编译时是不会暴露出来的,只能到客户端调用运行时才暴露。
(4)实践版
通常好比sql构造之类的,参数太多,能够用builder模式,普通bean的赋值,采用builder反而搞得太过负责,工业上的最佳实践,通常是采用JavaBean + Design by Contract 的模式,要求开发者根据约定传参数,service层再进行一层校验,来确保必填参数是不为null的。
(1)私有构造器可以防止经过反射调用去构造实例
(2)为确保反序列化以后仍是单例,须要重写readResolve方法,return INSTANCE,或者直接使用枚举单例,它内置了反序列化单例的功能。
(1)达到尽可能重用对象的目的,好比字符串字面常量,不可变的对象。
反例
public class Person { private final Date birthDate; public Person(Date birthDate) { // Defensive copy - see Item 39 this.birthDate = new Date(birthDate.getTime()); } // Other fields, methods omitted // DON'T DO THIS! public boolean isBabyBoomer() { // Unnecessary allocation of expensive object Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0); Date boomStart = gmtCal.getTime(); gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0); Date boomEnd = gmtCal.getTime(); return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0; } }
正解:使用静态初始化器,初始化起止日期
class Person { private final Date birthDate; public Person(Date birthDate) { // Defensive copy - see Item 39 this.birthDate = new Date(birthDate.getTime()); } // Other fields, methods /** * The starting and ending dates of the baby boom. */ private static final Date BOOM_START; private static final Date BOOM_END; static { Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0); BOOM_START = gmtCal.getTime(); gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0); BOOM_END = gmtCal.getTime(); } public boolean isBabyBoomer() { return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0; } }
(2)优先使用基本类型,而不是封装类型,小心无心识的自动装箱额外产生的对象,下面的sum声明为long,便可减小2的31次方个多余的Long实例。
public class Sum { // Hideously slow program! Can you spot the object creation? public static void main(String[] args) { Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); } }
(3)对象建立的误解
误解:对象建立的代价很是昂贵,应该避免建立对象。
正解:小对象的建立,构造器只作不多量的显式工做,其建立和回收都是很是廉价的,于是对小对象不必搞什么对象池之类的;只有重量级的对象,好比数据库链接池等,链接数据库代价是昂贵的,采用对象池正好。
public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; } /** * Ensure space for at least one more element, roughly * doubling the capacity each time the array needs to grow. */ private void ensureCapacity() { if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1); } }
出栈的时候没有清空引用
public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; return result; }
(1)清空对象引用应该是一种例外,而不是一种行为规范,没必要每次使用变量的时候,都紧张兮兮的,考虑要不要在使用后赋值为null
(2)内存泄露的常见来源
A、本身管理内存的容器
B、缓存
C、监听器和回调方法(注册监听,不须要的时候没有取消监听)
(1)JVM不保证finalize方法会被及时执行,并且根本不保证它们会被执行
(2)不要依赖finalize方法去关闭重要资源,好比关闭文件、关闭数据库链接,通常采用finally语句便可
(3)使用finalize可能会形成额外的性能损失