标签:
常用的场景是,查询时,有多个参数。因此构建查询参数对象时,考虑使用Builder模式。
public class QueryBuilder {
//查询的每个参数,不需要set方法
private String userName;
private String mobile;
private int cityId;
private int pageNum;
private int pageSize;
//提供一个Builder实例
public static Builder newBuilder(){
return new Builder();
}
//共有的public 静态static内部类
public static class Builder{
private String userName;
private String mobile;
private int cityId;
private int pageNum;
private int pageSize;
//每个方法都是公有的
public Builder withUserName(String userName){
this.userName = userName;
return this;
}
public Builder withMobile(String mobile){
this.mobile = mobile;
return this;
}
public Builder withCityId(int cityId){
this.cityId = cityId;
return this;
}
public Builder withPageNum(int pageNum){
this.pageNum = pageNum;
return this;
}
public Builder withPageSize(int pageSize){
this.pageSize = pageSize;
return this;
}
//最后提供一个build方法,返回查询类
public QueryBuilder build(){
return new QueryBuilder(this);
}
}
//查询类构造方法私有,接收一个Builder参数
private QueryBuilder(Builder builder){
userName = builder.userName;
mobile = builder.mobile;
cityId = builder.cityId;
pageNum = builder.pageNum;
pageSize = builder.pageSize;
//可以根据需要提供一个boolean hasQuery字段,用于判断是否有查询条件
//没有查询条件时,返回所有值
/*hasQuery = StringUtils.isNotEmpty(userName)
|| StringUtils.isNotEmpty(mobile)
|| cityId > 0;
*/
}
}
public String getUserName() {
return userName;
}
public String getMobile() {
return mobile;
}
public int getCityId() {
return cityId;
}
public int getPageNum() {
return pageNum;
}
public int getPageSize() {
return pageSize;
}
public boolean isHasQuery() {
return hasQuery;
}
//使用
QueryBuilder.Builder builder = QueryBuilder.newBuilder();
QueryBuilder query = builder.withUserName("name1").withMobile("13456463216")
.withCityId(1).withPageNum(0).withPageSize(10)
.build();
这里主要写一下Java的Sigleton模式吧,下文讨论的内容引入了其他博文
http://blog.csdn.net/cnyyx/article/details/7482735
http://my.oschina.net/alexgaoyh/blog/261106?fromerr=FT8qyEHA
public class Singleton {
//私有化构造器,防止外部new Singleton()
private Singleton(){}
private static final Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
这种方法在类加载的时候就会创建一个Singleton对象,不管该资源是否被请求,占用Jvm内存。
public class Singleton {
private Singleton(){}
private static Singleton instance;
public static synchronized Singleton getInstance(){
if(null == instance){ //@1
instance = new Singleton(); //@2
}
return instance;
}
}
该方法加载了同步锁,可以防止多线程在执行getInstance方法得到2个对象,如果不加synchronized关键字,考虑线程A、B
A执行 @1 还未执行 @2
B执行 @1 还未执行 @2
将会得到2个对象
缺点:只有在第一次调用的时候才需要同步,一旦instance部位null了,系统依旧花费同步锁开销,有点得不偿失
private Singleton(){}
private static Singleton instance;
public static Singleton getInstance(){
if(null == instance){ //@1
synchronized (Singleton.class){ //@2
instance = new Singleton(); //@3
}
}
return instance;
}
这种写法减少了锁开销,但是在如下情况,却创建了2个对象:
a:线程1执行到1挂起,线程1认为singleton为null
b:线程2执行到1挂起,线程2认为singleton为null
c:线程1被唤醒执行synchronized块代码,走完创建了一个对象
d:线程2被唤醒执行synchronized块代码,走完创建了另一个对象
所以看出这种写法,并不完美。
private Singleton(){}
private static Singleton instance;
public static Singleton getInstance(){
if(null == instance){ //@1
synchronized (Singleton.class){//@2
if(null == instance){//@3
instance = new Singleton();//@4
}
}
}
return instance;
}
在同步锁代码块内部,再判断一次对象是否为null,为null才创建对象。这种写法已经接近完美:
a:线程1执行到1,已经进入synchronized的时候,线程挂起,线程1占有Singleton.class资源锁;
b:线程2执行到1,当它准备synchronized块时,因为Singleton.class被占用,线程2阻塞;
c:线程1被唤醒,判断出对象为null,执行完创建一个对象
d:线程2被唤醒,判断出对象不为null,不执行创建语句
如此分析,发现似乎没问题。
但是实际上并不能保证它在单处理器或多处理器上正确运行;
问题就出现在singleton = new Singleton()这一行代码。它可以简单的分成如下三个步骤:
mem= singleton();//1
instance = mem;//2
ctorSingleton(instance);//3
这行代码先在内存开辟空间,赋给singleton的引用,然后执行new 初始化数据,但是注意初始化是要消耗时间。如果此时线程3在执行步骤1的时候,发现singleton 为非null,就直接返回,那么线程3返回的其实是一个没构造完成的对象。
我们期望1,2,3 按照反序执行,但是实际jvm内存模型,并没有明确的有序指定。
这归咎于java的平台的内存模型允许“无序写入”。
private Singleton(){}
private static volatile Singleton instance;
public static Singleton getInstance(){
if(null == instance){ //@1
synchronized (Singleton.class){//@2
if(null == instance){//@3
instance = new Singleton();//@4
}
}
}
return instance;
}
Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。
但是5的写法,虽然理论上似乎可以解决无序写入问题。实际上并非如此。
private Singleton(){}
private static class InstanceHolder{
private static final Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return InstanceHolder.instance;
}
JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,
并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题(方法4)。此外该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低效问题(方法2)。
最后instance是在第一次加载InstanceHolder类时被创建的,而InstanceHolder类则在调用getInstance方法的时候才会被加载,因此也实现了惰性加载。
public enum A{
INSTANCE;
public void invoke(){...}
}
有时候可能需要编写只包含静态方法和静态域的类,如工具类。最好给其提供一个私有构造器,否则编译器会为其生成一个默认的无参构造函数。
public class MobileUtils {
private MobileUtils(){}
/**
* 隐藏手机号中间4位
* @param mobile
* @return String 隐藏手机号中间4位之后的手机号
*/
public static String hideMobile(String mobile) {
if (StringUtils.isEmpty(mobile)) {
return StringUtils.EMPTY;
}
if (mobile.length() < 8) {
return StringUtils.EMPTY;
}
return mobile.substring(0, 3) + "****" + mobile.substring(7);
}
}
对于同时提供了构造器和静态工厂方法,通常使用静态工程方法而不是构造器,以避免
创建不必要的对象,比如Boolean.valueOf(String)比new Boolean(String)要好,构造器每次
被调用时都要创建一个新的对象,静态工厂方法则没有这种要求,也不会这样做
下面是Boolean的部分源码,查看其valueOf方法
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(String s) {
return toBoolean(s) ? TRUE : FALSE;
}
private static boolean toBoolean(String name) {
return ((name != null) && name.equalsIgnoreCase("true"));
}
这里只能说学习,主要看的是ArrayList吧,对不用的对象是如何处理的。
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// clear to let GC do its work 就是这里!
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,int length);
简单总结一下:
1、是否是同一个对象的引用
2、类型转换
3、域的比较,在比较时,优先比较区分度大的域
注意:这里有个坑:equals方法的参数是Object,而不是自己定义的类。否则直接变成代码重载,而不是重写了!!
@Override的作用也可以看到了 书中36条:坚持使用Override注解
@Override
public boolean equals(Object anObject) {
if (this == anObject) {//是否是同一个对象的引用
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;//转换为该对象类型
int n = value.length; //管家field的值比较,先比较区分度比较大的!
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
主要考虑Java 深拷贝和浅拷贝
浅拷贝(浅复制、浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。
换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
深拷贝(深复制、深克隆):被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,
而不再是原有的那些被引用的对象。
换言之,深拷贝把要复制的对象所引用的对象都复制了一遍。
clone基本类型 深拷贝
clone对象类型 浅拷贝,重写clone方法,将对象引入一一clone,即可实现深拷贝
// 改为深复制:
Student2 student = (Student2) super.clone();
// 本来是浅复制,现在将Teacher对象复制一份并重新set进来
student.setTeacher((Teacher) student.getTeacher().clone());
serialization序列化 深拷贝
类的比较,主要有两种方法,一种是类实现Comparable接口,重写compareTo方法;另外一种是在集合比较的时候,新建一个Comparator,重写compare方法。与书中hashCode讲解有点关系的部分是:hashCode影响:HashSet、HashMap、HashTable
compareTo影响:TreeSet、TreeMap、Collections、Arrays。
自我感觉关于整数比较时,尽量直接<>直接比较,通过减法有可能溢出!
另外,有点不太相关的内容,在比较时,返回-1、0、1表示大小关系,其实只要返回一个符号(正负)就行,看到了Long的signum方法
public static int signum(long i) {
return (int) ((i >> 63) | (-i >>> 63));
}
直接通过移位,不需要比较操作符,一句话搞定!吊吊的!Long的rotate和reverse也很吊!
标签:
原文地址:http://blog.csdn.net/bupt09211303/article/details/51603747