本文主要是收录一些人们可能经常会忽略,但又挺重要的Java方面的小知识。有推荐的也可以在下方留言,大家一起进步呀!
目录:
1.a=a+b和a+=b的区别
2.String str1 = new String("a"); String str2 = "a"+"b"; 这两行代码分别创建了几个对象,是什么
3.启动线程的方式以及如何更好地结束一个线程?
4.Java 中 == 和 equals 和 hashCode的区别
2019-7-7
1.a=a+b和a+=b的区别
(1)从效率上看
a+=b要略高于a=a+b
(2)从运算符上看
a+=b的执行过程是先计算出a的值,然后用一个temp对象存储,之后和b进行相加,然后将值赋给a引用。
a=a+b的执行过程是先计算a+b,然后再赋值给a引用,赋值给a引用的时候如果引用a有计算过程,则会再次计算。
(3)从类型自动转换上看
当a和b的数据类型不一样时,a+=b会自动进行类型转换;而a=a+b不会,需要手动进行类型转换
比如:
byte a = 1;
int b = 4;
a = a + b;//此时编译会报错,因为a为byte,b为int,
//a+b的时候默认会向大类型即int转换,则a+b的类型为int,而a为byte,所以报错
a += b;//此时编译不会报错,因为+=会自动进行类型转换,并且向低转换
2.String str1 = new String("a"); String str2 = "a"+"b"; 这两行代码分别创建了几个对象,是什么
(1)首先第一行代码中创建了两个对象(因为字符串池中没有a字符串),一个是new String创建出来的str1对象,一个是在字符串池中创建的a对象。
(2)然后因为a字符串已经在常量池中存在了,所以在第二行代码中就不会再创建a对象了。接着创建的就是b对象,最后是str2对象,值为ab。
总结:要先看字符串池中有没有该字符串,有的话会直接拿过来,没有再重新创建。
3.启动线程的方式以及如何更好地结束一个线程?
(1)启动线程的方式
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口通过FutureTask包装器来创建Thread线程
- 匿名内部类
(2)如何更好地结束一个线程
线程中调用interrupt()方法仅仅是在当前线程中打了个停止的标记,并不是真的停止线程。
如何判断线程的状态是否是停止,主要包含以下两种方法:
1、this.interrupted():测试当前线程是否已经是中断状态,执行后具有将状态标志置清除为false的功能。
2、this.isInterrupted():测试线程thread对象是否已经是中断状态,但不具备清除状态标志。
注:使用stop()方法停止线程是非常暴力的,该方法已经作废,不考虑。
注意:官方文档中说明If this thread is blocked in an invocation of the [
wait()
], [wait(long)
], or [wait(long, int)
] methods of the [Object
] class, or of the [join()
], [join(long)
], [join(long, int)
], [sleep(long)
], or [sleep(long, int)
], methods of this class, then its interrupt status will be cleared and it will receive an [InterruptedException
].
也就是说,在run方法里面调用Object类的wait或线程的join/sleep方法之后,这个标记会被清空并抛出InterruptedException异常。解决方法:可在调用的方法的catch中再this.interrupt一次。(不是下文例子中的catch)
① 抛异常法
public static void main(String[] args) throws InterruptedException {
MyThread t1 = new MyThread();
t1.start();
Thread.sleep(100);
t1.interrupt();
}
public static class MyThread extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 5000000; i++) {
if (this.isInterrupted()) {
System.out.println("Thread Stop!");
throw new InterruptedException();
}
System.out.println("i: " + i);
}
System.out.println("我在for下面");
} catch (InterruptedException e) {
System.out.println("进入到catch了!");
}
}
}
运行结果:
...
i: 11759
i: 11760
i: 11761
i: 11762
Thread Stop!
进入到catch了!
② 使用return
public static void main(String[] args) throws InterruptedException {
MyThread t1 = new MyThread();
t1.start();
Thread.sleep(100);
t1.interrupt();
}
public static class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5000000; i++) {
if (this.isInterrupted()) {
System.out.println("Thread Stop!");
return;
}
System.out.println("i: " + i);
}
System.out.println("我在for下面");
}
}
运行结果:
...
i: 12301
i: 12302
i: 12303
i: 12304
i: 12305
Thread Stop!
③ 使用退出标志
和上面两种方法差不多,只不过是用一个布尔变量代替this.isInterrupted(),然后要想停止线程,赋值该布尔变量为false即可。
2019-8-2
4.Java 中 == 和 equals 和 hashCode的区别
(1)==
对于八种基本数据类型,比较的是他们的值
对于引用数据类型(类,接口和数组),比较的是他们在内存中的地址,所以,除非是同一个new出来的对象,他们比较之后的结果为true,否则为false。eg:
Integer a = new Integer(127);
Integer b = 127;
Integer c = 127;
//a==b为false,b==c为true
Integer d = 128;
Integer e = 128;
//d==e为false
//这里为什么b==c为true而d==e为false呢?
//Integer b = 127在编译时会被翻译成Integer.valueOf(127),该方法对于[-128,127]之间
//的数会进行缓存,如果已经有的话会直接从缓存中拿出,不会再new
//因为128不在该区间,那么d和e就只是new出来的两个不同的对象了,所以就为false
Java中堆和栈的区别
最主要的区别就是:new出来的对象和数组是存放在堆中的,基本数据类型的变量和对象的引用变量是存放在栈中的。
Java的内存机制:
栈:当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当该变量超过它的作用域后,Java会自动释放掉为该变量所分配的内存空间。
堆:在堆中分配的内存,由GC来管理。在堆中产生了一个数组或对象之后,还可以在栈中定义一个特殊的变量,让栈中这个变量的值等于该数组或者对象在堆内存中的首地址,栈中的这个变量就成了数组或者对象的引用变量,以后可以在程序中使用栈中的引用变量来访问数组或者对象。
(2)equals
默认情况下的equals方法是没有被覆盖的,调用的都是Object类的equals方法,这种情况下的equals方法和==是等效的。
public boolean equals(Object obj) {
return (this == obj);
}
如果equals方法被覆盖,则按照新的方法来判断,覆盖后一般
都是通过对象的内容是否相等来判断对象是否相等。比如String类的equals方法:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
String类的equals方法总结为:
首先看是不是同一个对象,是的话返回true
然后看对比对象是不是String类型,
接着看长度是否一致
最后比较逐个字符是否相同
实现高质量的equals方法的技巧如下:
首先比较两个是否==,
然后检查对比对象是否是该类型,
接着比较他们的域是否相同
最后检查对称性,传递性,一致性
(3)hashCode
hashCode()方法也是Object类的一个方法,返回的是一个int型的整数。在集合类操作中使用,主要是为了提高查询速度。
两者的hashCode相同,他们不一定equals。
两者的hashCode不相同,他们一定不equals。
他们equals,hashCode一定相同。
他们不equals,hashCode有可能相同。