文章标签 » Java

[译文]设计模式06 – 单例模式(附代码实例)

原文网址:Singleton Pattern

意图

  • 确保一个类只存在一个实例,并供全局访问
  • 适时初始化,或者在第一次使用时初始化

问题

应用程序需要一个,并且只需要一个对象的实例。另外,延迟初始化和全局访问是必要的。

讨论

单例的职责有:创建、初始化,访问和执行。声明一个私有的、静态的成员变量;提供一个公共的、静态的方法来封装初始化代码,并访问该实例。

客户端可以随时调用这个静态方法来获取单例。

Continue Reading »

[译文]设计模式05 – 原型模式(附代码实例)

原文网址:Prototype Pattern

意图

  • 创建指定对象的原型实例,然后通过复制这个原型来创建更多的实例
  • 指派一个类的一个实例用于育种该类的未来所有的实例
  • new 操作是危险的

问题

应用程序在使用 new 操作时跟对象产生了“硬连接”(耦合)。

讨论

定义一个可供“克隆”的接口方法,维护一个包含所有“可克隆”的具体衍生类的“注册表”。每一个类都具有“多态性”:继承自基类或者接口,注册它的原型实例,实现了“克隆”方法。

作为客户端,不用再使用跟跟类名“硬连接”的 new 操作了,而是调基类的 clone 方法,通过字符串或者枚举值类型来指定具体的衍生类。

Continue Reading »

[译文]设计模式04 – 对象池模式(附代码实例)

原文网址:Object Pool Pattern

意图

对象池对性能有显著的提升。在以下场景中最有效:实例化过程复杂的对象;实例化频率高的对象;同一时刻用到的实例数量较少。

问题

对象池(也叫资源池)是用来管理对象缓存的。一个使用了对象池的客户端可以请求对象池中已经存在的实例,而不用自己创建。一般来说,这个对象池是可以自动增长的,当它是空的时候可以自己创建对象。或者我们可以限定对象池的大小。

将所有可重复使用的、当前未使用的对象放在同一个对象池中以保证其连贯性是有必要的。为了达到这个目的,对象池应该是单例的。

讨论

对象池允许其他程序从中获取对象,当用完后在放回池中,以便下次再用。

但是我们不会一直等着某个对象被释放,所以在必要的时候对象池可以创建新的对象,但一定要有定期清理未使用的对象的机制。

Continue Reading »

[译文]设计模式03 – 工厂方法模式(附代码实例)

原文网址:Factory Method Design Pattern

意图

  • 定义一个用来创建对象的接口,由其子类(实现类)决定哪个类应该被初始化。工厂方法把类的初始化过程延迟到子类里
  • 定义一个虚拟的构造器
  • new 是危险的操作

问题

一个框架需要对其架构模型有一套标准化的操作规范,但对一个单独的应用来说,可以定义不同的作用域对象及其初始化过程。

讨论

工厂方法模式是为了创建对象,就像模板方法模式是为了实现一种算法。接口定义了标准的创建对象的方法(用纯虚拟的标识——如abstract——来修饰创建步骤),然后委托子类去完成创建的具体步骤,并将子类提供给客户端调用。

工厂方法模式使得设计具有更多的可定制化空间,而只是多了一点点复杂性。其他设计模式需要新的类,而它只需要新的操作(方法)。

大家经常使用工厂方法模式作为创建对象的标准方式,但以下情况就没有必要用了:初始化过程不会再改变的类,或者初始化过程被放在很容易被子类覆盖的方法里(如构造函数)。

工厂模式方法和抽象工厂很相似,只是少了那一组相关或类似对象。

工厂模式通常是在基础框架中定义,然后由使用者去实现。

Continue Reading »

[译文]设计模式02 – 构造器模式(附代码实例)

原文网址:Builder Design Pattern

意图

  • 将一个复杂对象的创建和它可能的表现形式分开,以便于同一个创建过程可以创建不同的表现形式
  • 分析一套繁杂的表现形式(最终产品),完成其中一个

问题

