0815实习培训随记
                魔鬼数字
用有意义的常量代替字面量数字
- 便于理解和替换
 
常用枚举类型代替枚举含义的变量
- 典型的反例是C中习惯用
return 0表示正确执行 
对于局部的字面量可以只用注释说明,如单位换算没必要用常量替换10/100/1000等
反例
int ONE=1
不推荐但允许的情况
int HOUR_12 = 12 //12小时制
并发工具
略
单例模式
1  | public class Single {  | 
lazyinit
1  | public class Single {  | 
把getInstance整个方法都同步,实际应用中抢占并初始化单例对象并非常见情况,这么做会严重影响性能
DoubleCheck
1  | public class Single {  | 
只锁静态类,保证了日常调用的性能,同时doublecheckinst == null保证了不会初始化多个对象
利用classLoader的特性(更推荐)
1  | public class Single {  | 
利用类加载的特性,只有在调用getInstance的时候才会加载SingleHolder内部类,同样实现了lazyinit的效果
验证Volatiole
1  | public class StopThread {  | 
基本型偏执
1  | public int deposit(int money)  | 
- 便于理解
 - 编译器的语义检查
 - 提供了对Money的行为放置场所
 - 便于扩展,例如精度修改等
 
线程不安全的对象
DateFormat等不一定是线程安全的
位运算
有符号右移:>>
无符号右移:>>> 负数补0而非1
1  | byte i = (byte) 0xf3; //1111 0011  | 
对于>>>运算左边如果是byte/char/short,会先转换为int
1  | byte i = (byte) 0xf3; //1111 0011  | 
非短路运算
短路与:&&
位与运算:&
常量右置:左侧倾向于变化、右侧倾向于不变
- 在C中会采用常量左置,如
if(null == a),此时如果写成=编译器报警 - Java中的例外
"foo".equals(var),反之则需要if(var != null)... 
静态成员类
非静态成员
- 可以访问外围类的成员,等效于外围类的一个非静态方法
 - 必须依附于外围类的实例对象
 - 需要维护和实例对象的关联关系
 
静态成员(更加常用)
- 只能访问静态成员
 - 不需要维护关联关系,少了空间和时间开销
 
equals覆写
覆写equals时也应当覆写hashcode
Hash集合依赖于hashCode决定索引和返回
- 保证equals的对象,hashcode必须相等
 - 否则会出现找不到值的情况
 
其中equals的原型为:
1  | public boolean equals(Object o)  | 
重写HashCode
- 把某个非零常数保存在一个叫result的的变量(通常是质数,如17)
 - 对于每一个成员字段,完成以下步骤
 
- result = 31 * result +c
 - boolean f?0:1
 - byte/char/short/int (int)f
 - long (int)(f^(f>>>32))
 - float Float.floatToIntBits(f)
 - double Double.doubleToIntBit
 
Locale
对于不同语言的大小写可能有不同规则,要指定Locale转换方式
调用toUpperCase()时,默认调用toUpperCase(Locale.getDefault())
例如String name=aquickbrownfoxjumpoverthelazydog
应当调用name.toUpperCase(Locale.ENGLISH)
size
- byte - 1字节
 - char - 2字节
 - String - char串而非byte串,二进制协议编解码时应当注意
 
常量池
Integer a = -128和Integer a=Integer.valueOf(-128)都会应用常量池
只有new出来的会在堆里创建新对象
永远用valueOf和equals进行包装类的创建和比较
不要对包装类使用synchronized,否则会因为常量池意外获得同一把锁
Long/Short
- -128~127
 
Byte/Boolean
- 全部缓存
 
Float/Double
- 全部不缓存
 
String.intern()
- 永远返回常量池的String对象
 - 当且仅当s.equals(t)时,有s.intern()==t.intern()
 
异常关闭
在fianlly中关闭资源
- close某个资源时如果close方法本身也抛异常,如果不捕获会导致后面的资源无法关闭
 
建议使用try-with-resource写法
- 多个资源抛出异常时会保留第一个异常,并将后续异常作为
Supressed Exceptions,可以通过getSuppressed()捕获 
1  | try(...){  | 
暴露和拷贝
1  | public void getA(){  | 
根据实际情况设计采用暴露还是拷贝
substring在Java7之后变为深拷贝
引用和指针
Java中的引用在行为上更接近C中的指针
1  | public static void main(String[] args){  | 
类的访问修饰符
- public > protected > default > private
 - protected除内部文件的类可见外,外部文件的子类也可见
 - default仅有内部文件的类可见
 
对于同一个package的default类,他们互为友元,可以让同一个package内的类互相访问private对象
- default打通了package的类
 - protected打通了继承树的类
 
暴露增加了修改的困难程度,暴露n个方法就会被外界调用n个方法,想要修改逻辑就要同时考虑n个对外的接口
多态的优先级
不建议利用如下优先级
- this.func(args)
 - super.func(args)
 - this.func((super)args)
 - super.func((super)args)
 
建议多使用@Override增加可读性
多态的设计模式——策略模式
SAP Breaker——破坏软件抽象
最稳定的类/被依赖的类应当是最抽象的类,反之亦然
- 依赖倒置
 
业务->基础设施
业务->基础设施接口<-基础设施
正方形悖论
正方形 is a 长方形
SOLID原则
- SIngle Responsibility Principle 单一职责
 - Open-Closed Principle 开闭原则
- 只是一个期望,往往难以实现
 
 - Liskov Substitution Principle 里氏替换原则
- 最重要的,不可违背
 
 - Interface Segregation Principle 接口隔离原则
 - Dependency Inversion Principle 依赖倒置原则