区别:
==解读
对于基本类型和引用类型==的效果是不同的
基本类型:比较的是值是否相同
引用类型:比较的是引用是否相同
equals解读
equals本质上就是==,如果一个类不重写equals方法,默认的equals方法实现就是==
Object的equals的实现方法:
public boolean equals(Object obj) {
return (this == obj);
}
代码演示
String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true
x==y 因为指向的是同一个引用所以结果为true
x==z 因为new String()开辟了新的内存空间,所以为false
因为String类重写了equals方法,所以equals比较的都是true
不对,两个对象的 hashCode()相同,equals()不一定 true。
代码示例:
String str1 = "通话";
String str2 = "重地";
System.out.println(String.format("str1: %d | str2: %d", str1.hashCode(), str2.hashCode()));
System.out.println(str1.hashCode() == str2.hashCode());
System.out.println(str1.equals(str2));
输出结果:
str1: 1179395 | str2: 1179395
true
false
代码解读:很显然“通话”和“重地”的 hashCode() 相同,然而 equals() 则为 false,因为在散列表中,hashCode()相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。
首先我们要明确一些概念:
不重写hashCode一般不会有什么影响,但一旦涉及到hash有关的计算,如放到HashSet集合中就可能出现与预期不一样的结果。
例如:
import java.util.Objects;
/**
* @author ZhengNC
* @date 2020/5/28 22:21
*/
public class Student {
private int age;
private String name;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name);
}
}
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author ZhengNC
* @date 2020/5/28 22:26
*/
public class Test {
public static void main(String[] args) {
Student a = new Student(1, "a");
Student b = new Student(2, "a");
System.out.println(a.equals(b));
System.out.println(a.hashCode() == b.hashCode());
List<Student> list = new ArrayList<>();
list.add(a);
//如果不存在b,ArrayList直接调用equals方法判断是否存在
if (!list.contains(b)){
list.add(b);
}
System.out.println("--------list---------");
System.out.println(list);
Set<Student> set = new HashSet<>();
set.add(a);
//如果不存在b,HashSet先调用hashCode方法判断,
// 如果hashCode不一样就立刻认为不一样,就不再继续调用equals方法判断了
if (!set.contains(b)){
set.add(b);
}
System.out.println("--------set---------");
System.out.println(set);
}
}
运行结果:
true
false
--------list---------
[Student{age=1, name='a'}]
--------set---------
[Student{age=2, name='a'}, Student{age=1, name='a'}]
在Student类中重写了equals方法,没有重写hashCode方法。
在上面的测试方法中a和b的equals相同,hashCode不同。
判断相同的对象不重复放入集合中,ArrayList和HashSet的处理方式就不一样,ArrayList直接调用equals方法判断对象是否相同,所以ArrayList认为a和b是相同的。HashSet先调用hashCode方法判断,如果hashCode不同直接就认为两个对象不同,不再调用equals做判断。
等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。
JAVA共有8种基本数据类型:byte、short、int、long、float、double、char、boolean
它们的包装类型分别是:Byte、Short、Integer、Long、Float、Double、Character、Boolean
String不是基本数据类型。
有三种:String、StringBuilder、StringBuffer
String和StringBuilder、StringBuffer的区别是String声明的是不可变的字符串对象,每次修改值都会产生新的String对象,然后将指针指向新的String对象,而StringBuilder、StringBuffer可以在对象原有的基础上进行操作,因此对于经常改变字符串内容的情况下最好不要使用String。
StringBuilder和StringBuffer的最大区别是StringBuilder是非线程安全的,StringBuffer是线程安全的,StringBuilder的效率要高于StringBuffer,因此在单线程环境中建议使用StringBuilder,在多线程环境下建议使用Stringbuffer。
String str="a"是把“a”分配到常量池中,而String str=new String(“a”)是在常量池中创建“a”之后再复制到堆内存中,然后返回堆内存的引用给str。
String str1 = new String("a");
String str2 = "a";
String str3 = str1.intern();//返回字符串对象的规范形式,就是返回常量池中的那一份对象
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str2 == str3);
运行结果:
false
false
true
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。
不需要,抽象类不一定非要有抽象方法。
不可以。
不能,抽象类定义出来就是为了让其它类继承的,而final修饰的类不能被继承,因此final不能修饰抽象类。
实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
main 方法:抽象类可以有 main 方法,并且我们能运行它;接口不能有 main 方法。
public abstract class MyAbstract {
public static void main(String[] args) {
System.out.println("abstract");
}
}
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:
接口中的方法默认使用 public 修饰,并只能是public修饰;
抽象类中的方法默认为default修饰,普通方法可以是任意访问修饰符,而抽象方法不能是private修饰。
修饰符 | 类内部 | 同一包 | 子类 | 任何地方 |
---|---|---|---|---|
private | 是 | 否 | 否 | 否 |
default | 是 | 是 | 否 | 否 |
protected | 是 | 是 | 是 | 否 |
public | 是 | 是 | 是 | 是 |
按功能来分:输入流(input)、输出流(output)。
按类型来分:字节流和字符流。
字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。