【笔试面试】第三波

来源:互联网 发布:mac口红一盒 编辑:程序博客网 时间:2024/05/16 08:15

1、String的split(String regex)方法参数注意点

  使用这个方法时,当我们直接以“.”为参数时,是会出错的,如:

String str = "12.03";  String[] res = str.spilt(".");    //出错!!!  

  此时,我们得到的res是为空的(不是null),即str = [];
  因为String的split(String regex)根据给定的正则表达式的匹配来拆分此字符串,而”.”是正则表达式中的关键字,没有经过转义split会把它当作一个正则表达式来处理的,需要写成str.split(“\.”)进行转义处理。
  正则表达式关键字:^$(){}[].?+*|

2、关于hashCode方法

参考文章

我们可以先通过HashMap中hashCode的作用来体验一下。
我们知道HashMap中是不允许插入重复元素的,如果是插入的同一个元素,会将前面的元素给覆盖掉,那势必在HashMap的put方法里对key值进行了判断,检测其是否是同一个对象。其put源码如下:

public V put(K key, V value) {        if (table == EMPTY_TABLE) {    //key的hashCode值放在了table里面            inflateTable(threshold);        }        if (key == null)            return putForNullKey(value);        int hash = hash(key);    //计算我们传进来的key的hashcode值        int i = indexFor(hash, table.length);        for (Entry<K,V> e = table[i]; e != null; e = e.next) {            Object k;            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {    //将传进来的key的hashcode值于HashMap中的table里面存放的hashCode值比较                V oldValue = e.value;                e.value = value;                e.recordAccess(this);                return oldValue;            }        }        modCount++;        addEntry(hash, key, value, i);        return null;    }  

  可以看到这里的判断语句 if (e.hash == hash && ((k = e.key) == key || key.equals(k))),里面通过&&逻辑运算符相连,先判断e.hash == hash,即判断传进来的key的hashCode值与table中的已有的hashCode值比较,如果不存在该key值,也就不会再去执行&&后面的equals判断;当已经存在该key值时,再调用equals方法再次确定两个key值对象是否相同。从这里可以看出,hashCode方法的存在是为了减少equals方法的调用次数,从而提高程序效率。
  可以看到,判断两个对象是否相同,还是要取决于equals方法,而两个对象的hashCode值是否相等是两个对象是否相同的必要条件。所以有以下结论:
  (1)如果两个对象的hashCode值不等,根据必要条件理论,那么这两个对象一定不是同一个对象,即他们的equals方法一定要返回false;
  (2)如果两个对象的hashCode值相等,这两个对象也不一定是同一个对象,即他们的equals方法返回值不确定;
 反过来,
  (1)如果equals方法返回true,即是同一个对象,它们的hashCode值一定相等;
  (2)如果equals方法返回false,hashCode值也不一定不相等,即是不确定的;

(hashCode返回的值一般是对象的存储地址或者与对象存储地址相关联的hash散列值)

  然而,很多时候我们可能会重写equals方法,来判断这两个对象是否相等,此时,为了保证满足上面的结论,即满足hashCode值相等是equals返回true的必要条件,我们也需要重写hashCode方法,以保证判断两个对象的逻辑一致(所谓的逻辑一致,是指equals和hashCode方法都是用来判断对象是否相等)。如下例子:

public class Person {      private String name;      private int age;      public Person(String name,int age){          this.name = name;          this.age = age;      }      public String getName() {          return name;      }      public void setName(String name) {          this.name = name;      }      public int getAge() {          return age;      }      public void setAge(int age) {          this.age = age;      }      @Override      public boolean equals(Object obj) {          return this.name.equals(((Person)obj).name) && this.age== ((Person)obj).age;      }  }  

  在Person里面重写了equals方法,但是没有重写hashCode方法,如果就我们平时正常来使用的话也不会出什么问题,如:
  

Person p1 = new Person("lly",18);  Person p2 = new Person("lly",18);  System.out.println(p1.equals(p2));    //返回true  

  上面是按照了我们重写的equals方法,返回了我们想要的值。但是当我们使用HashMap来保存Person对象的时候就会出问题了,如下:  

Person p1 = new Person("lly", 18);  System.out.println(p1.hashCode());  HashMap<Person, Integer> hashMap = new HashMap<Person, Integer>();  hashMap.put(p1, 1);  System.out.println(hashMap.get(new Person("lly", 18)));    //此时返回了null,没有按我们的意愿返回1  

  这是因为,我们没有重写Person的hashCode方法,使hashCode方法与我们equals方法的逻辑功能一致,此时的Person对象调用的hashCode方法还是父类的默认实现,即返回的是和对象内存地址相关的int值,这个时候,p1对象和new Person(“lly”,18);对象因为内存地址不一致,所以其hashCode返回值也是不同的。故HashMap会认为这是两个不同的key,故返回null。
   所以,我们想要正确的结果,只需要重写hashCode方法,让equals方法和hashCode方法始终在逻辑上保持一致性。

在《Java编程思想》一书中的P495页有如下的一段话:
  “设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该产生同样的值。如果在将一个对象用put()添加进HashMap时产生一个hashCdoe值,而用get()取出时却产生了另一个hashCode值,那么就无法获取该对象了。所以如果你的hashCode方法依赖于对象中易变的数据,用户就要当心了,因为此数据发生变化时,hashCode()方法就会生成一个不同的散列码”。
  如下一个例子:  

public class Person {      private String name;      private int age;      public Person(String name,int age){          this.name = name;          this.age = age;      }      public String getName() {          return name;      }      public void setName(String name) {          this.name = name;      }      public int getAge() {          return age;      }      public void setAge(int age) {          this.age = age;      }      @Override      public int hashCode() {          return name.hashCode()*37+age;    //hashCode的返回值依赖于对象中的易变数据      }      @Override      public boolean equals(Object obj) {          return this.name.equals(((Person)obj).name) && this.age== ((Person)obj).age;      }  }  

  此时我们继续测试:

Person p1 = new Person("lly", 18);  System.out.println(p1.hashCode());  HashMap<Person, Integer> hashMap = new HashMap<Person, Integer>();   hashMap.put(p1, 1);   p1.setAge(13);   //改变依赖的一个值  System.out.println(hashMap.get(p1));    //此时还是返回为null,这是因为我们p1的hashCode值已经改变了  

  所以,在设计hashCode方法和equals方法的时候,如果对象中的数据易变,则最好在hashCode方法中不要依赖于该字段。

0 0