()
1.JDK和JRE的区别
对比项 | JDK | JRE |
---|---|---|
名称释义 | Java Development Kit | Java Runtime Enviroment |
开发环境工具包,包含了各种类库和工具 | 运行环境 | |
面向对象 | 开发人员 | 使用人员 |
细节对比 | jdk/jre/bin中client和server文件夹下都包含一个jvm.dll | jre中只有server下面的jvm.dll |
安装使用 | 配置环境变量后使用的javac,jdk | 如果同时安装了jre和jdk使用的java要看环境变量中的配置顺序 |
- 如果一台电脑安装两套以上的JRE,谁来决定呢?
这个重大任务就落在java.exe身上。Java.exe的工作就是找到合适的JRE来运行Java程序。 Java.exe依照底下的顺序来查找JRE:自己的目录下有没有JRE;父目录有没有JRE;查询注册表: [HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment] 所以java.exe的运行结果与你的电脑里面哪个JRE被执行有很大的关系。
2.equals和==的区别
比较对象 | 方法 | 比较原则 |
---|---|---|
基本类型 | == | 比较值是否相等 |
equals | 比较值是否相等 | |
引用类型 | == | 比较引用是否相等 |
equals | 默认情况下使用 == 比较,若重写了equals方法,使用重写后的方法 |
深入 String重写了Object的equals方法,把引用比较改为了值比较,故两个值同 string的 equals 结果为true
- 对象 hashCode() 与 equals() 是否对等: hashCode()相等 是否 一定 equals()为 true
在JAVA中所有类都是Object类的子类, 在实际的实现中可以重写对应的方法,故不一定对等 例如 两个String 对象的hashCode可能一样 但实际 equals() = false
HashSet 使用HashMap 将要保存的元素作为key,PRESENT 作为键值对put 到map中
private static final Object PRESENT = new Object();
即使用要放入的元素 的 hashCode方法作重复校验,使用hashMap的put方法,默认情况下会更新值,但不会更新key,
所有当我们要实现自定义 Class 去重, 且保留最先进入的元素可以用hashset, 同时重写 hashCode()方法
例如
public class CaseTest
{
class DemoSet{
String id;
int name;
public DemoSet(String id, int name)
{
this.id = id;
this.name = name;
}
@Override
public int hashCode()
{
int result = 17;
result = 31 * result + (id == null ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj){
if(obj instanceof DemoSet){
DemoSet ds = (DemoSet) obj;
if(ds.id.equals(this.id)){ // ds.id == this.id
return true;
}
}
return false;
}
@Override
public String toString(){
return String.format("{id:%s,name:%d}",id,name);
}
}
@Test
public void testSet(){
HashSet set = new HashSet();
Set<DemoSet> demoSets = Sets.newConcurrentHashSet();
demoSets.add(new DemoSet("1",1));
Set<DemoSet> demoSets2 = Sets.newConcurrentHashSet();
demoSets2.add(new DemoSet("1",2));
demoSets.addAll(demoSets2);
System.out.println(demoSets);
}
}
最终列表之后保留 1,1 注意字符串 == 比较引用
- final 修饰符的作用
作用 | 特性 |
---|---|
类 | 最终类,不可继承 |
方法 | 不可重写 |
变量 | 常量,必须被初始化,初始化值不可修改只要在对象构造完成之前初始化即可 |
引申 为什么匿名内部类参数必须为final类型 局部内部类能访问方法中的所有的局部变量,问题在于 局部变量的生命周期与局部内部类的对象的生命周期的不一致性
1. 设方法f被调用,从而在它的调用栈中生成了变量i,此时产生了一个局部内部类对象inner_object,它访问了该局部变量i.
当方法f()运行结束后,局部变量i就已死亡了,不存在了
但:局部内部类对象inner_object还可能一直存在(只能没有人再引用该对象时,它才会死亡),它不会随着方法f()运行结束死亡.
这时:出现了一个"荒唐"结果:局部内部类对象 inner_object要访问一个已不存在的局部变量i!
2. 当变量是final时,通过将final局部变量"复制"一份,复制品直接作为局部内部中的数据成员.这样:当局部内部类访问局部变量 时,其实真正访问的是这个局部变量的"复制品"(即:这个复制品就代表了那个局部变量).因此:当运行栈中的真正的局部变量死亡时,局部内部类对象仍可以 访问局部变量(其实访问的是"复制品"),给人的感觉:好像是局部变量的"生命期"延长了.
3. 那么:核心的问题是:怎么才能使得:访问"复制品"与访问真正的原始的局部变量,其语义效果是一样的呢?
4. 当变量是final时,若是基本数据类型,由于其值不变,因而:其复制品与原始的量是一样.语义效果相同.(若:不是final,就无法保证:复制品与原始变量保持一致了,因为:在方法中改的是原始变量,而局部内部类中改的是复制品)
5. 当变量是final时,若是引用类型,由于其引用值不变(即:永远指向同一个对象),因而:其复制品与原始的引用变量一样,永远指向同一个对象(由于是 final,从而保证:只能指向这个对象,再不能指向其它对象),达到:局部内部类中访问的复制品与方法代码中访问的原始对象,永远都是同一个即:语义效 果是一样的.否则:当方法中改原始变量,而局部内部类中改复制品时,就无法保证:复制品与原始变量保持一致了(因此:它们原本就应该是同一个变量.)
from https://feiyeguohai.iteye.com/blog/1500108
-
java中Math函数易错知识
Math.round(-1.5) = -1
* <ul><li>If the argument is NaN, the result is 0. * <li>If the argument is negative infinity or any value less than or * equal to the value of {@code Integer.MIN_VALUE}, the result is * equal to the value of {@code Integer.MIN_VALUE}. * <li>If the argument is positive infinity or any value greater than or * equal to the value of {@code Integer.MAX_VALUE}, the result is * equal to the value of {@code Integer.MAX_VALUE}.</ul>
距离一致,取较大的值 Math.rint(-10.5) = -10.0 Math.rint(-11.5) = -12.0
StrictMath.rint(a) x取整为它最接近的整数,如果x与两个整数的距离相等,则返回其中为偶数的那一个
6.java的基本数据类型 java中有8中基本类型 byte boolean char short int float long double
基本类型 | 字节长度 | 默认值 |
---|---|---|
byte | 1 | 0 |
short | 2 | 0 |
int | 4 | 0 |
long | 8 | 0L |
float | 4 | 0.0f |
double | 8 | 0.0d |
char | 2 | ‘\u0000’ |
boolean | 1 | false |
- Java中字符串操作类,String StringBuffer StringBuilder 对比
操作类 | 特点 |
---|---|
String | 声明不可变对象,每次操作产生新的对象,修改指针指向 |
StringBuffer | 线程安全,每次可操作原有对象 |
StringBuilder | 线程不安全,更高性能,操作原有对象 |
StringBUffer 在方法上使用 synchronized关键字 保证线程安全