一个应用需要创建一个有很多元素组成的复杂的集合体。该集合体的具体内容存储在辅助存储器内(如文件),但其中某一种展现形式需要在主存储器(内存)中构建。

讨论

将解析(读取和分析)已存储的数据(如RTF文件)的算法与构建并展示众多表现形式(如ASCII,TeX,文本组件)之一的算法分开。重点在于创建一个复杂的集合体。

“主管”在解析底层数据时调用“构建者”。“构建者”每次被调用都构建这个复杂对象的某一部分,并且掌控所有中间状态。构建完成后,客户端可以从“构建者”处获取。

对创建过程有了更好的控制。不像之前的“抽象工厂模式”一步构建(new)对象,“构造器模式”是在“主管”的控制下一步步地完成构建。

Continue Reading »

[译文]设计模式01 – 抽象工厂模式(附代码实例)

原文网址:Abstract Factory Design Pattern

意图

  • 提供一个创建一组相关或相似对象的接口,而不用关心具体的类
  • 一种继承关系,包括了各种可能的”平台”和一组对象的创建
  • new 操作是有害的(言下之意就是少用)

问题

如果一个应用是便捷式的,那么它就要封装对平台的依赖。这里说的“平台”包括视窗系统、操作系统、数据库等等。通常这些封装不会提前设计,所以当要增加新的平台时 if 的条件语句就会像兔子一样在代码里到处乱串。

讨论

采用一种迂回的方式将一组类似或相关的对象的创建与具体的对象类隔离开来。工厂对象负责提供所有这一类对象的创建服务。客户端不用直接创建平台对象,让“工厂”去创建。

这样的机制使得不同“产品”之间的切换变得简单,因为具体的类只在工厂对象类里出现一次——实例化对象的地方。通过在抽象工厂里使用不同的具体实现类的方式,应用程序可以大规模地替换整个产品簇。

由于抽象工厂的方式使用得很普遍,它惯常用单例模式实现。

Continue Reading »

Java | @Override 不要再把它当成可有可无的了

@Override,一定不陌生吧!就是没敲过,也一定见过。
是不是觉得它可有可无,多它不多,少它不少?更有甚者,把它当个累赘。
不爱搭理它就算了。IDE帮你生成了你还要删掉它,这就有点过分了哈。
它真的是毫无用处吗?开发JDK和IDE的大神们造了个无用的东西?

看看下面这个例子,请你来找茬儿。

IShape类

1
2
3
public interface IShape {
    String introduceYourself();
}

Rectangle类

1
2
3
4
5
public class Rectangle implements IShape {
    public String introduceYourself() {
        return "我是一个长方形。";
    }
}

Square类

1
2
3
4
5
public class Square extends Rectangle {
    public String introduceYouself() {
        return "你可以叫我长方形,但它并不是我的真名。我的真名叫正方形。";
    }
}

测试类

1
2
3
4
5
6
7
8
public class AnnotationTest {
    @Test
    public void introduceYourself() {
        IShape aShape = new Square();
        assertEquals("你可以叫我长方形,但它并不是我的真名。我的真名叫正方形。", 
        				aShape.introduceYourself());
    }
}

测试结果

java-annotation-override

IDEA JUnit 测试结果

这是为什么呢? 明明是一个正方形,它怎么偏说自己是个长方形呢?​​能看出是哪的问题吗? 如果还是找不到问题,在方法上添加​​​@Override注解看看。 是不是很神奇?

所以,请善待它吧! 其实之前我也没认识到这一点。是最近听了一个关于 Annotation的课才知道它还有这个用处。​

相关链接

Eclipse | 导入(import)不想要星号(*)?

或出于个人喜好,或出于编码规范,import语句里不想/不能带有星号(*):

1
import com.youngzy.*;

要改成:

1
2
3
import com.youngzy.Foo;
import com.youngzy.Bar;
...

如果你熟悉Eclipse的快捷键(不熟悉的话网上很容易查),组合键 Ctrl+Shift+O(字母O)应该就能达到你的要求。
但你有没有遇到这样的情况:删掉了*的这一行代码,通过上述快捷键补全的代码仍然是xxx.*

