总结
effecttive java 注意的地方简单概括下。
并发部分没有java并发编程实战全。就不写在这了
JDBC
java Database Connectivity java数据库连接
重叠构造器
这种构造器是什么,就是提供很多个构造函数。短的构造器,会给没有赋值的,给一个默认值。
public A(int i, int j) {
this(i, j ,0);
}
public A(int i, int j, int k) {
...
}
这种模式是可行,但是当有很多参数的时候,客户端代码会很难编写,并且仍然很难以阅读。
Build模式
new NutritionFacts.Build(1, 2).calories(11).sodium(23).build();
优秀的可读性、有保证重复构造器模式的安全性。
不足: 为了创建对象,要先构造它的构造器。 只有在很多参数的时候才使用,比如4个活着更多的参数。
如果类的构造器活着静态工厂中具有多个参数,设计这种类的时,Build模式就是种不错的选择。
singleton
最原始的singleton
public class Singleton
{
private volatile static Singleton singleton = null;
private Singleton() { }
public static Singleton getInstance() {
if (singleton== null) {
synchronized (Singleton.class) {
if (singleton== null) {
singleton= new Singleton();
}
}
}
return singleton;
}
}
私有构造器单例模型
public class Elvis {
public static final Elvis instantce = new Elvis();
private Elvis() {...}
}
但是某些客户端可以反射机制调用私有构造器,所有要防止其他人调用私有的构造器,要在创建第二个实例的时候抛出异常。
静态工厂方法
public class Elvis {
private static final Elvis instantce = new Elvis();
private Elvis() {...}
public static Elvis getInstance() {return instantce;}
}
但是这种会在类构造的时候就会调用。所以用下面这种:
由于 SingletonHolder 是私有的,除了 getInstance() 之外没有办法访问它,因此它只有在getInstance()被调用时才会真正创建;
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举Singleton
public enum Elvis {
INSTANCE;
}
单例序列化问题
要实现readResolve()函数;
而枚举enum单例不需要处理这个
最佳的实现方法
怎样实现不可实例化的能力,比如说一些静态类
让这类包含私有的构建器
避免自动装箱autoboxing
Long sum = 0l;
for(int i = 0; i < Interger.Max_Value; i++) {
sum += i;
}
这个启示会构建大约 2的31次方个Long实例。
如果用long而不是Long,就可以解决
优先使用基本类型而不是装箱的基本类型。
java的什么时候需要考虑内存泄漏的问题
只要是类自己管理内存的,比如说实现了一个对象池,堆栈,就应该警惕内存泄漏的问题
缓存
监听器和其他回调(因为要保存需要回调的客户端,这里最好只保存弱引用,否则可能会堆积)
java缓存,怎么实现,方法 ?
只要缓存之外存在某个项的引用,该项就有意义,可以用WeakHashMap代表缓存。
或者起一个后台线程定时清理
或者在新家条目的时候清理,LinkedHashMap removeEldestEntry,lRu
更复杂,使用java.lang.ref
弱引用是什么,有什么用?
终结方法的问题。
不应该依赖终结方法来更新重要的持久状态。因为java规范不保证他们会执行。
而且有严重的性能问题
子类中的终结方法不会自动调用父类的终结方法,必须要手动调
除非最为安全网,或者未来终止非关键多本地资源,否则不要使用终结方法。
object.equals方法
这些方法都要遵循约定,因为像hashset、list这些都遵循约定的。如果有问题会出错。
-
自反性
-
对称性
这里要注意子类和父类的equals结果可能不一样。
-
传递性
同样对于子类和父类有问题。
-
一致性
另外注意点:
float和double要单独比较。
不要将equals中的Object替换成其他class,因为这样就没有覆盖了
重写了equals方法点要重写hashcode()
因为hashMap这些如果没重写,会有问题。
规则见书
DAO
Data Access Object
接口优于抽象类
接口可以继承自两个接口
常量接口
是不良使用!类如果继承类常量接口,它的所有子类的命名空间也会被接口中的常量所污染。
应该用什么呢:
枚举类型
不可实例化的工具类,private的构造函数。
类层次优于标签类
就是说在class中加type,不如编写不同形式的class
策略模式
比如Arrays.sort(arrays, new Comparator<String> {
public int compare(String s1, s2) {
}
})
java中实现这种模式,要声明一个接口来表示该策略,然后为每一个具体策略声明一个实现了该接口的类。
通常用匿名类
当一个具体策略是设计用来重复使用的,别实现为私有的静态成员类,并通过公有的静态final 域被导出。
public class A {
private final B = new B();
private static class B imple... {
private String name;
private int age;
}
}
嵌套类
-
静态成员类
如果是public,就最好看做一个普通的类,只是碰巧申明在内部
可以访问外围类的所有static成员,包括私有
如果是private,他就只能在外围类的内部才能访问。 -
非静态成员类
非静态成员类与一个外部类相关联,可以直接调用外部类的非static方法
泛型
Set<Object> 是一个参数化类型,可以包含任意对象的集合。但是如果Set<String> 传进来,会报错
Set<?> 是一个通配符类型,不能将任何(除了null)放到里面
Set 是一个原生态类型,它脱离了泛型类型。
class DelayQueue<E extends Delayed> . 可以有extends的泛型,传进来的必须是这个的子类。
总而言之,泛型比在客户端代码中进行类型转换更安全,也更容易。
List优于数组
这些数组创建表达式不合法:
new List<E>[]
new List<String>[]
new E[]
传一个类的超类子类进泛型函数
如果要传一个子类进函数,进行处理。用 do(Iterable<? extends E> src)
如果需要一个类的超类传进函数,用do(Iterable<? super E>)
如果想对<?>的list进行操作怎么办
因为这种只能插null。那么需要定义一个泛型的辅助方法
枚举
- 枚举天生是不可变的,所有的域都应该是final的,他们可以是公有的,但最好做成私有的.
- ordinal 返回每个枚举常量的位置,但是不要用这个,除非自己写一个enumSet这种东西的时候。
- enumSet很快,相当于位域实现,实际就是用一个long来标记。
- enumMap很快,相当于一个数组,index就是用ordinal,所以get的时候很快
- 枚举可以extents吗?不行
每种枚举类实现的方法不同怎么实现
可以用抽象方法
public enum Operation {
PLUS {double apply(double a, double b){return a + b}},
SUB {double apply(double a, double b){return a - b}},
abstract double apply(double a, double b);
}
当想给枚举分类,不同类的枚举用不同的策略,怎么实现
多个枚举常量同时共享相同的行为时,则考虑枚举策略
enum PayrollDay {
MON(PayType.WEEKDAY),TUE(PayType.WEEKDAY)
....SAT(PayType.WEEKEND), SUN(PayType.WEEKDAY);
...
private final PayType type;
double pay() {
return type.pay();
}
private enum PayType {
....
abstact double pay();
}
}
注解
一般的自己的注解
@Retention(RetentionPolicty.RUNTIME)
@Targe(ElementType.METHOD/CLASS)
可变参数
可变参数每次调用都会导致一次数组的分配和初始化,性能不如正常函数。
要精确计算浮点应该用什么
float和double不准,要不就用整数,然后确定有效位。
或者使用BigDecimal(不过有点慢)
装箱类型
每次与基础类型进行混合计算时,都会自动拆箱和装箱。要考虑性能问题
StringBuild,StringBuffer
StringBuffer线程安全,但没有StringBuild速度快
反射
反射利用了 java.lang.reflect 包里。
但是反射调用回避普通方法慢很多
并发
Thread.stop 不安全,不要用。可能导致数据破坏
不要依赖线程调度器
线程组已经过时了,不要用
executor 和task 优于线程
- Executors.newCachedThreadPool 每次如果不够久新建线程。
- Executors.newFixedThreadPool 提供了一个包换固定线程的线程池
- ScheduledThreadPoolExecutor 用来代替timer
网友评论