Java入门——类抽象类和接口

Posted 瓜牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java入门——类抽象类和接口相关的知识,希望对你有一定的参考价值。

Java是一门面向对象语言,可以看出“对象”在Java有着举足轻重的位置。那么,“对象”从何而来呢?那必须是丈母娘造出来的,下面我们就先来说说这个丈母娘——类。

Java类

  • 对象: 对象具有状态和行为。 例如:一只狗的状态有:颜色,名称,品种,它的行为有:摇尾巴,吠叫,吃东西。 对象是类的实例
  • 类: 类是一个模板,它描述一类具有相同状态和行为的对象。比如人类,都具有思考这个行为,而植物没有。

类可以看成是创建Java对象的模板,下面简单定义一个类:

public class People{
  String name;  // 成员变量
  int age;
  String weight;
  static final double weeks = 9.5;  // 类变量
  void eat(){
  }
 
  void sleep(){
  }
 
  void play(){
  }
  
  Public People {
    // 这是一个构造方法
    int count = 0; // 局部变量
  }
}

一个类可以包含以下类型变量:

  • 局部变量: 在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁
  • 成员变量:成员变量定义在类中,方法体之外的变量。 这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问
  • 类变量:类变量也声明在类中,方法体之外,但必须声明为static类型
  • 类方法:概念同上面的类变量

构造方法

每个类都有构造方法。如果没有显示地为类定义构造方法,Java编译器将会为该类提供一个默认构造方法。

在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法

public class Puppy{
    public Puppy(){
    }
 
    public Puppy(String name){
        // 这个构造器仅有一个参数:name
    }
}

实例化对象

对象时根据类创建的。在Java中,使用关键字new来创建一个新的对象。创建对象需要以下三步:

  1. 声明:声明一个对象,包括对象名称和对象类型
  2. 实例化:使用关键字new来创建一个对象
  3. 初始化:使用new创建对象时,会调用构造方法初始化对象

下面是一个创建对象的例子:

public class Puppy{
   public Puppy(String name){
      //这个构造器仅有一个参数:name
      System.out.println("小狗的名字是 : " + name ); 
   }
   
   public static void main(String[] args){
      // 下面的语句将创建一个Puppy对象
      Puppy myPuppy = new Puppy( "tommy" );
   }
}

编译并运行上面的程序,会打印出下面的结果:

小狗的名字是:tommy

下面的例子展示如何访问实例变量和调用成员方法:

public class Puppy{
   int puppyAge;
   public Puppy(String name){
      // 这个构造器仅有一个参数:name
      System.out.println("小狗的名字是 : " + name ); 
   }
 
   public void setAge( int age ){
       puppyAge = age;  // 当形参`age`也是puppyAge时,需要用this:this.puppyAge = puppyAge
   }
 
   public int getAge( ){
       System.out.println("小狗的年龄为 : " + puppyAge ); 
       return puppyAge;
   }
 
   public static void main(String[] args){
      /* 创建对象 */
      Puppy myPuppy = new Puppy( "tommy" );
      /* 通过方法来设定age */
      myPuppy.setAge( 2 );
      /* 调用另一个方法获取age */
      myPuppy.getAge( );
      /*你也可以像下面这样访问成员变量 */
      System.out.println("变量值 : " + myPuppy.puppyAge ); 
   }
}

编译并运行上面的程序,产生如下的结果:

小狗的名字是 : tommy
小狗的年龄为 : 2
变量值 : 2

Java继承

Java的继承是一种机制,表示为一个对象获取父对象的所有属性和行为

继承是类与类之间的关系,是一个很简单很直观的概念,与现实世界中的继承(例如儿子继承父亲财产)类似。

Java中的继承,可以创建基于现有类构建新的类。 当你从现有类继承时,就可以重复使用父类的方法和字段,也可以在继承的新类中添加新的方法和字段。

为什么在Java中使用继承

对于方法覆盖(因此可以实现运行时的多态性),提高代码可重用性。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写(覆盖)。

Java类继承的语法示例:

class Super {
}
 
class Sub extends Super {
}

extends关键字表示从现有类派生创建的新类。extends的含义是增加功能。在Java的术语中,被继承的类称为父类或超类,新类称为子类。

Java继承示例

技术图片

如上图所示,Programmer是子类,Employee是超类。 两个类之间的关系是Programmer IS-A Employee. 它表示 Programmer 是一种 Employee 的类型。

参考下面示例代码实现:

class Employee {
    float salary = 40000;
}

class Programmer extends Employee {
    int bonus = 10000;

    public static void main(String args[]) {
        Programmer p = new Programmer();
        System.out.println("Programmer salary is:" + p.salary);
        System.out.println("Bonus of Programmer is:" + p.bonus);
    }
}

执行上面代码得到以下结果:

Programmer salary is:40000.0 
Bonus of programmer is:10000

在上面的例子中,Programmer对象可以访问自身类以及Employee类的字段,即提高了代码可重用性。

默认的: 不使用任何修饰符声明的属性和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为public static final,而接口里的方法默认情况下访问权限为public

Java继承类型

在类的基础上,在Java中可以有三种类型的继承:单一,多级和分层继承。在Java的编程中,仅能通过接口支持多继承和混合继承。

技术图片

注意:Java中的类不支持多继承

当一个类扩展多个类,即被称为多继承。例如:

技术图片

问题:为什么在Java中不支持多继承?

为了降低复杂性并简化语言,Java中不支持多重继承。想象一个:ABC是三个类。 C类继承AB类。 如果AB类有相同的方法,并且从子类对象调用它,AB类的调用方法会有歧义。

因为编译时错误比运行时错误好,如果继承2个类,Java会在编译时报告错误。 所以无论子类中是否有相同的方法,都会有报告编译时错误。