时灵时不灵?
你都要怀疑是不是Eclipse有Bug了。(好吧,是我在怀疑^_^)

上网各种搜,噢,原来还有个叫Organize Imports的东西。

Eclipse里打开 Preferences,搜索框里输入 import ,你会看到 Java-Code Style-Organize Imports ,下方有两个数字,代表如果同一个包下需要导入的类太多(大于这里设置的数字),就会用*代替,而不是具体到类。默认值是 99 ,如图:

Eclipse-Preferences 截图

Eclipse-Preferences 截图

将其改大点,譬如 999,再回到代码里试试,是不是跟之前不一样了?

惊喜不惊喜?!

意外不意外?!

参考:
https://blog.csdn.net/qq_34068082/article/details/80096646

 

多线程与线程安全(实例讲解)

什么情况下需要关注线程安全问题?
就是多个线程会对某个变量同时执行读/写操作的时候。

问题

举个常用但没太注意过的例子 —— SimpleDateFormat 类。
这个类是JDK里面封装的,用来对日期进行格式化。提供 parse(String dateStr), format(Date date) 等方法。

注:上面提到的方法都在其父类 DateFormat 中。

翻开源代码就会发现,它有一个实体变量 calendar (也是在父类 DateFormat 中)。上面提到的 parse 、format 等方法会对这个变量执行 clear() 、set…(…) 等操作(具体操作请查看源代码)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class DateFormat extends Format {

    /**
     * The {@link Calendar} instance used for calculating the date-time fields
     * and the instant of time. This field is used for both formatting and
     * parsing.
     *
     * <p>Subclasses should initialize this field to a {@link Calendar}
     * appropriate for the {@link Locale} associated with this
     * <code>DateFormat</code>.
     * @serial
     */
    protected Calendar calendar;

    ...

}

这样,如果有一个类型为 SimpleDateFormat 的公共变量,就要小心了,这个变量不是线程安全的,多个线程间的数据可能会串了…几乎是一定会串。

例如,有这样一个日期的工具类,就是将日期转换成特定的字符串格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * 
 *
 * @author by youngz
 *      on 2016年11月27日
 *
 * Package&FileName: org.young.thread.DateUtil
 */
public class DateUtil {

	public final static String PATTERN_YMD = "yyyy-MM-dd";
	
	private static SimpleDateFormat formatter = new SimpleDateFormat();
	
	public static String getFormattedDate(Date date) {
		formatter.applyPattern(PATTERN_YMD);
		return formatter.format(date);
	}
}

这是测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * 测试类
 *
 * @author by youngz
 *      on 2016年11月27日
 *
 * Package&FileName: org.young.thread.Main
 */

public class Main {

	public static void main(String[] args) {
		// 昨天的日期
		Calendar calYesterday = Calendar.getInstance();
		calYesterday.setTime(new Date());
		calYesterday.add(Calendar.DAY_OF_MONTH, -1);
		ShowDate yesterday = new ShowDate("YESTERDAY", calYesterday.getTime());
		
		// 今天的日期
		ShowDate today = new ShowDate("TODAY", new Date());
		
		Thread t1 = new Thread(yesterday);
		Thread t2 = new Thread(today);
		
		/*
		 * start() 
		 * 它的作用是启动一个新线程,新线程会执行相应的run()方法。start()不能被重复调用。
		 * run() 
		 * 就和普通的成员方法一样,可以被重复调用。单独调用s的话,会在当前线程中执行run(),而并不会启动新线程!
		 */
		t1.start();
		t2.start();
	}
}

还有一个线程类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
 * 一个简单的线程的实现类
 *
 * @author by youngz
 *      on 2016年11月27日
 *
 * Package&FileName: org.young.thread.ShowDate
 */
class ShowDate implements Runnable {

	private String desc;
	private Date date;
	
	public ShowDate(String desc, Date date) {
		this.desc = desc;
		this.date = date;
	}

