您的位置 首页 golang

JAVA脱水学习-java接口、继承与多态,抽象类与接口的区别

Java 是个纯粹的面向对象语言,没有过程式的写法,所有操作都是基于对象。面向对象的设计可以更好的解决系统维护、扩展、和代码重用的需求,代码过多后过程式的逻辑组织会变得异常复杂,所以就发展出了面向对象式编程。而面向对象的基本特性就是封装、继承、与 多态

一、继承

extends 关键字表示继承某个已存在的类,已存在的类称为“超类”、“基类”、或“父类”,而新继承的类称为“子类”、“派生类”。子类可以方法父类中的所有非 private 域,也即子类通过继承获得了父类具有的特性和能力。

定义一个 Person 父类:

public class Person
{
 private String name;
 private int age;

 public Person(String name, int age)
 {
 this.name = name;
 this.age = age;
 }

 public String getName()
 {
 return name;
 }

 public int getAge()
 {
 return age;
 }
}
 

定义一个 Student 子类:

public class Student extends Person
{
 private String school;

 //  构造函数 
 public Student(String name, int age, String school)
 {
 super(name, age); // 调用父类构造函数
 this.school = school;
 }

 public String getSchool()
 {
 return school;
 }
}
 

写个 Main 类测试下:

public class Main
{
 public static void main(String[] args)
 {
 Student s = new Student("小明", 12, "xx小学");
  System .out.println(s.getName()); // 输出:小明
 System.out.println(s.getAge()); // 输出:12
 System.out.println(s.getSchool()); // 输出:xx小学
 }
}
 

从输出可以看出,子类 Student 并没有 getName、getAge 方法,但通过继承获得了父类的能力。在上一章我们知道 this、super 两个关键字,this 访问自身,super 访问父类,这里调用父类的构造函数使用 super。

继承可以获得父类的能力,但有时候获得的能力并不太理想,这时可以在子类中重写父类的方法,使其符合子类的需求。同样 Student 类:

public class Student extends Person
{
 private String school;

 // 构造函数
 public Student(String name, int age, String school)
 {
 super(name, age); // 调用父类构造函数
 this.school = school;
 }

 public String getSchool()
 {
 return school;
 }

 // 重写 getName 方法
 public String getName()
 {
 return "我是一名学生,我叫" + super.getName();
 }
}
 

通过重写父类中的方法,使子类具有不同的能力。

二、继承层级

上面的例子只讲了一层继承关系,当然也可以进行多次继承。A 继承 B,B 继承 C,C 继承 D 理论上可以一直继续,但是肯定不建议嵌套太多继承关系,这会让程序变得复杂且性能降低。

Java 可以有多个继承层次,一个类也可以有多条继承链路,M 继承 A,N 继承 A。但是 Java 不支持多继承,即 M 同时继承 A 又 继承 B,Java 不允许多继承降低了复杂度,如果要实现多继承,可以通过接口 interface 形式实现。 所以 Java 类之间只有单一继承关系,没有多继承。 问什么这样设计,要问语言设计者。

三、多态

我们通过类实现了封装,又通过继承获得了父类的功能,减少了重复代码,最后我们通过扩展子类,或者重写子类中的方法实现了多态。就好比一个母亲生了多个孩子,每个孩子性格差异各不相同。

子类生成的对象都属于父类类型。如:

public class Main
{
 public static void main(String[] args)
 {
 Student s = new Student("小明", 12, "xx小学");
 Person s2 = s; // 将 s 赋值给 s2
 System.out.println(s2.getName()); // 输出:我是一名学生,我叫小明
 System.out.println(s2.getAge()); // 输出:12
// System.out.println(s2.getSchool()); // s2 没有 getSchool 方法
 }
}
 

注意看,所有子类实例都可以赋值给父类变量,但仅能调用父类定义的方法。因为 JVM 会把 s2 当作 Person 类实例看待,父类中不存在的则不能访问,又因为 s 和 s2 实际指向的是同一对象,所以调用 getName 方法还是子类的方法。

子类实例引用可以赋值给父类变量,但父类引用不能赋值给子类变量。因为这是一个包含关系,父类包含子类(人 Person 包含学生 Student),反之则不成立。

如何判断一个对象是某个类生成的,或通过某个类构造的,可以用 instanceof 语句。instanceof 可以判断某个对象是通过那个类(或其父类)构造的,如:

public class Main
{
 public static void main(String[] args)
 {
 Student s = new Student("小明", 12, "xx小学");
 System.out.println(s instanceof Student); // true
 System.out.println(s instanceof Person); // true
 }
}
 

四、接口

接口不是类,它是对类的一组需求描述和行为规范 。为什么是需求描述,因为接口只是定义行为方法,并不实现方法,而继承它的类规定必须实现接口定义的方法。类通过实现接口定义的方法而受接口的约束,所以说接口是类的需求描述和行为规范。接口和类是两种不同的数据类型。

接口使用 interface 关键字定义,格式如下:

public interface InterfaceName
{
 public type funcName(type args, ...); // type 是数据类型
}
 

继承类使用 extends,而继承接口使用 implements。

定义一个 Calculate 接口:

public interface Calculate
{
 // 定义一个加法运算
 public int add(int i, int j);
}
 

声明一个类 Calculator 继承 Calculate:

public class Calculator implements Calculate
{
 // 实现 add 方法
 public int add(int i, int j)
 {
 return i+j;
 }
}
 

从上文可知 Java 中类不能实现多继承,但是这里类可以通过接口实现多继承,多个接口之间用 ‘,’ 分割,继承的类必须实现所有继承接口中定义的方法。如:

public class Calculator implements Calculate1,Calculate2,Calculate3
{
 ... // 实现 Calculate1,Calculate2,Calculate3 中定义的所有方法
}
 

五、接口与 抽象类

上一章中我们还知道类可以被定义成抽象的,抽象类中可以定义属性和方法,也可以定义抽象方法。

那么什么时候使用抽象类,什么时候使用接口呢?为了准确使用我们需要需要了解下抽象类和接口的区别。

抽象类: 将一组共同的行为组合在一起,作为一个抽象类。在抽象类中可以定义抽象方法,也可以实现方法。抽象类属于类不能多继承,可以用 instanceof 判断从属关系。

接口: 对类的一组需求描述和行为规范。接口不能实现具体方法,但可以实现多继承。

那什么时候使用抽象类,什么时候使用接口呢?

1.如果抽象出来的一组行为,和子类具有从属关系(is-a),那么就使用抽象类。如果没有从属关系,只是希望具备某个能力,那么使用接口。

2.如果需求变更会导致父类的功能扩展,那么使用抽象类修改的代码会少些,而使用接口所有子类都需要调整。

如何使用抽象类或者接口,有时需要反复的代码练习。

文章来源:智云一二三科技

文章标题:JAVA脱水学习-java接口、继承与多态,抽象类与接口的区别

文章地址:https://www.zhihuclub.com/87241.shtml

关于作者: 智云科技

热门文章

网站地图