Java 接口
文章目录
- 抽象方法和抽象类
- 接口
- 使用接口模拟多继承
- 接口之间的继承
- 接口的使用实例
- Clonable接口和深浅拷贝
- object类
- 对象的equals比较方法

抽象方法和抽象类
- 如果一个类中有抽象方法,那么这个类也必须是抽象类,抽象类中不一定包含抽象方法,
- 抽象类和抽象方法都由abstract修饰
abstract class Shape{public abstract void draw();
}
-
什么叫做抽象类?
抽象类:如果一个类不能具体地描绘一个对象,比如Animal -
抽象类不能实例化对象,因为不能具体描绘一个对象
-
抽象类和普通类一样,可以定义成员变量和成员方法
6. 当一个普通类继承了抽象类,必须对抽象类中的所有抽象方法进行重写,不然会报错 -
为什么会出现抽象类?
为了被继承,不然没有用 -
抽象类不能被private修饰,不能被static和final修饰,被static和final,private修饰的不能重写,而抽象类可以重写
-
抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量
抽象类必须被继承,并且子类重写父类中的抽象方法,否则也必须是抽象类,要使用abstract修饰
// 否则,到最后如果第一个抽象类中有抽象方法,
// 到最后一个类继承的时候也必须重写它的方法
abstract class Shape{}abstract class Pa extends Shape{}
抽象类的作用:提示语法错误,子类必须重写父类的抽象方法
接口
- 接口属于一种标准
- 接口是多个类的公共规范,是一种引用数据类型
- 语法:
a. 接口是interface修饰的
b. 接口中的抽象方法默认都是public abstract修饰的
c. 接口中的成员变量默认都是public static final 修饰的,所以要赋个值,是常量
d. 接口中不能有被实现的方法,只能有抽象方法,除了两个方法:一个是static修饰的方法,一个是default修饰的方法
e. 接口不能实例化
f. 用类实现这个接口,使用implements关联类和接口关联,第一种使用抽象类实现这个接口,后续继承的类还要实现接口中的抽象方法,第二种实现接口中的抽象方法
g. 接口也有对应的字节码文件
public interface Shape{public abstract void draw();// == void draw();public static final int A = 1;// == int A = 1;public static void draw1(){}default public void draw2(){}
}// Ract 类名
abstract class Ract implements Shape{}/class Ract implements Shape{public void draw(){System.out.println("矩形");}
}interface Shape{public static void draw1(){System.out.println("a");}public abstract void draw();//default public void a(){//}// public abstract void b();
}class Ract implements Shape{public void draw(){System.out.println('*');}
}class Flower implements Shape{public void draw(){System.out.println('!');}
}public class test {public static void drawMap(Shape shape){shape.draw();}public static void main(String[] args) {Shape shape1 = new Ract();Shape shape2 = new Flower();drawMap(shape1);drawMap(shape2);Shape[] shape3 = {new Ract(),new Flower(),new Ract(),new Flower()};for(Shape shape : shape3){shape.draw();}}
}
- 子类的访问权限必须比接口中的大,只能是public
- 接口中不能有静态和动态代码块和构造方法
- 接口虽然不是类,但是编译完成后的字节码文件的后缀是.class
- 如果类没有实现接口中所有的抽象方法,则类必须设置为抽象类,反正到某个类继承,最后都要实现
5. 可以在一个包下,写一个接口,很多个类实现这个接口,最后使用这些类实例化对象,调用实现的方法,达到多态的效果
使用接口模拟多继承
- Java中没有多继承,只能想办法实现多继承
- 一个类可以实现多个接口
- 一个类继承父类具备某种特性
- 可以忘记类型,即使不是动物也可以使用这些接口
public abstract class Animal {public String name;public int age;public Animal(String name, int age) {this.name = name;this.age = age;}public abstract void eat();
}
public interface IRunning {void run();
}
public interface ISwimming {void swim();
}
public interface IFlying {void fly();
}
public class Dog extends Animal implements IRunning,ISwimming{public Dog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println(name+"吃狗粮!");}@Overridepublic void run() {System.out.println(name+"用狗腿在跑");}@Overridepublic void swim() {System.out.println(name+"用狗腿游泳");}
}
public class Bird extends Animal implements IRunning,IFlying{public Bird(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println(name+"吃鸟粮");}@Overridepublic void fly() {System.out.println(name+"用翅膀飞");}@Overridepublic void run() {System.out.println(name+"用鸟腿跑");}
}
public class Test {public static void test1(Animal animal) {animal.eat();}public static void test2(IRunning iRunning) {iRunning.run();}public static void test3(ISwimming iSwimming) {iSwimming.swim();}public static void test4(IFlying iFlying) {iFlying.fly();}public static void main(String[] args) {// 子类可以给接口,然后接口对象调用它的方法test1(new Dog("狗",4));test2(new Dog("狗",4));test3(new Dog("狗",4));System.out.println("=====================");test1(new Bird("鸟",2));test2(new Bird("鸟",2));test4(new Bird("鸟",2));}
}
接口之间的继承
- 接口A可以拓展接口B的功能,也就是A接口同时具备了B接口的功能
- 接口A和B都是testA的功能,那么重写的是谁的功能?
重写的是接口B的testA()
接口的使用实例
- 实例化两个Student对象,并比较他们的大小,无法用对象直接比较大小,可以使用实现接口比较大小
class Student implements Comparable<Student>{public String name;public int age;public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}// 接口的实现@Overridepublic int compareTo(Student o) {/*法一:if(this.age > o.age) {return 1;}else if(this.age < o.age) {return -1;}else {return 0;}*///法二:return this.age - o.age;}
}// 调用这个方法比较大小
public class test{public static void main(String[] args){Student student1 = new Student("zhangsan",10);Student student2 = new Student("lisi",20);System.out.println(student1.compareTo(student2));}
}
-
如果这个类要根据姓名比较,是不是要修改方法,这里我们使用比较器进行比较
age的类比较age,name的类比较name
-
对比:单独写两个对象传入的比写在类里面的比较方式灵活性更强
-
一般一个自定类型的类里面会写一个默认的比较方法
5. 可以自己写一个排序方法,使用自己类内部的比较方法进行比较
Clonable接口和深浅拷贝
- object类中有一个clone方法,调用这个方法可以创建一个对象的拷贝
- 我们自己写的类要实现克隆,必须实现Clonable接口
为什么调用不了clone方法?
1.clone方法由protected修饰,需要用super.
2.需要在子类中重写clone方法
package test1;// 有implements Cloneable接口后表明这个类是可以被克隆的class Person implements Cloneable{public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class test11 {public static void main(String[] args) throws CloneNotSupportedException{Person person = new Person("张三",20);Person person2 = (Person)person.clone();// cloneSystem.out.println(person2);System.out.println(person);}
}
- 浅拷贝
克隆前:19.99 19.99
克隆后:99.99 99.99
为什么呢?
因为是浅拷贝,Money对象都指向了同一份
浅拷贝就是值拷贝,就是把person复制了一份过去
class Money{public double m = 19.99;
}class Person implements Cloneable{public int age;public String name;public Money money = new Money();public Person(int age,String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Person{" +"age=" + age +String + '}';}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}//克隆方法在Object当中,并且由protected修饰,所写类默认继承Object类
//protected:不同包中的子类.同时使用时,需要super调用
public class Test2 {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person(3);Person person2 = (Person)person1.clone();System.out.println(person1.money.m);//19.99System.out.println(person2.money.m);//19.99System.out.println("=========================");person2.m.money = 99.99;System.out.println(person1.money.m);//99.99System.out.println(person2.money.m);//99.99
//person2.m.money = 99.0;这句代码原本应该是只改变person1.m.money的值,但是person2也改变了}
}
- 深拷贝
每个person都有自己的一份Money对象
tmp出了作用域就销毁
class Money implements Cloneable{public double money = 19.99;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}class Person implements Cloneable{public int age;public String name;public Money money = new Money();public Person(int age,String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Person{" +"age=" + age +String + '}';}@Overrideprotected Object clone() throws CloneNotSupportedException {//这里面在克隆person 但是我没看到你克隆money,那么怎么克隆呢?(重点)Person tmp = (Person)super.clone();tmp.money = (Money)this.money.clone();return tmp;// return super.clone();//克隆的返回值类型为Object需要强转}
}//克隆方法在Object当中,并且由protected修饰,所写类默认继承Object类
//protected:不同包中的子类.同时使用时,需要super调用
public class Test2 {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person(3);Person person2 = (Person)person1.clone();System.out.println(person1.money.m);// 19.99System.out.println(person2.money.m);// 19.99System.out.println("=========================");person2.m.money = 99.99;System.out.println(person1.money.m);// 19.99System.out.println(person2.money.m);// 99.99}
}
object类
- Java中默认所有的类都继承于object类
- 所有类的对象可以用object类的引用进行接收
- 可以重写equals方法,toString方法和hashCode方法
对象的equals比较方法
- 编译器默认比较的是两个对象的地址,这是不符合我们的比较的
2. 正确的比较方法:
重写equals
class Student{public String name;public int age;public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}// 自己重写一个equals方法/*@Overridepublic boolean equals(Object obj) {Student tmp = (Student)obj;// 要同一中类型的才能比较,应该都为子类对象// return this.name.equals(obj.name);return this.name.equals(tmp.name) &&this.age == tmp.age;}*/
}
public class test11 {public static void main(String[] args) {Student person = new Student("张三",20);Student person1 = new Student("张三",20);System.out.println(person.equals(person1));}
}
- hashcode方法是用来算一个具体对象的位置的