	@Override
	public void run() {

		for (int i = 0; i < 1000; i++) {
			if (i % 30 == 0) {
				try {
					Thread.sleep(500L);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println(desc + ": " + DateUtil.getFormattedDate(date));
		}
	}
}

按照设想,以今天(2016-11-27)为例,应该是 YESTERDAY: 2016-11-26TODAY: 2016-11-27 这两个字符串交叉着,各自打印 1000 遍。
可事实是这样吗?
运行一下看看。
截图
结果简直惨不忍睹,第一行就出错了(当然,这个可能需要一定的“运气”)。“今天”一会儿 26,一会儿 27。“昨天”也一样,一会儿 26,一会儿 27。
这就是线程不安全导致的问题了。
该怎么解决呢??

解决办法(一) —— synchronized

比较容易想到的就是这个关键字了:synchronized 。在学校就是这么学的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 * 进化的 DateUtil
 * 使用同步块,synchronized
 *
 * @author by youngz
 *      on 2016年11月27日
 *
 * Package&FileName: org.young.thread.SyncDateUtil
 */
public class SyncDateUtil {

	public final static String PATTERN_YMD = "yyyy-MM-dd";
	
	private static SimpleDateFormat formatter = new SimpleDateFormat();
	
	public static String getFormattedDate(Date date) {
		synchronized(formatter) {
			
			formatter.applyPattern(PATTERN_YMD);
			return formatter.format(date);
		}
	}
}

只要把线程类 —— ShowDate 的第 30 行的工具类替换一下就行,DateUtil 换成 SyncDateUtil ,即:

1
2
//	System.out.println(desc + ": " + DateUtil.getFormattedDate(date));
	System.out.println(desc + ": " + SyncDateUtil.getFormattedDate(date));

在运行试试!
不管执行多少遍,都不会出现前面说的串数据的问题了。

解决办法(二) —— ThreadLocal

除了 synchronized 还有 ThreadLocal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * 进化的 DateUtil —— ThreadLocal
 *
 * @author by youngz
 *      on 2016年11月27日
 *
 * Package&FileName: org.young.thread.ThreadLocalDateUtil
 */
public class ThreadLocalDateUtil {

	public final static String PATTERN_YMD = "yyyy-MM-dd";
	
	private static ThreadLocal<DateFormat> formatter = new ThreadLocal<DateFormat>() {
		protected DateFormat initialValue() {
			return new SimpleDateFormat(PATTERN_YMD);
		}
	};
	
	public static String getFormattedDate(Date date) {
		return formatter.get().format(date);
	}
}

ThreadLocal 还有另一种实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
 * 进化的 DateUtil —— ThreadLocal 的另一种实现
 *
 * @author by youngz
 *      on 2016年11月27日
 *
 * Package&FileName: org.young.thread.ThreadLocalDateUtil2
 */
public class ThreadLocalDateUtil2 {

	public final static String PATTERN_YMD = "yyyy-MM-dd";
	
	private static ThreadLocal<DateFormat> formatter = new ThreadLocal<DateFormat>();
	
	public static DateFormat getDateFormat() {
		DateFormat df = formatter.get();
		
		if (null == df) {
			df = new SimpleDateFormat(PATTERN_YMD);
			formatter.set(df);
		}
		
		return df;
	}
	
	public static String getFormattedDate(Date date) {
		return getDateFormat().format(date);
	}
}

详细代码可参照 https://github.com/youngzhu/CollectionCode4Java/tree/master/src/org/young/thread

参考:
http://www.cnblogs.com/doit8791/p/4093808.html

 

从 Hibernate 3 升级到 Hibernate 4 序列号(Sequence)不能用 String 了?(已解决)

从 Hibernate 3 升级到 Hibernate 4 ,出现了这样的错误:

1
2
3
4
5
6
org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.String
at org.hibernate.id.IdentifierGeneratorHelper.getIntegralDataTypeHolder(IdentifierGeneratorHelper.java:215)
at org.hibernate.id.SequenceGenerator.buildHolder(SequenceGenerator.java:150)
at org.hibernate.id.SequenceGenerator.generateHolder(SequenceGenerator.java:126)
at org.hibernate.id.SequenceGenerator.generate(SequenceGenerator.java:116)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:118)

原来,在 Hibernate 4 中如果主键的生成策略是 Sequence ,则要求数据库中对应的字段必须为数字(Number,Long 等)类型。
而当前系统中使用的是字符串类型,所以报错了。

网上参考了几篇文章,就一篇(见文末)还不错。在此基础上,覆写了部分方法,解决了问题。

首先是 HISequenceGenerator 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package org.young.hibernate.common;

import java.io.Serializable;

import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.IntegralDataTypeHolder;
import org.hibernate.id.SequenceGenerator;

/**
 * 继承 hibernate 里的 SequenceGenerator 类,
 * 覆写2个方法:
 * 	1. buildHolder()
 * 	2. generate(SessionImplementor session, Object obj)
 *
 * @author by youngz
 *      on 2016年7月24日
 *
 * Package&FileName: org.young.hibernate.common.HISequenceGenerator
 */
public class HISequenceGenerator extends SequenceGenerator {

