4. 抽象类和接口的区别
核心区别: 抽象类中可以包含普通方法和普通字段,这样的普通方法和字段可以被子类直接使用(不必重写),而接口中不能包含普通方法,子类必须重写所有的抽象方法。
区别 |
抽象类(abstract) | 接口(interface) | |
1 | 结构组成 | 普通类+抽象方法 | 抽象方法+全局变量 |
2 | 权限 | 各种权限 | public |
3 | 子类使用 | 使用extends关键字继承抽象类 | 使用implements关键字实现接口 |
4 | 关系 | 一个抽象类可以实现若干接口 | 接口不能继承抽象类,但是接口可以使用extends关键字继承多个父接口 |
5 | 子类限制 | 一个子类只能继承一个抽象类 | 一个子类可以实现多个接口 |
5. Object类
Object 是 Java 默认提供的一个类。Java里面除了 Object类,所有的类都是存在继承关系的。默认会继承 Object父类。即所有类的对象都可以使用 Object 的引用进行接收。
实例:使用Object接收所有类的对象
class Person{} class Student{} public class Test { public static void main(String[] args) { function(new Person()); function(new Student()); } public static void function(Object obj) { System.out.println(obj); } } //执行结果: Person@1b6d3586 Student@4554617c
在开发之中,Object类是参数的最高统一类型。
但是Object类也存在有定义好的一些方法。如下:
5.1 获取对象信息
如果要打印对象中的内容,可以直接重写Object类中的toString()方法
// Object类中的toString()方法实现: public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
5.2 对象比较equals方法
在Java中,进行比较时:
- 如果==左右两侧是基本类型变量,比较的是变量中值是否相同
- 如果==左右两侧是引用类型变量,比较的是引用变量地址是否相同
- 如果要比较对象中内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的:
// Object类中的equals方法 public boolean equals(Object obj) { return (this == obj); // 使用引用中的地址直接来进行比较 }
实例:判断相等
class Person{ private String name ; private int age ; public Person(String name, int age) { this.age = age ; this.name = name ; } } public class Test1 { public static void main(String[] args) { Person p1 = new Person("gaobo", 20) ; Person p2 = new Person("gaobo", 20) ; int a = 10; int b = 10; System.out.println(a == b); // 输出true System.out.println(p1 == p2); // 输出false System.out.println(p1.equals(p2)); // 输出false } }
Person类重写equals方法后,然后比较:
class Person{ private String name ; private int age ; public Person(String name, int age) { this.age = age ; this.name = name ; } public boolean equals(Object obj) { if (obj == null) { return false ; } if(this == obj) { return true ; } // 不是Person类对象 if (!(obj instanceof Person)) { return false ; } Person person = (Person) obj ; // 向下转型,比较属性值 return this.name.equals(person.name) && this.age==person.age ; } } public class Test1 { public static void main(String[] args) { Person p1 = new Person("gaobo", 20) ; Person p2 = new Person("gaobo", 20) ; int a = 10; int b = 10; System.out.println(a == b); // 输出true System.out.println(p1 == p2); // 输出false System.out.println(p1.equals(p2)); // 输出true } }
所以比较对象中内容是否相同的时候,一定要重写equals方法。
5.3 hashcode方法
hashcode方法源码:
public native int hashCode(); //该方法是一个native方法,底层是由C/C++代码写的。
我们认为两个名字相同,年龄相同的对象,将存储在同一个位置,如果不重写hashcode()方法,我们可以来看示例代码:
class Person { public String name; public int age; public Person(String name, int age) { this.name = name; this.age = age; } } public class Test1 { public static void main(String[] args) { Person per1 = new Person("gaobo", 20) ; Person per2 = new Person("gaobo", 20) ; System.out.println(per1.hashCode()); System.out.println(per2.hashCode()); } }
🍤 运行结果:
从运行结果可以发现:两个对象的hash值是不一样的。
重写hashcode()方法:
import java.util.Objects; //重写hashCode class Person { public String name; public int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public int hashCode() { return Objects.hash(name, age); } } public class Test1 { public static void main(String[] args) { Person per1 = new Person("gaobo", 20) ; Person per2 = new Person("gaobo", 20) ; System.out.println(per1.hashCode()); System.out.println(per2.hashCode()); } }
🍤 运行结果:
此时,哈希值是一样。
注:
- hashcode方法用来确定对象在内存中存储的位置是否相同
- 事实上hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。