1.Object类
Object类是所有类的父类,所有类都默认继承Object类,所以任何类都可以用Object类用来接收
1.1获取对象信息
public class Main {
class Person{
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override//重写toString方法
public String toString() {
return this.name + " " + this.age;
}
}
public static void main(String[] args) {
{
int a=1;
int b=2;
int c=3;
}
Object obj1 = new Person("RRR",32);//接受类
System.out.println(obj1.toString());输出信息
}
}
}
//运行结果
//RRR 32
1.2 对象比较-equals
在Java中,用equals比较时,基本引用类型则比较变量值是否相同,引用类型则是比较变量地址是否相同,如果要比较对象内容,一定要重写equals方法。
如下图:
public static void main(String[] args) {
int a1=1;
int b1=2;
int c1=3;
// System.out.println(Objects.equals(a1, b1));
// Object obj1 = new Person("RRR",32);
// System.out.println(obj1.toString().equals("RRR 32"));
Object ME = new Person("刘佳",18);
Person other =new Person("刘佳",18);
Person RER = new Person("Ewew",312);
System.out.println(other.equals(other));
System.out.println(ME.equals(other));
System.out.println(other.equals(ME));
}
}
//true
//false
//false
//以下在类中重写之后,即可得到3个true
// @Override
// public boolean equals(Object obj) {
// if (obj == null){
// return false;}
// if (this == obj)
// { return true;}
// if(!(obj instanceof Person)) {
// return false;
// }
// Person other = (Person) obj;
// return this.name.equals(other.name) && this.age == other.age;
// }
可以看出来,如果不重写类里面的equals方法,是无法比较类的内容的,只有重写之后,才能比较其内容,否则比较的是变量地址。就是false
1.3hashcode方法
hashCode这个方法就是给出一个具体的对象位置,这个对象位置以16进制输出
hashCode底是用C/C++写的,我们不用太关注
如果我们不重写hashCode方法,两个相同的类存放的位置就不一样,重写之后,即两个存放位置一样,如下图:
@Override
public int hashCode() {
return Objects.hash(name, age);
}
在类中重写之后:
小结:1.hashcode方法用来确定对象在内存中存储的位置是否相同
2.事实上hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。
2. 抽象类
2.1 抽象类概念
在面向对象的概念中,所有的对象都是通过类来描绘的,但是不是所有的都是这样的,如果某一个类里面没有包含足够的信息来描述一个具体的对象,这样的类就是抽象类
如上图所示的植物类,就是一个抽象类 ,抽象类中存在抽象方法,它并没有实际的工作方法,只能依靠子类中的重写方法来实现具体的工作,也就是多态性,来实现
2.2抽象类语法
抽象类中被abstract修饰的方法叫做抽象方法,抽象方法不用给出具体的实现方法
// 抽象类:被abstract修饰的类
public abstract class Plant {
// 抽象方法:被abstract修饰的方法,没有方法体
abstract public void easd();
abstract void casd2();
// 抽象类也是类,也可以增加普通方法和属性
public double getLength(){
return area;
}
protected double colar; //颜色
}
2.3 抽象类特性总结
- 抽象类不能直接实例化对象
- 抽象方法不能private的
- 抽象方法不能被final和static所修饰的,因为抽象方法要重写
- 抽象类必须被继承,并且子类要重写抽象方法,否则子类也是抽象类,必须也用abstract来修饰
抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量
抽象类可以防止父类被误用,在某些情况下,父类不小心被使用时,编译器不会报错,但如果父类是抽象类就不一样了,编译器及时提醒我们,充分利用编译器的校验机制,在开发过程中非常有意义的
3.接口
3.1接口概念
在 Java 中,接口可以看成是:多个类的公共规范,是一种引用数据类型并且实现接口的类中要重写接口中的抽象方法
public interface Ishape{
void draw();
}
//用一个类去实现接口,注意public修饰词,要分开
public class Test1 implements Ishape {
public void draw() {
System.out.println("draw");
}
}
3.2 语法规则
public interface 接口名称{
// 抽象方法
public abstract void method1(); // public abstract 是固定搭配,可以不写
public void method2();
abstract void method3();
void method4();
// 注意:在接口中上述写法都是抽象方法,推荐使用第四种
}
3.3 接口使用
要有一个类来实现该接口,并实现该接口中的所有抽象方法,不然会报错
package comit.demo2;
public class Test1 implements Ishape {
public void draw() {
System.out.println("draw");
}
public void move() {
System.out.println("move");
}
}
语法规则:
public class 类名称 implements 接口名称 {// ...}
3.4 接口特性
- 接口类型是一种引用类型,但是不能直接new接口的对象
public class TestUSB {public static void main ( String [] args ) {USB usb = new USB ();}}//java: comit.demo2.USB是抽象的; 无法实例化
-
接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract(只能是public abstract,其他修饰符都会报错)
- 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现
- 重写接口中方法时,不能使用默认的访问权限
- 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量
- 接口中不能有静态代码块和构造方法
public interface IShape {
// 编译失败
public IShape(){
}
{} // 编译失败
void draw();
void move();
}
-
接口不是类,但是接口编译完成后字节码文件的后缀格式也是.class
-
如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
- jdk8中:接口中还可以包含default方法。
3.5 实现多个接口
在 Java 中,类和类之间是单继承的,一个类只能有一个父类,即 Java 中不支持多继承 ,但是 一个类可以实现多个接 口 。下面通过代码解释
注意:一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类 。
3.6 接口间的继承
在 Java 中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承。用接口可以达到多继承的目的。
接口间的继承相当于把多个接口合并在一起.
3.7 接口使用实例
3.7.1对象数组排序
class Person implements Comparable {
private String name;
private int score;
public Person(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "[name=" + name + ", score=" + score + "]";
}
@Override
public int compareTo(Object o) {
Person p = (Person) o;
if (this.score > p.score) {
return -1;
} else if (this.score < p.score) {
return 1;
}else {
return 0;
}
}
}
public class Test1{
public static void main(String[] args) {
Person[] stu =new Person[]{
new Person("231",78),
new Person("231",86),
new Person("231",97),
};
Arrays.sort(stu);
System.out.println(Arrays.toString(stu));
}
}
运行结果:
在 sort 方法中会自动调用 compareTo 方法. compareTo 的参数是 Object , 其实传入的就是 Student 类型的对象.
利用Comparable可以实现类的冒泡排序,前提是必须重写CompareTo方法
public static void BubbleSort(Comparable[] a) {
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - i - 1; j++) {
if (a[j].compareTo(a[j+1]) < 0) {
Comparable c = a[j];
a[j] = a[j+1];
a[j+1] = c;
}
}
}
}
3.8 Clonable 接口和深拷贝
Clonable是一个Java内置的接口,非常有用
Object 类中存在一个 clone 方法 , 调用这个方法可以创建一个对象的 " 拷贝 ". 但是要想合法调用 clone 方法 , 必须要先实现 Clonable 接口 , 否则就会抛出 CloneNotSupportedException 异常
Clonable是一个空接口!!!它的作用就是标记当前类是可以被克隆的
package demo3;
public class Student implements Cloneable {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone()
throws CloneNotSupportedException { //解决异常
return super.clone();
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
class main {
public static void main(String[] args) //注意这里没有花括号
throws CloneNotSupportedException {
Student s1 = new Student("刘佳", 18);
Student s2 = (Student) s1.clone();
System.out.println(s1);
System.out.println(s2);
}
}
但两者的地址是不一样的:
假设每个学生类中还有一个钱包类,通过clone,我们只是拷贝了Student对象。但是Student对象中的Money对象,并没有拷贝。通过s2这个引用修改了m的值后,s1这个引用访问m的时候,值也发生了改变。这里就是发生了浅拷贝,如下代码:
public class Student implements Cloneable { private String name; private int age; Money money; public Student(String name, int age) { this.name = name; this.age = age; money = new Money(); } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", money=" + money + '}'; } class main { public static void main(String[] args) throws CloneNotSupportedException { Student s1 = new Student("刘佳", 18); Student s2 = (Student) s1.clone(); System.out.println("修改前"); System.out.println(s1.money.money); System.out.println(s2.money.money); s2.money.money=19.9; System.out.println("修改后"); System.out.println(s1.money.money); System.out.println(s2.money.money); } }
如上就是发生了浅拷贝,只是将对象的内容完完全全复制了一份到另一个空间
对上进行深拷贝,其实就是将学生中的money再拷贝一份,如下代码,
package demo3;
class Money implements Cloneable{
public double money=9.9;
@Override
protected Object clone()
throws CloneNotSupportedException {
return super.clone();
}
}
public class Student implements Cloneable {
private String name;
private int age;
Money money;
public Student(String name, int age) {
this.name = name;
this.age = age;
money = new Money();
}
@Override
protected Object clone()
throws CloneNotSupportedException {
Student student = (Student) super.clone();
student.money = (Money)this.money.clone();//克隆一份新的money
return student;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", money=" + money +
'}';
}
}
class main {
public static void main(String[] args)
throws CloneNotSupportedException {
Student s1 = new Student("刘佳", 18);
Student s2 = (Student) s1.clone();
System.out.println("修改前");
System.out.println(s1.money.money);
System.out.println(s2.money.money);
s2.money.money=187.9;
System.out.println("修改后");
System.out.println(s1.money.money);
System.out.println(s2.money.money);
}
}
运行结果:
3.9 抽象类和接口的区别
抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别(重要!!! 常见面试题).
核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法
假设一个动物类中有皮毛颜色等属性,这些属性在其子类中也存在,也就注定了动物类无法称为接口.只能作为抽象类
抽象类存在的意义是为了让编译器更好的校验, 像 Animal 这样的类我们并不会直接使用, 而是使用它的子类.万一不小心创建了 Animal 的实例, 编译器会及时提醒我们.