	@Override
	public Serializable generate(SessionImplementor session, Object obj) {
		
		/*
		 * 源码
		 * 
		 * return generateHolder(session).makeValue();
		 */
//		Serializable id = generateHolder(session).makeValue();
		Number id = generateHolder(session).makeValue();
		
		/*
		 * 笔者曾自作聪明地以为可以省掉这一步,
		 * 继而这个方法就不用覆写,毕竟都是 Serializable ,
		 * 不管是数字(Number)还是字符串(String)
		 * 
		 * 但返回值却需要确定到String,因为Java类(hbm对象)的属性是String类型的
		 * 而 makeValue() 返回的 Number (这里的实际类型是 Long)
		 * 
		 * 所以 id 的类型直接定义成 Number (更直观),
		 * 而不是 Serializable
		 */
        if (getIdentifierType().getReturnedClass() == String.class){
        	//增加对String的判断
            return id.toString();
        }
        
        return id;
	}

	@Override
	protected IntegralDataTypeHolder buildHolder() {
		/*
		 * 源码
		 * 
		 * return IdentifierGeneratorHelper.getIntegralDataTypeHolder(this.identifierType.getReturnedClass());
		 */
		return HIIdentifierGeneratorHelper
				.getIntegralDataTypeHolder(getIdentifierType()
						.getReturnedClass());
	}
}

还有一个辅助类 HIIdentifierGeneratorHelper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package org.young.hibernate.common;

import java.math.BigDecimal;
import java.math.BigInteger;

import org.hibernate.id.IdentifierGenerationException;
import org.hibernate.id.IdentifierGeneratorHelper;
import org.hibernate.id.IntegralDataTypeHolder;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * IdentifierGeneratorHelper ,final 类,不可继承
 *
 * @author by youngz
 *      on 2016年7月24日
 *
 * Package&FileName: org.young.hibernate.common.HIIdentifierGeneratorHelper
 */
public class HIIdentifierGeneratorHelper {

	public static IntegralDataTypeHolder getIntegralDataTypeHolder(
			Class integralType) {
		if ((integralType == Long.class) || (integralType == Integer.class)
				|| (integralType == Short.class)
				// 增加对String的判断
				|| (integralType == String.class)) {
			return new HIBasicHolder(integralType);
		}
		if (integralType == BigInteger.class)
			return new IdentifierGeneratorHelper.BigIntegerHolder();

		if (integralType == BigDecimal.class) {
			return new IdentifierGeneratorHelper.BigDecimalHolder();
		}

		throw new IdentifierGenerationException(
				"Unknown integral data type for ids : "
						+ integralType.getName());
	}

	public static class HIBasicHolder implements IntegralDataTypeHolder {
		private final Class exactType;
		private long value = 0L;

		public HIBasicHolder(Class exactType) {
			
			this.exactType = exactType;
			if ((exactType != Long.class) && (exactType != Integer.class)
					&& (exactType != Short.class)
					// 增加对String的判断
					&& (exactType != String.class)
					)
				throw new IdentifierGenerationException(
						"Invalid type for basic integral holder : " + exactType);
		}
		
