类在继承时,会用到this和super,以前也不多用到,之前看过,今天看了一下,只记得之前看过,理解仍是不深。html
thisjava
直接引用,至关于指向对象自己算法
型参与成员变量名字相同,用this来区分bash
class A{
private int number = 15;
A(){
System.out.println("number:"+number);
}
public int getNumber(int number){
this.number = number; //用来区分参数number和A类中的属性number(this.number)
return this.number;
}
}
复制代码
引用构造函数多线程
this(参数):调用本类中另外一种构造函数(应在构造函数的第一行)ide
super函数
直接引用,指向当前对象的父类,能够用super.xx来引用父类的属性ui
子类的变量/方法与父类的变量/方法重名this
在子类种调用时,重名的方法/变量,直接使用是子类的,this.xx或this.xx()属于调用父类的。spa
引用构造函数
super(参数):调用父类中某种构造函数(应在构造函数的第一行)
这两个方法都是Object中带有的方法,即全部方法都有equals和hashcode方法。
在没有重写的状况下,equals方法即"==",hashcode方法获取哈希码,即肯定对象在散列表中的索引位置。
若是不重写equals方法,那么好比User这种对象,通常咱们equals比较的是它包含的属性是否相同,不重写的话,依照Object的equals方法,两个对象的内存地址不一样,因此返回false,这显然不是咱们想要要的。因此要重写,在方法中判断属性是否相同。
若是只重写equals方法,而没有重写hashcode方法,好比User对象放在hashset中,hashset的特性是不容许重复。当咱们放入两个数据相同的User时,重写后的equals方法返回true,可是没有重写hashcode方法,依照Object的hashcode方法,两个对象的hash值不一样,因此不是同一对象,hashset中均可以存入,可是当咱们将User放入hashset中,要求若是是要求数据不一样的话,就会没法实现。因此须要重写hashcode方法,使得包含数据相同的两个User对象,返回的hash值相同,而此时,hashset会判断重复,就只能存入一个。
```
而这其中就涉及到hashset判断重复的依据
add(object)会先用Object的equals方法和hashcode方法判断set中,
是否已有重复元素,固然,若是两个元素若是不是指向同一对象,不管如何也不会重复。
因此,当咱们须要剔除数据相同的元素,就须要在此基础上从新给元素对应的类型重写hashcode方法。
```
复制代码
参考:
重写equals方法后重写hashCode方法的必要性
如何重写hashCode算法
HashSet重复元素判断
对我来讲,是急需增强的一个点,由于以前用到的很少,因此也就不求甚解。
Java多线程的两种实现方式:继承Thread类、实现Runnable接口
继承Thread类
package cn.wh3t;
public class MultiThread extends Thread{
private String name;
public MultiThread(String name) {
// TODO 自动生成的构造函数存根
this.name = name;
}
@Override
public void run() {
// TODO 自动生成的方法存根
for(int i =0;i<5;i++) {
System.out.println("Thread-"+name+"----hello"+i);
}
}
public static void main(String[] args) {
MultiThread multiThread1 = new MultiThread("A");
MultiThread multiThread2 = new MultiThread("B");
multiThread1.start();
System.out.println("hello1");
System.out.println("hello2");
multiThread2.start();
System.out.println("hello3");
System.out.println("hello4");
}
}
复制代码
输出结果://屡次运行结果都会不一样
hello1
hello2
Thread-A----hello0
Thread-A----hello1
Thread-A----hello2
hello3
Thread-A----hello3
hello4
Thread-A----hello4
Thread-B----hello0
Thread-B----hello1
Thread-B----hello2
Thread-B----hello3
Thread-B----hello4
复制代码
实际启动的时候并非调用Thread的run方法,而是strat方法。
那么run()和start()有什么区别
在Java中,线程一般都有5种状态:建立、就绪、运行、阻塞、死亡
1. 建立:生成线程对象时,还未调用start方法
2. 就绪:调用了该线程对象的start,线程进入就绪状态,可是并未把该线程设成当前线程。在线程运行以后,从等待或者睡眠中回来,也会进入就绪状态
3. 运行:将该线程设为当前线程,线程进入运行状态,开始运行run()中的代码
4. 阻塞:线程正在运行时,被暂停,一般是为了某个时间发生或者加载某个资源以后再继续运行。sleep、suspend、wait都会形成阻塞
5. 死亡:线程的run()结束,或者调用了stop方法,线程就会死亡。对于死亡的线程,再使用start方法也不会使其进入就绪状态
总之就是说,若是没有start方法,只有run方法。就不是多线程执行了。由于start方法使线程进入就绪状态,并无当即执行,经过上面代码的运行结果也能够看出,线程1的start要早于hello一、hello2的打印,却比他们输出要晚。若是没有start,只是run(),就会依次执行,回归单线程(当前主线程)执行的状态。
实现Runnable接口
package cn.wh3t;
public class MultiThreadByRunnable implements Runnable{
private int count = 20;
@Override
public void run() {
// TODO 自动生成的方法存根
for(int i =0;i<40;i++) {
if(count>0) {
System.out.println(Thread.currentThread().getName()+" "+count--);
}
}
}
public static void main(String[] args) {
MultiThreadByRunnable runnable = new MultiThreadByRunnable();
Thread thread1 = new Thread(runnable,"A");
Thread thread2 = new Thread(runnable,"B");
thread1.start();
System.out.println("hello1");
System.out.println("hello2");
thread2.start();
System.out.println("hello3");
System.out.println("hello4");
}
}
复制代码
输出结果://屡次运行结果都会不一样
hello1
A 20
hello2
A 19
A 18
A 17
hello3
hello4
A 16
B 15
B 13
B 12
A 14
B 11
B 10
B 9
B 8
B 6
B 5
B 4
B 3
B 2
B 1
A 7
复制代码
两种实现方式不一样:相比之下,实现Runnable接口更有优点
1. 适合多个代码相同的程序去处理同一资源;
2. 能够避免Java中的单继承,能够扩展实现更多接口
3. 增长程序的健壮性,代码能够被多个程序共享,代码和数据独立
sleep()、suspend()、yield()等都是Thread类的方法,wait()和notify()确实属于Object的方法,即全部类均可以执行这两个方法。由于这两个方法阻塞时要释放占用的锁,而全部对象都有锁。wait()致使线程阻塞,释放该对象上占用的锁。调用notify()则致使因调用该对象的wait()而阻塞的线程中,随机选择一个解除阻塞(可是要等到真正得到锁之后才能执行)。这两个方法必须在synchronized方法或块中执行,由于synchronized方法/块才能占有锁,有锁才能释放。
关于wait和notify要注意的三个点:
1. 调用notify方法而接触阻塞的线程是从wait方法阻塞的线程中随机选取的,因此没法预料哪一个线程被选取,因此要当心,避免不肯定性产生的问题
2. 除了notify,notifyAll方法也能够唤醒,解除阻塞的是因wait方法而阻塞的全部线程,固然,只有得到锁的那个线程才能进入可执行状态
3. wait和notify必须成对存在
package cn.wh3t;
public class CountThread extends Thread{
int total;
@Override
public void run() {
// TODO 自动生成的方法存根
synchronized (this) {
for(int i=0;i<100;i++) {
total = total +1 ;
}
this.notify();//唤醒被阻塞的线程
System.out.println("notify"+total);
}
}
}
复制代码
package cn.wh3t;
public class TestWaitAndNotify {
public static void main(String[] args) {
CountThread thread = new CountThread();
thread.start();
synchronized(thread) {
System.out.println("等到线程结束"+thread.total);
try {
thread.wait();
System.out.println("wait"+thread.total);
}catch(Exception e) {
e.printStackTrace();
}
System.out.println("计算的结果是:"+thread.total);
}
}
}
复制代码
(主线程等待技术线程结束后才打印输出)
等到线程结束0
notify100
wait100
计算的结果是:100
复制代码
参考:
java 线程详解
Thread的run()与start()的区别
java thread中的wait()和notify()