1. 抽象类
简而言之,如果没有足够的信息去描述一个对象,那么这样的类就是抽象类。
抽象类用abstract来修饰。例如图型Shape类
package demo1;
public abstract class Shape {
public abstract void draw();
}
在shape类中,我们没有足够的信息去描述这个模糊的shape,所以我们可以去将Shape类去定义为一个抽象类。
在抽象类中,内部也可以包含普通的方法和属性,但在抽象类中不能去实例化对象。在其中的抽象方法也不能被private,final,static修饰。
抽象类的作用主要是用来被继承,在被继承的类中,要重写父类中的抽象方法。除非子类也是抽象类。
通过继承抽象类Shape,在子类中重写抽象方法
package demo1;
public class Cycle extends Shape{
@Override
public void draw() {
System.out.println("画一个圆形");
}
}
而重写抽象方法后,编译器会自动进行校验,强制了子类实现抽象方法,确保了代码的正确性。
2. 接口
接口通过interface来实现,其在生活中有很多体现,例如USB的接口。
package demo2;
public interface USB {
void openService();
void closeService();
}
在USB接口中,定义了openService和closeService方法。其方法的固定搭配为public abstract,但是最好进行省略,保证代码的简洁性。
除此之外,在接口中,接口类型不能直接进行实例化;
接口中的方法不能进行具体的实现;
接口中的变量会被隐式地指定为public static final;
接口中不能含有静态代码块和构造方法
在USB的例子中,我们接着可以定义鼠标,键盘类通过implements来连接我们的接口USB。在鼠标键盘类中,要重写我们的接口方法,在方法中,我们就可以进行具体的功能实现。
Mouse:
package demo2;
public class Mouse implements USB{
@Override
public void openService() {
System.out.println("打开鼠标");
}
@Override
public void closeService() {
System.out.println("关闭鼠标");
}
public void click(){
System.out.println("点击鼠标");
}
}
Keyboard:
package demo2;
public class Keyboard implements USB{
@Override
public void openService() {
System.out.println("打开键盘");
}
@Override
public void closeService() {
System.out.println("关闭键盘");
}
public void input(){
System.out.println("键盘输入");
}
}
另外,我们可以再定义computer类,用来实现使用USB设备的功能。
package demo2;
public class Computer {
public void Open(){
System.out.println("打开笔记本");
}
public void Close(){
System.out.println("关闭笔记本");
}
public void Use(USB usb){
usb.openService();
if(usb instanceof Mouse){
Mouse mouse = (Mouse) usb;
mouse.click();
}
else if(usb instanceof Keyboard){
Keyboard keyboard = (Keyboard) usb;
keyboard.input();
}
usb.closeService();
}
}
值得注意的是,在Use方法中,我们接受USB类型的参数,其可能为Mouse也可能为Keyboard,所以我们要进行判断,从而实现其正确的功能。
3. 实现多个接口
我们知道,在Java中是不支持多继承的。但是一个类可以实现多个接口。
我们可以通过Animal类来进行举例。
package demo3;
public abstract class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public abstract void eat();
}
在Animal类中,我们将其定义为抽象类,定义了抽象方法eat。
因此我们在其子类Dog类和Duck类中,必须重写eat方法。
Dog会跑步,可以定义一个接口来进行实现。但是鸭子不仅会跑,还会飞甚至会游,所以这就体现出多接口的作用。
因此,我们可以定义多个接口来实现鸭子的功能。
Duck:
package demo3;
public class Duck extends Animal implements IFlyable,IRunable,ISwimable{
public Duck(String name) {
super(name);
}
@Override
public void eat() {
System.out.println(this.name+"正在吃鸭粮");
}
@Override
public void fly() {
System.out.println(this.name+"正在飞");
}
@Override
public void run() {
System.out.println(this.name+"正在跑");
}
@Override
public void swim() {
System.out.println(this.name+"正在游");
}
}
IFlyable:
package demo3;
public interface IFlyable {
void fly();
}
IRunable:
package demo3;
public interface IRunable {
void run();
}
ISwimable:
package demo3;
public interface ISwimable {
void swim();
}
除此之外,我们在测试类中,也可以通过这些接口来调用方法。(此处的Dog类省略)
package demo3;
public class Test2 {
public static void CanRun(IRunable runable){
runable.run();
}
public static void main(String[] args) {
Dog dog=new Dog("旺财");
Duck duck=new Duck("唐老鸭");
CanRun(dog);
CanRun(duck);
}
}
4.Comparable和Comparator接口
假如,我们拥有一个Student类,其中定义了name和age的属性,实例化时需要通过构造方法进行传参。
如果我们实例化了若干个对象,现在想通过age进行排序,该怎么进行?
所以,我们可以通过Comparable接口来进行功能的实现。
package demo4;
import java.util.Comparator;
public class Student implements Comparable<Student> {
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Student o) {
return this.age-o.age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
首先,当我们连接上接口后,要通过<>将所要进行排序的类输入。
其次,在其中重写campareTo方法。
最后,按升序和降序的要求调整this与o的位置。
通过测试类Test1,我们可以进行排序。
package demo4;
import java.util.Arrays;
public class Test1 {
public static void main(String[] args) {
Student student1=new Student("Alpha",20);
Student student2=new Student("Bob",18);
Student student3=new Student("Jack",22);
Student[] students = new Student[3];
students[0] = student1;
students[1] = student2;
students[2] = student3;
System.out.println(Arrays.toString(students));
Arrays.sort(students);
System.out.println(Arrays.toString(students));
}
}
但是,如果我们想通过名字进行排序,该怎么办呢?
这时我们就应该通过Comparator接口进行实现。
package demo4;
import java.util.Comparator;
public class NameCompare implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
通过在重写方法compare中传入两个需要比较的Student,通过compareTo进行比较,就可以实现排序。
但要注意其中的返回值是int类型,所以要通过在测试类Test2中与0的大小关系进行比较。
package demo4;
public class Test2 {
public static void main(String[] args) {
Student student1=new Student("Alpha",20);
Student student2=new Student("Bob",18);
NameCompare nameCompare=new NameCompare();
int ret1 = nameCompare.compare(student1,student2);
System.out.println("根据姓名比较:");
if(ret1>0){
System.out.println("student1>student2");
}
else if(ret1 == 0){
System.out.println("student1=student2");
}
else{
System.out.println("student1<student2");
}
AgeCompare ageCompare=new AgeCompare();
int ret2 = ageCompare.compare(student1,student2);
System.out.println("根据年龄比较:");
if(ret2>0){
System.out.println("student1>student2");
}
else if(ret2 == 0){
System.out.println("student1=student2");
}
else{
System.out.println("student1<student2");
}
}
}