好久没有更新过blog了。
回顾:
前面的一篇博客总结了:
- 九种基本数据类型的大小,以及他们的封装类。
- Switch能否用string做参数?
- equals与==的区别。
- Object有哪些公用方法?
- Java的四种引用,强弱软虚,用到的场景。
五个问题,并进行了相关的详细解释,也请大家多多发表见解,相互学习。
6. Hashcode的作用
作用:用于查找的快捷性
注意事项:
1.两个对象通过 == 或 equals方法比较结果为true的时候,这两个对象的hashCode也一定要相同。所以重写equals方法的时候建议重写hashCode方法,保证结果一致;
2.两个对象的hashCode相同不代表两个对象完全相同。也就是说hashCode并不能用来控制和判断两个对象是否相同。
举例
Class A{
public int age;
public int stature;
public String name;
public A (int age, int stature, String name){
this.age = age;
this.stature = stature;
this.name = name;
}
public A (){}
public getAge(){
return age;
}
public String getName(){
return name;
}
public int getStature(){
return stature;
}
@Override
public boolean equals(Object obj){
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
A a = (A) obj;
if (a.getAge() != this.getAge())
return false;
if (a.getName() != null && !a.getName().equals(this.getName()))
return false;
if (a.getStature() != this.getStature())
return false;
return true;
}
@Override
public int hashCode(){
return name.leng() + stature + age;
}
}
1.equals方法和 == 比较结果为true, hashCode也要相同
A a = new A(1, 175, “uana”);
A b = a;
b.equals(a); // b == a;2.equals方法比较结果为true,hashCode结果也要一致
A a = new A(1, 175, “uana”);
A b = new A(1, 175, “uana”);
b.equals(a); // true3.hashCode相同不代表是同一个对象
A a = new A(1, 175, “uana”);
A b = new A(5, 170, “uana”);
b.equals(a); // false
b.hashCode() == a.hashCode(); // true
下面说一下使用hashCode怎么样提高查找速度(代码中有些逻辑判断不合理,大体思路已经表现出来)
public class MyHashMap {
/*根据hashCode存放数据,查询数据的时候会减少查询次数*/
private static Map<Integer, List<A>> map = new HashMap();
public static void put(A a) {
if (map.containsKey(a.hashCode())) {
if (!map.get(a.hashCode()).contains(a)) {
map.get(a.hashCode()).add(a);
}
} else {
List<A> list = new ArrayList<>();
list.add(a);
map.put(a.hashCode(), list);
}
}
public static A get(int hashCode, A target) {
if (map == null || map.size() == 0) {
return "";
}
if (map.get(hashCode).contains(target)) {
for (int i = 0; i < map.get(hashCode).size(); i++) {
if (target == map.get(hashCode).get(i)) {
// 有效减少查询次数
return map.get(hashCode).get(i);
}
}
}
return "";
}
}
注:上面举得例子是一个类(A)的情况下。同理还有可能出现不同类的对象的hashCode值是相同的情况。
总结:hashCode不同代表肯定不是同一个对象。它的作用是用来分离存储对象的,通过hashCode值来存储数据,在查找的时候能有效提高查询速度。
7. 进程和线程
Part one 两者的区别
对于应用层开发者而言,进程就是一个正在执行的(运行的)应用程序。线程就是进程内部的一个执行序列,一个进程可以有多个线程。线程依附于进程而存在。也可以把线程看做是一个轻量级的进程(实际上不是进程)。
Part two 创建线程的方式
1.继承Thread类
2.实现Runnable接口
3.应用程序可以使用Executor框架来创建线程池
实现Runnable接口这种方式更受欢迎,因为不需要继承Thread类。因为Java不支持多继承,所以很多情况下在应用设计中会优先考虑使用Runnable接口。另外使用线程池也是一个很不错的选择。
Part three
线程的状态
1.就绪状态(Runnable): 线程准备运行,但是不代表立刻就能开始执行。
2.运行中(Running):进程正在执行线程中的代码逻辑。
3.等待中(Waiting):线程处于阻塞状态,等待外部的代码逻辑处理结束。
4.睡眠中(Sleeping):线程被强制睡眠。
5.I/O阻塞(Blocked on I/O):等待I/O操作完成。
6.同步阻塞状态(Blocked on Synchronization):此刻线程在等待获取到锁。
7.死亡(Dead):线程执行结束。
注意事项:不建议手动调用stop来结束线程(这样操作不安全,所以不建议这样操作。可以考虑在线程执行中加入逻辑控制来结束线程)。
8.如何做线程同步
关键词:synchronized
实际应用中的作用点:
1.修饰实例方法,作用与当前实例加锁。进入同步代码前要获取当前实例的锁
2.修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
3.修饰代码块。指定加锁对象,对给定的对象加锁,进入同步代码块之前要获得给定对象的锁
下面出相应的例子:代码中会标注注意点
public class NormalMothedSync implements Runnable{
// 共享资源
static int num = 0;
/**
* synchronized 修饰实例方法
*/
public synchronized void increase(){
num++;
}
@Override
public void run(){
for(int i=0; i<1000; i++){
increase();
}
}
public static void main(String[] args) throws InterruptedException{
// 创建实体对象
NormalMothedSync nms = new NormalMothedSync();
// 注意:这里两个线程使用的runnable对象是同一个对象。感兴趣的朋友可以试试,两个线程的runnable不适用同一个对象试试结果
Thread th_01 = new Thread(nms);
Thread th_02 = new Thread(nms);
th_01.start();
th_02.start();
// join含义:当前线程B等待A线程终止之后才能执行(前提是AB两个线程使用的锁是同一个锁对象)
th_01.join();
th_02.join();
// 输出结果 2000
System.out.println(num);
}
}