Java编程的一些小技巧-----基础语法篇(3)

继续昨天的话题,越看到后面越吃力啊,感觉都理解一点,但却只是停留在表面,唉,虽然每篇文章只更新五个问题,但却要花我几个小时。坚持吧,坚持把每个问题都深入一点,自己也会收获更多。


11.HashMap和Hashtable的区别?哪一个对于多线程应用程序更好?

  1. Hashtable是同步的,加了synchronized锁,而HashMap不是。没有加synchronized锁的对象,性能通常比加了synchronized锁的对象要更好一些,因此,如果是非多线程程序,不需要考虑锁、同步等问题,那么使用HashMap更好。
  2. Hashtable不允许有空的键或值。HashMap允许空键和空值。
  3. 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)



哇的一下就想哭啊,好多看不懂,序列化到底是个啥,有啥用啊。看来还得好好研究一下。

猜你喜欢

转载自blog.csdn.net/a_helloword/article/details/79997219
今日推荐