【笔试面试】第三波

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方法中不要依赖于该字段。

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值