		public long getActualLongValue() {
			return this.value;
		}

		public IntegralDataTypeHolder initialize(long value) {
			this.value = value;
			return this;
		}

		public IntegralDataTypeHolder initialize(ResultSet resultSet,
				long defaultValue) throws SQLException {
			long value = resultSet.getLong(1);
			if (resultSet.wasNull())
				value = defaultValue;

			return initialize(value);
		}

		public void bind(PreparedStatement preparedStatement, int position)
				throws SQLException {
			preparedStatement.setLong(position, this.value);
		}

		public IntegralDataTypeHolder increment() {
			checkInitialized();
			this.value += 1L;
			return this;
		}

		private void checkInitialized() {
			if (this.value == 0L)
				throw new IdentifierGenerationException(
						"integral holder was not initialized");
		}

		public IntegralDataTypeHolder add(long addend) {
			checkInitialized();
			this.value += addend;
			return this;
		}

		public IntegralDataTypeHolder decrement() {
			checkInitialized();
			this.value -= 1L;
			return this;
		}

		public IntegralDataTypeHolder subtract(long subtrahend) {
			checkInitialized();
			this.value -= subtrahend;
			return this;
		}

		public IntegralDataTypeHolder multiplyBy(IntegralDataTypeHolder factor) {
			return multiplyBy(IdentifierGeneratorHelper.extractLong(factor));
		}

		public IntegralDataTypeHolder multiplyBy(long factor) {
			checkInitialized();
			this.value *= factor;
			return this;
		}

		public boolean eq(IntegralDataTypeHolder other) {
			return eq(IdentifierGeneratorHelper.extractLong(other));
		}

		public boolean eq(long value) {
			checkInitialized();
			return (this.value == value);
		}

		public boolean lt(IntegralDataTypeHolder other) {
			return lt(IdentifierGeneratorHelper.extractLong(other));
		}

		public boolean lt(long value) {
			checkInitialized();
			return (this.value < value);
		}

		public boolean gt(IntegralDataTypeHolder other) {
			return gt(IdentifierGeneratorHelper.extractLong(other));
		}

		public boolean gt(long value) {
			checkInitialized();
			return (this.value > value);
		}

		public IntegralDataTypeHolder copy() {
			HIBasicHolder copy = new HIBasicHolder(this.exactType);
			copy.value = this.value;
			return copy;
		}

		public Number makeValue() {
			checkInitialized();
			if (this.exactType == Long.class)
				return Long.valueOf(this.value);
			
			// 增加对String的判断
			if (this.exactType == String.class) {
				return Long.valueOf(this.value);
			}

			if (this.exactType == Integer.class) {
				return Integer.valueOf((int) this.value);
			}

			return Short.valueOf((short) (int) this.value);
		}

		public Number makeValueThenIncrement() {
			Number result = makeValue();
			this.value += 1L;
			return result;
		}

		public Number makeValueThenAdd(long addend) {
			Number result = makeValue();
			this.value += addend;
			return result;
		}

		public String toString() {
			return "BasicHolder[" + this.exactType.getName() + "[" + this.value
					+ "]]";
		}

		public boolean equals(Object o) {
			if (this == o)
				return true;

			if ((o == null) || (super.getClass() != o.getClass())) {
				return false;
			}

			HIBasicHolder that = (HIBasicHolder) o;

			return (this.value == that.value);
		}

		public int hashCode() {
			return (int) (this.value ^ this.value >>> 32);
		}
	}
}

最后,修改 hibernate 配置文件里的主键生成策略

1
2
3
4
5
6
7
<id name="id" type="java.lang.String">
    <column name="ID" length="20" />
	<!-- 此处的 class 即刚刚新建的 Generator -->
    <generator class="org.young.hibernate.common.HISequenceGenerator" >
    	<param name="sequence">SEQ_ID</param>
    </generator>
</id>

本文的实验是在 hibernate-core-4.1.8.Final.jar 基础上完成。

可至 GitHub 上查看相关代码。

参考:

http://my.oschina.net/liyuj/blog/386582?fromerr=4h5OjIKZ