Java小Tips

关于 “==”,equals,hashCode

关于Java的Hashcode,Object类的方法解释如下:
    public int hashCode()
    Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those provided by HashMap. 
    The general contract of hashCode is: 
    Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application. 
    If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result. 
    It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables. 
    As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the Java™ programming language.)
    简单来说,就是如果两个对象equals为true,那么hashcode则相同,如果euals不为true,不能保证都不同。
    各个类中的hashcode方法的实现是尽量保证不同对象具有不同的hashcode,但是不能保证都不同。
    事实上,判断两个变量引用的对象在物理上是不是同一个位置,最好用"=="(equals只是用在判断两个对象的内容是否一样?hashcode一般用在hashmap上?)。

String、StringBuffer与StringBuilder的区别

1、String 类
    String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间。 
String a = "a"; //假设a指向地址0x0001 
a = "b";//重新赋值后a指向地址0x0002,但0x0001地址中保存的"a"数据依旧存在,但已经不再是a所指向的,a 已经指向了其它地址。 

2、StringBuffer类
    它是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。 每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量。 对StringBuffer的引用的对象是不会变的,不管是append或者其他的操作,因为StringBuffer封装了里面的数据,就算是里面缓冲区不够了,也是里面数据的引用对象发生变化。

StringBuffer buf=new StringBuffer(); //分配默认字节长的字符缓冲区 
StringBuffer buf=new StringBuffer(512); //分配长512字节的字符缓冲区 
StringBuffer buf=new StringBuffer("this is a test")//在缓冲区中存放了字符串。 

3.StringBuilder
    StringBuffer和StringBuilder类功能基本相似,主要区别在于StringBuffer类的方法是多线程、安全的,而StringBuilder不是线程安全的,相比而言,StringBuilder类会略微快一点。对于经常要改变值的字符串应该使用StringBuffer和StringBuilder类。 

4.线程安全 
    StringBuffer 线程安全 
    StringBuilder 线程不安全 

5.速度 
    一般情况下,速度从快到慢:StringBuilder>StringBuffer>String,这种比较是相对的,不是绝对的。 

6.总结
(1)如果要操作少量的数据用  String 
(2)单线程 下操作大量数据  StringBuilder 
(3)多线程 下操作大量数据  StringBuffer 

package test;

public class stringthreetypes {
    final static int time = 100000; // 循环次数

    public stringthreetypes() {

    }

    public void test(String s) {
        long begin = System.currentTimeMillis();
        for (int i = 0; i < time; i++) {
            s += "add";
        }
        long over = System.currentTimeMillis();
        System.out.println("操作" + s.getClass().getName() + "类型使用的时间为:"
                + (over - begin) + "毫秒");
    }

    public void test(StringBuffer s) {
        long begin = System.currentTimeMillis();
        for (int i = 0; i < time; i++) {
            s.append("add");
        }
        long over = System.currentTimeMillis();
        System.out.println("操作" + s.getClass().getCanonicalName() + "类型使用的时间为:"
                + (over - begin) + "毫秒");
    }

    public void test(StringBuilder s) {
        long begin = System.currentTimeMillis();
        for (int i = 0; i < time; i++) {
            s.append("add");
        }
        long over = System.currentTimeMillis();
        System.out.println("操作" + s.getClass().getName() + "类型使用的时间为:"
                + (over - begin) + "毫秒");
    }

    /* 对 String 直接进行字符串拼接的测试 */
    public void test2() {
        String s2 = "abcd";
        long begin = System.currentTimeMillis();
        for (int i = 0; i < time; i++) {
            String s = s2 + s2 + s2;
        }
        long over = System.currentTimeMillis();
        System.out.println("操作字符串对象引用相加类型使用的时间为:" + (over - begin) + "毫秒");
    }

    public void test3() {
        long begin = System.currentTimeMillis();
        for (int i = 0; i < time; i++) {
            String s = "abcd" + "abcd" + "abcd";
        }
        long over = System.currentTimeMillis();
        System.out.println("操作字符串相加使用的时间为:" + (over - begin) + "毫秒");
    }

    public static void main(String[] args) {
        String s1 = "abcd";
        StringBuffer st1 = new StringBuffer("abcd");
        StringBuilder st2 = new StringBuilder("abcd");
        stringthreetypes tc = new stringthreetypes();
        tc.test(s1);
        tc.test(st1);
        tc.test(st2);
        tc.test2();
        tc.test3();
    }
}
输出结果:
    操作java.lang.String类型使用的时间为:50422毫秒
    操作java.lang.StringBuffer类型使用的时间为:15毫秒
    操作java.lang.StringBuilder类型使用的时间为:0毫秒
    操作字符串对象引用相加类型使用的时间为:32毫秒
    操作字符串相加使用的时间为:0毫秒

    输出结果的前三行好理解,上面也进行了叙述。
    第四行,主要是因为一行`String s = s2 + s2 +s2;`代码, 新建了好几个新对象,并且每次的String s的id号都不一样,说明它是十分耗资源的(每次都进行了对象的新建),相比于代码`String s ="abcd" + "abcd"+ "abcd";`它只是将s指向已经存在的"abcd" + "abcd"+ "abcd" 生成的对象(有可能是类似C语言中的常量,在运行前就已经确定出“abcdabcdabcd”),Debug过程中发现,循环中的String s的id号是一样的,说明它没有进行对象的新建,只是生成一个变量名,并进行引用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值