目录
🎓抽象类
🎈抽象类语法
🎈抽象类特性
🎈抽象类的作用
🎓接口
🎈语法规则
🎈接口特性
🎈接口使用(实现USB接口)
🎈实现多个接口
🎈接口间的继承
🎈接口使用实例 (给对象数组排序)
🌈Comparable接口<比较>
🌈Comparator接口<比较器>
🚩抽象类和接口的区别
🎓抽象类
抽象类自己本身是不具有什么特性的,就比如Shape类中我们有draw方法,但是Shape并没有什么具体的形状,而继承的子类比如三角形类,矩形类,圆形类等都是在有具体图形,我们称Shape类是抽象类。
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的, 如果 一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
在打印图形例子中 , 我们发现 , 父类 Shape 中的 draw 方法好像并没有什么实际工作 , 主要的绘制图形都是由 Shape的各种子类的 draw 方法来完成的 . 像这种没有实际工作的方法 , 我们可以把它设计成一个 抽象方法 (abstract method) , 包含抽象方法的类我们称为 抽象类 (abstract class)
🎈抽象类语法
// 抽象类:被abstract修饰的类
abstract class Shape1{// 抽象方法:被abstract修饰的方法,没有方法体abstract public void draw();abstract void calcArea();// 抽象类也是类,也可以增加普通方法和属性public int age;public void func(){};
}
🎈抽象类特性
1. 抽象类不能直接实例化对象 new
肯定很多人疑问,抽象类不能实例化对象,那么存在意义在哪?—抽象类存在的意义是为了被继承
public class Test {Shape1 shape1=new Shape1();
}
//Shape1是抽象类,不能实例化
2.抽象类和普通类不一样的是抽象类可以包含抽象方法,可以包含普通类所包含的成员(上述语法已讲述)
3.抽象类和抽象方法都是由abstract修饰的,方法中没有具体的实现体(上述语法)
4.抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract 修饰(被abstract修饰就不用重写方法,应用于有些类不需要这个方法)
abstract class Shape1{// 抽象方法:被abstract修饰的方法,没有方法体abstract public void draw();
}
class Cycle1 extends Shape1{@Overridepublic void draw() {System.out.println("画⚪");}
}
5.如果一个抽象类B继承了一个抽象类A,此时B当中不需要重写A的重写方法,但如果B再被
普通类继承,就需要重写。
6.抽象方法不能被private,final和static修饰,因为抽象方法要被子类重写我们可以这样想,方法就是为了重写设置成私有的,怎么能被重写?并且我们在 重写的时候说到 (java子类方法权限要等于大于父类的访问权限?)
7. 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类
8. 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量❗A类abstract class A{public int age;public String name;public A(int age,String name){this.age=age;this.name=name;}abstract public void func();
❗B类
class B extends A{public B(){super(8,"chenle");}public void func(){System.out.println("sadasd");} }
❗运行区
🎈抽象类的作用
有些同学可能会说了, 普通的类也可以被继承呀, 普通的方法也可以被重写呀, 为啥非得用抽象类和抽象方法
呢
🎓接口
🎈语法规则
public interface 接口名称{
// 抽象方法
public abstract void method1(); // public abstract 是固定搭配,可以不写
public void method2();
abstract void method3();
void method4();
// 注意:在接口中上述写法都是抽象方法,跟推荐方式4,代码更简洁
}
提示:1. 创建接口时, 接口的命名一般以大写字母 I 开头.2. 接口的命名一般使用 "形容词" 词性的单词.3. 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性
🎈接口特性
1.使用interface来修饰接口
2.接口当中的成员方法,不能有具体的实现 [默认是public]
所以子类的重写方法不能默认不写,子类的重写方法是default,而子类的访问权限要大于父类的访问权限,所以我们必须在子类中的重写方法前写上public
- 抽象方法:默认是public abstract方法
- JDK1.8开始 ,允许有可以实现的方法,但是这个方法只能由default修饰
- 可以实现一个静态方法
interface Ishape{public abstract void draw();//抽象方法void draw();//这是最好的表达抽象方法方式default public void draw1(){System.out.println("默认方法");}public static void draw2(){System.out.println("静态方法");} }
3.成员变量默认是public static final 修饰的(是不能修改的)
成员方法 默认是public abstract 修饰(其他修饰符都是错的)
public static final int age=10;//public static finalvoid draw3();//public abstract
4.接口不能被实例化(抽象类也不能实例化)因为接口中的方式默认为抽象方法
5.类和接口之间采用implements来实现多个接口
一旦类实现接口之后,就必须重写这个接口里面的抽象方法。接口里的普通成员方法可以重写也可以不重写。
interface Itest{void draw3();//public abstractdefault public void draw1(){System.out.println("默认方法");}public static void draw2(){System.out.println("静态方法");} } class Cycle implements Itest{@Overridepublic void draw3() {System.out.println("必须重写");}@Overridepublic void draw1() {System.out.println("可以重写也可以不重写");} }
6.将接口想象成特殊的类,我们可以当作参数,接口不能实例化,但是可以new普通的类。
interface Ishape{void draw(); } class Cycle implements IShape{@Overridepublic void draw() {System.out.println("画⚪");} } class Rect implements IShape{@Overridepublic void draw() {System.out.println("画矩形");} }class Flowers implements IShape{@Overridepublic void draw() {System.out.println("画❀");} } public class Test3 {public static void Map(IShape iShape){iShape.draw();}public static void main(String[] args) {Cycle cycle=new Cycle();Map(cycle);Map(new Flowers());Map(new Rect());}
相当于 Ishape ishape=new Cycle();
ishape.draw();实现创建对象,进行对接口的调用。
7. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
一个接口就是一个java文件
8.接口中不能有静态代码块和构造方法
9.如果不想实现接口的方法,那么就将这个类定义成抽象类,但是如果这个类被其他类继承,那么必须重写。(这个和抽象类类似)
🎈接口使用(实现USB接口)
public class 类名称 implements 接口名称{
// ...
}
请实现笔记本电脑使用 USB 鼠标、 USB 键盘的例子1. USB 接口:包含打开设备、关闭设备功能2. 笔记本类:包含开机功能、关机功能、使用 USB 设备功能3. 鼠标类:实现 USB 接口,并具备点击功能4. 键盘类:实现 USB 接口,并具备输入功能
package Interfaces;//USB接口
interface Iusb{void openDevice();void closeDevice();
}
//鼠标类
class Mouse implements Iusb{@Overridepublic void openDevice() {System.out.println("打开鼠标");}@Overridepublic void closeDevice() {System.out.println("关闭鼠标");}public void click(){System.out.println("点击鼠标");}
}// 键盘类,实现USB接口
class KeyBoard implements Iusb {@Overridepublic void openDevice() {System.out.println("打开键盘");}@Overridepublic void closeDevice() {System.out.println("关闭键盘");}public void inPut(){System.out.println("键盘输入");}
}// 笔记本类:使用USB设备
class Computer {public void powerOn() {System.out.println("打开笔记本电脑");}public void powerOff() {System.out.println("关闭笔记本电脑");}public static void useDevice(Iusb iusb){iusb.openDevice();if(iusb instanceof Mouse){Mouse mouse=(Mouse) iusb;mouse.click();}else if(iusb instanceof KeyBoard){KeyBoard keyBoard=(KeyBoard) iusb;keyBoard.inPut();}iusb.closeDevice();}}
public class Test4 {public static void main(String[] args) {Computer computer = new Computer();//打开设备computer.powerOn();//使用鼠标设备computer.useDevice(new Mouse());//使用键盘设备computer.useDevice(new KeyBoard());//关闭设备computer.powerOff();}
}
🎈实现多个接口
一个类可以实现多个接口。使用implements用逗号隔开。【可以解决多继承的问题】
我们可以定义一个动物类,然后狗类继承了动物类,我们实现多个接口,有些动物是又会飞又会跑,又会游泳的。
interface Running{void run();
}
interface Flying{void fly();
}
interface Swimming{void swim();
}
我们实现多个接口,而不是实现多个类,因为java中只能继承一个类,而不能继承多个类,但是一个类可以实现多个接口。我们不需要创建一个swim类,fiy类,run类,然后里面有自己的swim,fly,run的成员方法,然后狗类一个一个继承,因为java中不能多继承,所以代码的重复,而实现多个接口正是可以解决java中的多继承问题,让一个狗类同时implement多个接口,然后重写方法,即可完成了一个类继承多个接口的方法。
❗各接口
interface Running{void run();
}
interface Flying{void fly();
}
interface Swimming{void swim();
}
❗Animal类和各种子类
class Animal{int age;String name;Animal(int age,String name){this.age=age;this.name=name;}void eat(){System.out.println("正在吃饭");}
}class Dog extends Animal implements Running,Swimming{public Dog(int age, String name) {super(age, name);}@Overridepublic void run() {System.out.println(name+"正在跑");}@Overridepublic void swim() {System.out.println(name+"正在游泳");}public void eat(){System.out.println(name+"吃狗粮");}}
class Bird extends Animal implements Flying{public Bird(int age, String name) {super(age, name);}@Overridepublic void fly() {System.out.println(name+"正在飞");}public void eat(){System.out.println(name+"吃鸟粮");}
}
class Duck extends Animal implements Flying,Swimming,Running{public Duck(int age, String name) {super(age, name);}public void run() {System.out.println(name+"正在跑");}@Overridepublic void swim() {System.out.println(name+"正在游泳");}public void fly() {System.out.println(name+"正在跑");}public void eat(){System.out.println(name+"吃鸭粮");}
}
❗测试方法
public class Test6 {public static void walk(Running running){running.run();}public static void func(Animal animal){animal.eat();}public static void main(String[] args) {walk(new Dog(13,"chq"));walk(new Duck(12,"chhh"));}
}
🎈接口间的继承
就是说我们D1类是一个既能完成A1的行为,也能完成B1的行为,还能完成C1接口行为,然后我们接口C1继承了A1和B1的接口,其实C1继承A1和B1的行为,就相当于如果类实施了C1,那么这三个A1,B1,C1都是行动的。
接口间的继承相当于把多个接口合并在一起.
🎈接口使用实例 (给对象数组排序)
❗Animal类
class Student{public int age;public String name;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}
}
❗运行
这段代码是错误的,我们不管是按照什么来排序的,不管是年龄还是姓名都是错误的,我们可以来分析一下这段错误。
🌈Comparable接口<比较>
✅按照年龄来比较(Comparable 接口, 并实现其中的 compareTo 方法)
class Student implements Comparable<Student>{public int age;public String name;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}@Overridepublic int compareTo(Student o) {if(this.age>o.age){return 1;}else if(this.age<o.age){return -1;}else{return 0;}}
}
当Student类实施了Comparable接口并且实现了compareTo方法,我们就可以根据年龄来进行比较。
我们可以看到底层,底层代码的比较是调用compareTo方法比较
public static void main(String[] args) {Student student1=new Student(18,"chenle");Student student2=new Student(13,"zhang");if(student1.compareTo(student2)>0){System.out.println("student1>student2");}else {System.out.println("student2>student1");}}
🌈Comparator接口<比较器>
✅按照姓名来比较(实现Comparator接口,并实现compare方法)
我们是不能更改age的比较方法,那样势必回影响后面的运行,如果代码已经运行了一个月了,如果更改会影响很多。
所以我们需要利用 另外一个接口Comparator<T>以及接口里的compare方法
Comparator<T>接口中有很多方法,我们只需要compare抽象方法即可。
❗AgeCompare
class AgeCompare implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.age-o2.age;}
}
❗运行
public static void main(String[] args) {Student[] students=new Student[3];students[0]=new Student(18,"chenle");students[1]=new Student(13,"zhang");students[2]=new Student(9,"hao");AgeCompare ageCompare=new AgeCompare();Arrays.sort(students,ageCompare);System.out.println(Arrays.toString(students));}
❗NameCompare
因为比较字符串的底层是利用Comparable接口中的compareTo方法
class NameCompare implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.name.compareTo(o2.name);}
}
❗运行
public static void main(String[] args) {Student[] students=new Student[3];students[0]=new Student(18,"chenle");students[1]=new Student(13,"zhang");students[2]=new Student(9,"hao");NameCompare nameCompare=new NameCompare();Arrays.sort(students,nameCompare);System.out.println(Arrays.toString(students));}
我个人更推荐第二种,我们自己单独设置个类,然后我们直接利用比较器比较,如果比较整型直接return俩者相减即可,如果比较字符串,我们需要利用到compareTo方法进行比较。
🚩抽象类和接口的区别
祝你逃出苦难向春山。