一、抽象类
抽象类,说白了就是对类的抽象,那我们知道类也是对一类事物的抽象,那如何理解抽象类呢,我觉得应该从一些例子来说明抽象类是干啥的。
我们首先要知道抽象类的定义格式: public abstract class 类名
那么我们在抽象类里面写什么呢?
在抽象类里我们可以定义一些方法,我们定义的方法默认都为抽象的方法public abstract,这里大家要记住的一点就是,抽象方法一定在抽象类中存在,但是抽象类里不一定非得是抽象方法。也可以定义一些普通的方法。那么当我们定义一个抽象方法之后,我们在这个抽象方法里无法写入东西,即无法对这个抽象的方法进行实现。如下图,程序会直接暴红,提示我们抽象方法不能有方法体:
既然我们定义了一个抽象方法之后,程序也不让写具体的实现,那我们定义这个抽象方法有什么用呢,这里就暗示我们,抽象类肯定是被其他的类继承,然后在继承它的类中对这个抽象的方法进行详细实现。我们来试一下,在抽象类Person类中定义一个抽象方法,然后让学生类Student继承它。代码如下:
我们在Student类中对Person类中的抽象方法进行重写,然后进行具体的实现。这里我们要记住的是,抽象类中的抽象方法一定在继承它的类中一定要全部进行重写。以上程序可以正常运行,在抽象类中我们也可以写一些普通的方法,普通方法可以进行具体的实现,而不需要在其他类中进行具体的实现。这样子减少了代码的重复性。比如我们给Person类写一个普通方法eat(),代码如下:
抽象类中的普通发方法,不用在它的子类中进行重写,当然,如果想重写,还是可以的。
所以,我们定义一个抽象类有什么用呢,在我看来(如果有比我理解更好的,欢迎留言):当我们定义一个抽象类之后,我们可以将其他那些类公有的行为和属性在这里面进行实现,就比如以上例子,定义一个Student类和Teacher类,他们的类公有的方法就是他们都会吃饭,那么我就可以把吃饭这个方法在Person类中进行实现。但是对于sleep这个方法,可能只有学生会午休,但是老师不一定会午休,也就是他们对于sleep这个方法所表现出来的形式不一样,那么我们就可以在抽象类中定义这个抽象方法,不用说明这个方法要做什么,这个方法具体要做什么,可以让继承它的类中来实现。
二、接口
接口是对抽象的抽象,我相信听了这句话,就像是听了这句话,没有什么理解,完全不知道什么意思。在接口中,我们定义的方法,都是只有方法,而没有具体的实现,大家应该有点那个感觉了吧。我们再进一步来说,我们前面的例子是Person中定义了一个sleep抽象方法,虽然没有进行具体的实现,但我们知道这个方法肯定是与人有关。那我们此时在接口中定义一个抽象方法为sleep(睡觉),在这里的sleep,我们就不知道是不是与人有关了,它说不定还是与动物有关呢。因为动物也会睡觉啊。说到这里,大家应该有一个差不多的理解了,接口中只声明抽象方法,并且声明的方法必须是抽象的,一般是对某一个行为的抽象,具体谁会用这个方法,访问这个接口就可以了。
接口的声明格式如下,当我们在里面定义方法时,不用写public 和 abstract,它提示我们这两个修饰是多余的,因为接口中的方法默认都是抽象的公有方法,如下图:
在接口中我们还可以声明一个变量(变量在这里都是常量),前面用public static final修饰,这些都是默认的,在声明的时候,不用写,都是多余的,如下图所示:
当我们声明一个接口之后,如果想要在其他类中使用这个接口,我们可以通过implement关键字,来访问这个接口,这里我们要注意的是,一个类可以继承多个接口,这里就克服了java中类与类之间只能单继承的缺点,在接口这里可以实现多继承。
我们定义一个接口IF,定义一个抽象类Person,定义两个普通类Student,Animal,来写一个例子,先看实现效果:
具体代码如下:
public class Main {
public static void main(String[] args) {
Person person=new Student();//实例化类Student的一个对象person,作为Person类的引用。
IF f=new Animal();//实例化类Animal的一个对象f,作为接口IF类的引用。
f.run();
IF f1=(IF) person;//实例化类Student的一个对象person,作为Person类的引用,然后强制转换为IF接口的引用
f1.run();
}
}
//声明一个接口
public interface IF {
public abstract void run();//这里写不写public abstract都行
}
//定义一个抽象类
public abstract class Person {
public abstract void sleep();//定义的抽象方法
void eat(){
System.out.println("人们大多数都是一日三餐");
}
}
//定义一个普通的类
public class Student extends Person implements IF{
//这个是对继承的Person抽象类中的方法进行重写,然后进行具体的实现。
@Override
public void sleep() {
System.out.println("学生们都会有午休");
}
//当我们继承一个接口时,我们需要对这个接口中的所有抽象方法都进行重写。
//重写接口中的方法run
@Override
public void run() {
System.out.println("学生们跑的很快");
}
}
//定义一个普通类Animal
public class Animal implements IF {
//因为该类继承了接口IF,所以要重写IF中的全部抽象的方法
@Override
public void run() {
System.out.println("有些动物跑的比人快");
}
}
总结:抽象和接口这两个东西,我们只有运用到具体的实践中才能更好的去体会,我们只要记着定义他们时候的规则,以及它们各有什么特点即可。