Java语言之抽象类与接口
一、抽象类
1、抽象类的概念
我们之前应该也做过类似猫与狗都属于动物类似的练习吧,其实我们都知道,猫和狗都是动物,他们都具有动物所具有的共同的属性和功能,所以便会提取出一个动物类。并且我们也创建过了动物对象,其实呢,这是不对的。
如果我说动物,你根本不知道知道我说的是什么动物,只有看到了具体的动物,你才知道这是什么动物。所以说,动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫狗才是具体的动物。同理,我们也可以推想,不同的动物吃的东西应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。
抽象类就是被abstract所修饰的类,父类将所有子类的共性功能向上抽取后,他并不给予每个子类对这个共性功能的具体实现,所以没有必要在父类中,给出共性功能的具体实现,而是给出声明即可,所谓给出功能的声明,就是将此功能抽象出来,然后强制子类必须重写抽象类的功能。也就是说,在Java中,一个没有方法体的方法就会将其定义为抽象方法,而类中如果有抽象方法,则该类必须定义为抽象类。
2、抽象类的代码格式
//抽象类和抽象方法必须用abstract关键字修饰
抽象类格式: abstract class 类名 {}
抽象方法格式: public abstract void eat();
一旦一个类中,有了抽象方法,那么此抽象类和抽象方法必须用abstract关键字修饰。抽象类不一定有抽象方法,有抽象方法的类一定是抽象类。也就是说,一个抽象类中可以没有抽象方法,但只要一个类中有抽象方法,则具有这个抽象方法的类一定是抽象类。抽象类中既可以有抽象方法,也可以有非抽象方法,抽象方法需强制子类进行重写,非抽象方法可以让子类继承下去使用。抽象类是不能直接进行实例化的,但我们可以采用多态的方式,进行间接实例化,即按照多态的方式,由具体的子类实例化。
抽象类中有构造方法,但抽象类不能进行实例化,此时构造方法便用于子类访问父类数据时的初始化。抽象类的子类要么重写父类中所有的抽象方法,要么自己也是一个抽象类。
二、抽象类的成员特点
1、抽象类的成员变量
抽象类的成员变量既可以是变量,也可以是常量,常量用public final修饰
2、抽象类的成员方法
抽象类的成员方法既可以是抽象的,也可以是非抽象的。抽象的成员方法用public abstract修饰,强制要求子类重写;非抽象的成员方法让子类直接继承,这样能提高代码复用性。
下面是一个抽象类引用指向子类对象的例子:
//创建抽象类
public abstract class Animal {
int a=100;
public final int b = 10;
public Animal() {
System.out.println("父类的构造方法执行了");
}
//抽象方法,此方法没有方法实现
public abstract void eat();
public abstract void sleep();
//抽象类中既可以有抽象方法,也可以非抽象方法
public void show(){
System.out.println("这是父类的一个非抽象方法");
}
}
//创建子类继承抽象类
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫爱吃鱼");
}
@Override
public void sleep() {
System.out.println("猫白天睡觉");
}
}
//创建测试类进行测试
public class MyTest {
public static void main(String[] args) {
//抽象类不能直接创建对象,可以采用多态间接的去实例化抽象类
Animal an=new Cat();
System.out.println("抽象类的一个变量为:"+an.a);
System.out.println("抽象类的一个常量为"+an.b);
an.eat();
an.sleep();
an.show();
}
}
运行结果为:
三、接口
1、接口的概念
回到我们之前做过类似猫与狗都属于动物的练习,其实在当下,狗一般是用来看门的,而猫则一般作为宠物来养的。但是当下有很多的驯养员或者是驯兽师,可以训练出狗跳高、做计算,猫钻火圈等,而这些额外的动作,并不是所有猫或者狗一开始就具备的,这就属于经过特殊的培训训练出来的。所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫或狗才具备这些功能。为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗已经被培训而且会这些额外功能了,我们只需要把这些额外功能用于这部分猫或狗进行实现即可。也就是说,接口是用来定义一些扩展功能,哪些事物想要具备这个功能,我们就可以实现这个接口并对功能做出具体实现。
2、接口的代码格式
//接口用关键字interface表示
格式: interface 接口名 {}
//类实现接口用implements表示
格式: class 类名 implements 接口名 {}
接口不能实例化,但我们可以向抽象类一样,按照多态的方式来实例化。接口的子类可以是抽象类,但是我们接口的核心就是用来定义一些额外的功能让我们的子类进行功能的具体实现,如果接口的子类是抽象类的话,那就使得接口没有多大意义了。接口的子类最好是具体类,但是在具体类中要重写接口中所有的抽象方法。
四、接口中的成员特点
1、接口中的成员变量
接口中的成员变量全是静态的公共常量,注意只能是常量,并且成员变量前面有默认的修饰符:public static final,但建议自己手动写出来,便于代码的可读性。
2、接口中的成员方法
接口中的成员方法只能是抽象方法,即没有非抽象方法,全是抽象方法,并且成员方法前面也有默认修饰符:public abstract,也建议自己手动写出来,便于代码的可读性。
3、接口中的构造方法
接口中是没有构造方法的。
五、类与类、类与接口、接口与接口的关系
1、类与类之间的关系:
类与类之间的关系是继承关系,其特点是:类与类之间的继承只能单继承,不能多继承,但可以多层继承。
2、类与接口之间的关系
类与接口之间的关系是实现关系,其特点是:类与接口之间的实现可以是实现一个接口,也可以是实现多个接口,并且还可以在继承一个类的同时实现多个接口,但想要实现接口就必须重写接口中所有的抽象方法。
3、接口与接口之间的关系
接口与接口之间的关系是继承关系,其特点是:接口与接口之间的继承可以单继承,也可以多继承。
下面是我根据以上内容总体写的一段代码:
//创建抽象类作为父类
public abstract class Teacher {
String name;
public int age;
static {
System.out.println("传智播客是一个培训机构");
}
public void fenLei(){
System.out.println("传智播客分为基础班和就业班");
}
public abstract void teach(String name);
}
//创建一个子类并继承父类,接着连接一个接口
public class JiChu extends Teacher implements Speak {
@Override
public void teach2(String name) {
System.out.println(super.name+"老师还需要教"+name);
}
@Override
public void teach(String name ) {
System.out.println("基础班的老师教的是"+name);
}
public void people(){
System.out.println("基础班的人数较多");
}
}
//创建一个子类并继承父类,但不连接接口
public class JiuYe extends Teacher {
int num;
@Override
public void teach(String name) {
System.out.println("就业班老师教的是" + name);
}
public void teach2(String name) {
System.out.println(super.name+"老师还需要教"+name);
}
public int people2(int num){
return this.num=num;
}
}
//创建接口,用于实现某些额外的功能
public interface Speak {
public abstract void teach2(String name);
}
//创建测试类,用于实现以上类与接口的属性与功能
public class MyTest {
public static void main(String[] args) {
Teacher t1 = new JiChu();
t1.fenLei();
((JiChu) t1).people();
t1.teach("Java");
t1.name="刘杰";
t1.age=28;
System.out.println("基础班其中一个老师叫"+t1.name);
System.out.println(t1.name+"的年龄为:"+t1.age+"岁");
((JiChu) t1).teach2(" Japanese");
t1=new JiuYe();
t1.teach("Python");
int num=((JiuYe) t1).people2(56);
System.out.println("就业班的人数为"+num);
t1.name="李华";
t1.age=26;
System.out.println("就业班其中一个老师叫"+t1.name);
System.out.println(t1.name+"的年龄为:"+t1.age+"岁");
((JiuYe) t1).teach2(" Japanese");
}
}