继续昨天的话题,越看到后面越吃力啊,感觉都理解一点,但却只是停留在表面,唉,虽然每篇文章只更新五个问题,但却要花我几个小时。坚持吧,坚持把每个问题都深入一点,自己也会收获更多。
11.HashMap和Hashtable的区别?哪一个对于多线程应用程序更好?
- Hashtable是同步的,加了synchronized锁,而HashMap不是。没有加synchronized锁的对象,性能通常比加了synchronized锁的对象要更好一些,因此,如果是非多线程程序,不需要考虑锁、同步等问题,那么使用HashMap更好。
- Hashtable不允许有空的键或值。HashMap允许空键和空值。
- HashMap有一个子类LinkedHashMap,对这个类对象进行迭代时,它的顺序是有序的(按插入顺序排序)。如有需要,你也能轻易的从LinkedHashMap转化成HashMap。Hashtable就没那么简单了。
总之,如果你无需关心同步(synchronized)问题,我会建议用HashMap。反之,你可以考虑使用ConcurrentHashMap。
12.如何便捷的将两个数组合到一起?(有歧义,是把两个数组|合到一起)
方法一:一行代码搞定 Apache Commons Lang library ArrayUtils.addAll(T[], T…)就是专门干这事的
public class Test12 {
public static void main(String[] args) {
int[] a = {1,2,3};
int[] b = {3,4,5};
int[] c = ArrayUtils.addAll(a, b);
System.out.println(Arrays.toString(c));
}
}
输出
[1, 2, 3, 3, 4, 5]
献上Apache Commons Lang的API文档地址http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/package-summary.html
方法二:非泛型 把下面的Foo替换成你自己的数组类型
public Foo[] concat(Foo[] a, Foo[] b) {
int aLen = a.length;
int bLen = b.length;
Foo[] c= new Foo[aLen+bLen];
System.arraycopy(a, 0, c, 0, aLen);
System.arraycopy(b, 0, c, aLen, bLen);
return c;
}
方法三:泛型
public <T> T[] concatenate (T[] a, T[] b) {
int aLen = a.length;
int bLen = b.length;
@SuppressWarnings("unchecked")
T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen+bLen);
System.arraycopy(a, 0, c, 0, aLen);
System.arraycopy(b, 0, c, aLen, bLen);
return c;
}
注意,泛型的方案不适用于基本数据类型(int,boolean……)
看到这个问题,第一次接触Commons Lang这个东西,其实之前有个问题也用到了这个jar包,但我忽略了,没想到这个问题又来了,所以我觉得有必要了解一下了。去官网下了jar包导入项目后,试了一下方法一,的确可行,ArrayUtils.addAll(T[], T…)源码如下:
public static Object[] addAll(Object[] array1, Object[] array2) {
if (array1 == null) {
return clone(array2);
} else if (array2 == null) {
return clone(array1);
}
Object[] joinedArray = (Object[]) Array.newInstance(array1.getClass().getComponentType(),
array1.length + array2.length);
System.arraycopy(array1, 0, joinedArray, 0, array1.length);
System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
return joinedArray;
}
看看有没有发现,和我们方法三十分相似,不过一个是T类型的,一个是Object类型的,然鹅方法三不支持基本类型,方法一却支持基本类型,所有如果不使用方法一,使用方法三,也建议把T改成Object,就可以使用基本类型了。
13.Java是否支持默认的参数值?
在 c++ 中,常见到如下的方法定义(param3 默认为 false)
void MyParameterizedFunction(String param1, int param2, bool param3=false);
那在 java 中,是否也支持这样的定义方式?
答案是否定的,不过我们可以通过多种方式处理这种参数默认值的情况。
方法一:创建者模式(我看不懂,想了解的可以移步)
使用创建者模式,你可以设定部分参数是有默认值,部分参数是可选的如:
Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
.name("Spicoli")
.age(16)
.motto("Aloha, Mr Hand")
.buildStudent();
方法二:构造函数重载(这个我知道)
void foo(String a, Integer b) {
//...
}
void foo(String a) {
foo(a, 0); // here, 0 is a default value for b
}
foo("a", 2);
foo("a");
构造函数重载,对于参数比较少的情况下,比较适合;当参数相对多的时候,可以考虑使用静态工厂方法,或添加一个参数辅助对象。
如果是常规方法重载,可以考虑使用参数辅助对象,或者重命名多种情况(比如说,有多个开银行卡的重载方法,可以根据需要重命名为开交行卡,开招行卡等多种方法)。
方法三:null的传递
当有多个默认参数时,可以考虑传递null,当参数为null时,将参数设为默认值。如:
void foo(String a, Integer b, Integer c) {
b = b != null ? b : 0;
c = c != null ? c : 0;
//...
}
foo("a", null, 2);
方法四:多参数方式
当有多个参数,且某些参数可以忽略不设置的情况下,可以考虑使用多参数方式。
- 可选的参数类型的一致
void foo(String a, Integer... b) {
Integer b1 = b.length > 0 ? b[0] : 0;
Integer b2 = b.length > 1 ? b[1] : 0;
//...
}
foo("a");
foo("a", 1, 2);
- 可选参数类型不一致
void foo(String a, Object... b) {
Integer b1 = 0;
String b2 = "";
if (b.length > 0) {
if (!(b[0] instanceof Integer)) {
throw new IllegalArgumentException("...");
}
b1 = (Integer)b[0];
}
if (b.length > 1) {
if (!(b[1] instanceof String)) {
throw new IllegalArgumentException("...");
}
b2 = (String)b[1];
//...
}
//...
}
foo("a"); foo("a", 1); foo("a", 1, "b2");
方法五:使用Map作为方法中的参数
void foo(Map<String, Object> parameters) {
String a = "";
Integer b = 0;
if (parameters.containsKey("a")) {
if (!(parameters.get("a") instanceof Integer)) {
throw new IllegalArgumentException("...");
}
a = (String)parameters.get("a");
}
if (parameters.containsKey("b")) {
//...
}
//...
}
foo(ImmutableMap.<String, Object>of( "a", "a", "b", 2, "d", "value"));
好吧,现在看了我也不知道具体的应用场景在哪。也许过些许时日我倒过头来看看,理解会更深刻。
14.Java产生指定范围的随机数
方法一:使用Math.Random()方法
Math.random()可以产生一个大于等于 0且小于 1的双精度随机数,假设需要产生“0”=随机数<= 10“的随机数,可以这样做:
int num =(int)(Math.random() * 11);
那如何产生“5 <=随机数<= 10”的随机数呢?
int num = 5 + (int)(Math.random() * 6);
生成“min <=随机数<= max”的随机数
int num = min + (int)(Math.random() * (max-min+1));
方法二:使用java.util.Random类
随机是java提供的一个伪随机数生成器。
生成“min <=随机数<= max”的随机数:
import java.util.Random;
/**
* Returns a pseudo-random number between min and max, inclusive.
* The difference between min and max can be at most
* <code>Integer.MAX_VALUE - 1</code>.
*
* @param min Minimum value
* @param max Maximum value. Must be greater than min.
* @return Integer between min and max, inclusive.
* @see java.util.Random#nextInt(int)
*/
public static int randInt(int min, int max) {
// NOTE: Usually this should be a field rather than a method
// variable so that it is not re-seeded every call.
Random rand = new Random();
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
方法三:标准库
在实际使用中,没有必要区重新写一次这些随机数的生成规则,可以借助一些标准库完成。如commons-lang。
org.apache.commons.lang3.RandomUtils提供了如下产生指定范围的随机数方法:
// 产生 start <= 随机数 < end 的随机整数
public static int nextInt(final int startInclusive, final int endExclusive);
// 产生 start <= 随机数 < end 的随机长整数
public static long nextLong(final long startInclusive, final long endExclusive);
// 产生 start <= 随机数 < end 的随机双精度数
public static double nextDouble(final double startInclusive, final double endInclusive);
// 产生 start <= 随机数 < end 的随机浮点数
public static float nextFloat(final float startInclusive, final float endInclusive);
org.apache.commons.lang3.RandomStringUtils提供了生成随机字符串的方法,简单介绍一下:
// 生成指定个数的随机数字串
public static String randomNumeric(final int count);
// 生成指定个数的随机字母串
public static String randomAlphabetic(final int count);
// 生成指定个数的随机字母数字串
public static String randomAlphanumeric(final int count);
15.JavaBean到底是什么?
(我的理解:JavaBean是一个特殊的Java类,1.类是public类型的。2.属性都是private类型的。3.有一个无参的public构造方法。4.每个属性都要setter和getter方法。)
问题:按照我的理解: “Bean” 是一个带有属性和getters/setter方法的Java类。它是不是和C的结构体是相似的呢,对吗? 一个“Bean”类与普通的类相比是不是语法的不同呢?还是有特殊的定义和接口? 为什么会出现这个术语呢,这让我很困惑? 如果你很好心告诉我一些关于Serializable接口的信息,对于你的答案那到底是什么意思,我会非常感谢你的。
回答:
JavaBean 只是一个标准
- 所有的属性是私有的(通过getters/setters处理属性)
- 一个公有的无参数的构造器
- 实现了序列化(Serializable)
就这些,它只是一个规范。但是很多的类库都是依赖于这些预定。
对于Serializable,看一下API文档的解释
实现java.io.Serializable接口的类能串行化。
不实现此接口的类不会有任何状态的序列化和反序列化。
可序列化类的所有子类型本身都是可序列化。
序列化接口没有方法或字段,仅用于标识的可序列化的语义。
换句话说,序列化的对象可以被写入流,文件,对象数据库等。
另外,一个JavaBean类和一个普通的类没有语法区别,如果遵循上面的标准的话,一个类可以认为成JavaBean类。
之所以需要JavaBean,是因为这样预定义了一种类的格式,一些库能依据这个约定的格式,来做一些自动化处理。举个例子,如果一个类库需要通过流来处理你传递的任何对象,它知道它可以正常处理,因为这个对象是可序列化的。(假设这个类库要求你的对象是JavaBeans)
哇的一下就想哭啊,好多看不懂,序列化到底是个啥,有啥用啊。看来还得好好研究一下。