注意:构造方法不能被继承,掌握这一点很重要。 一个类能得到构造方法,只有两个办法:编写构造方法,或者根本没有构造方法,类有一个默认的构造方法。

抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类

在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。

由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。

抽象类

在Java中使用abstract关键字来定义抽象类。如下示例:

//example of abstract class that have method body  
abstract class Bike {
    Bike() {
        System.out.println("bike is created");
    }

    abstract void run();

    void changeGear() {
        System.out.println("gear changed");
    }
}

class Honda extends Bike {
    void run() {
        System.out.println("running safely..");
    }
}

class TestAbstraction2 {
    public static void main(String args[]) {
        Bike obj = new Honda();
        obj.run();
        obj.changeGear();
    }
}

注意到该Bike类没有什么不同,尽管该类是抽象类,但是它仍然有成员变量,抽象方法,方法体,构造函数甚至main()方法。

执行上面的代码:

bike is created
running safely..
gear changed

抽象方法

如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。

Abstract 关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体

抽象方法没有实现,方法名后面直接跟一个分号,而不是花括号。

public abstract class Employee
{
   private String name;
   private String address;
   private int number;
   
   public abstract double computePay();
   
   //其余代码
}

声明抽象方法会造成以下两个结果:

  • 如果一个类包含抽象方法,那么该类必须是抽象类
  • 任何子类必须重写父类的抽象方法,或者声明自身为抽象类

继承抽象方法的子类必须重写该方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象。

如果Salary类继承了Employee类,那么它必须实现computePay()方法:

/* 文件名 : Salary.java */
public class Salary extends Employee
{
   private double salary; // Annual salary
  
   public double computePay()
   {
      System.out.println("Computing salary pay for " + getName());
      return salary/52;
   }
 
   //其余代码
}

注意: 抽象类中不能有抽象构造方法或抽象静态方法

参考:Java抽象类

抽象类和类的区别

抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。

  • 抽象类不能被实例化,如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以被实例化

  • 普通类和抽象类都可以被继承,但是抽象类被继承后子类必须重写继承的方法,除非自类也是抽象类

  • 抽象类中不一定含有抽象方法,但是有抽象方法的类必定时抽象类

  • 抽象类中的抽象方法只是声明,不包含方法体,即不能给出方法的具体实现

  • 构造方法、类方法(用static修饰的方法)不能声明为抽象方法

总之一句话,抽象类只是一种比较特殊的普通类。我觉得这篇文章解释的不错,大概意思就是:抽象类严格规定了几个你必须做的事情,比如:不能实例化、子类必须实现父类,除非子类也是抽象类。你不这样做就会出错,这种严谨的做法比人为规定的更加有效。

接口

定义:接口在Java中是一个抽象类型,是抽象方法的集合。一个类通过继承接口的方式,从而继承接口的抽象方法。

接口通常以interface来声明,可以看做是一种特殊的抽象类。一个类通过继承接口的方式,从而来继承接口的抽象方法。

接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。

接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。

接口的声明

接口的声明语法格式如下:

public interface 接口名称 [extends 其他的接口名] {
        // 声明变量
        // 抽象方法
}

接口有以下几个特征:

  • 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)
  • 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)
  • 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法

注:JDK 1.8 以后,接口里可以有静态方法和方法体

接口的实现

当类实现接口的时候,类要实现接口中的所有的方法。否则,类必须声明为抽象类

类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。

实现一个接口的语法,可以使用这个公式:

...implements 接口名称[, 其他接口名称, 其他接口名称..., ...] ...

下面是一个Java的接口示例:

interface printable {
    void print();
}

class A6 implements printable {
    public void print() {
        System.out.println("Hello, Interface");
    }

    public static void main(String args[]) {
        A6 obj = new A6();
        obj.print();
    }
}

执行上面的代码,结果如下:

Hello,Interface

接口与类的相似点

  • 一个接口可以有很多方法
  • 接口文件保存在.java结尾的文件中,文件名使用接口名
  • 接口的字节码文件保存在.class结尾的文件中
  • 接口相应的字节码文件必须在与包名称相匹配的目录结构中

接口与类的区别

  • 接口不能用于实例化对象
  • 接口没有构造方法
  • 接口中所有方法必须为抽象方法
  • 接口不能包含成员变量,除了staticfinal变量
  • 接口不是被类继承了,而是要被类实现
  • 接口支持多继承

接口和抽象类的区别

  • 抽象类中的方法可以不是抽象方法,但接口中的方法必须都是抽象方法
  • 抽象类中的非抽象方法可以有方法体,就是实现方法的具体功能,避免在子类中重复实现这些方法。但接口中的方法不行(JDK 1.8以后可以有方法体,作为默认实现)
  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的
  • 抽象类可以有具体的方法和属性, 接口只能有抽象方法和不可变常量(final)
  • 一个类只能继承一个抽象类,而一个类却可以实现多个接口
  • 抽象类里面的抽象方法必须全部被子类实现,如果子类不实现,那么子类必须也是抽象类。接口里面的方法也必须全部被子类实现,如果子类不能实现,那么子类必须是抽象类
  • 抽象类主要用来抽象类别,接口主要用来抽象方法功能。当你关注事物的本质的时候,请用抽象类;当你关注一种操作的时候,用接口
  • 抽离类可以继承接口,接口不能继承抽象类(有待考究)

参考:

抽象类和接口的区别

接口和抽象类有什么区别?

以上是关于Java入门——类抽象类和接口的主要内容,如果未能解决你的问题,请参考以下文章

Java抽象类和接口

Java学习笔记—抽象类和接口

java 抽象类和接口的差别

Java基础:抽象类和接口

Java抽象类和接口

Java抽象类和接口4000+字深度剖析