Java中接口和抽象类及其区别



一、接口


1.1 什么是接口

Java程序设计语言中,接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。

任何实现接口Comparable的类都需要包含compareTo方法,并且这个方法的参数必须是一个Object对象,返回一个整型数值。

接口中的所有方法自动地属于pubilc。因此,在接口中声明方法时,不必提供关键字public

当然,接口中还有一个没有明确说明的附加要求:在调用x.compareTo(y)的时候,这个compareTo方法必须确实比较两个对象的内容,并返回比较的结果。当x小于y时,返回一个负数;当x等于y时,返回0;否则返回一个正数。

       接口只有一个方法,而有些接口可能包含多个方法。在接口中还可以定义常量。然而,更为重要的是要知道接口不能提供哪些功能。接口绝不能含有实例域,也不能在接口中实现方法。提供实例域和方法实现的任务应该由实现接口的那个类来完成。因此,可以将接口看成是没有实例域的抽象类。但是这两个概念还是有一定区别的。

现在假设希望使用Arrays类的sort方法对User对象数组进行排序。User类就必须实现接口。

为了让一个类实现一个接口,通常需要下面两个步骤:

  1. 将类声明为实现给定的接口,使用implements关键字。

  2. 对接口中的所有方法进行定义。

当然,这里的User类需要提供给compareTo方法。假设希望根据用户的userId进行比较。以下是compareTo方法的实现:

	public int compareTo(User o) {
		return userId-o.userId;
	}
//或是使用Integer的静态方法compare方法实现:
	public int compareTo(User o) {
		return Integer.compare(this.userId, o.userId);
	}

如果第一个参数小于第二个参数,它会返回一个负值;如果相等返回0;否则返回一个正数。

警告:在接口声明中,没有将compareTo方法声明为public,这是因为在接口中的所有方法都自动地是public。不过,在实现接口时,必须把方法声明为public;否则,编译器将认为这个方法的访问属性是包可见性,即类的默认访问属性,之后编译器就会给出试图提供更弱的访问权限的警告信息。

1.2 接口中可以使用的权限修饰符

为什么在接口中方法自动的是public?这个和Java中接口的作用以及访问权限有关。接口的作用是提供一种格式的规范,在任何一个包中的任何类都可能去实现这个接口,如果将接口中的方法声明为protected,那么有些类对这个方法是没有访问权限的,接口也就失去了它本来的功能,所以,接口中的方法都是public访问权限的在接口中无论是方法还是常量都必须使用public修饰或是不写权限修饰符(自动为public),如果使用低权限的修饰符,则会提示错误。

接口的声明中修饰符只允许使用“公用”和“抽象”。

       定义一个测试接口:

interface InterfaceTest {
	void run();
	int SPEED = 60;
}

在这个接口中,声明没有使用权限修饰符,在方法的声明中也没有使用。使用反射打印一下默认的修饰符:

Class c = InterfaceTest1.class;
System.out.println(Modifier.toString(c.getModifiers()));
System.out.println(Modifier.toString(c.getMethod("run").getModifiers()));
System.out.println(Modifier.toString(c.getField("SPEED").getModifiers()));

打印出的语句为:

abstractinterface

publicabstract

publicstatic final

可以发现,接口的访问权限可以是publicdefault,接口中的方法和常量只能是public,即使不写修饰符,也会自动的为public反编译后也能看到在方法的前面也加上了public修饰符。

附:四种访问权限:


 NO.

范围

private

default

protected

Public

1

在同一包的同一类

2

同一包的不同类

×

3

不同包的子类

×

×

4

不同包的非子类

×

×

×

现在,已经看到,要让一个类使用排序服务必须让它实现compareTo方法。这是利索当然的,因为要向sort方法提供对象的比较方式。但是为什么不能在User类直接提供一个compareTo方法,而必须实现接口呢?

主要原因在于Java程序设计语言是一种强类型(strongly typed)语言。在调用方法的时候,编译器将会检查这个方法是否存在。在sort方法中有这样的语句:

(() dest[j-1]).compareTo(dest[j])>0; j--)

为此,编译器必须确认dest[j-1]一定有compareTo方法。如果a是一个对象的数组,就可以确保拥有compareTo方法,因为每个实现接口的类都必须提供这个方法的实现。

1.3 接口的特性

接口反编译后接口的声明中也会有abstract修饰符,接口不是类,尤其不能使用new运算符实例化一个接口。然而,尽管不能构造接口的对象,却能声明接口的变量。接口变量必须引用实现了接口的类对象。

Comparable c = user1;

接下来,如同使用instanceof检查一个对象是否属于某个特定类一样,也可以使用instanceof检查一个对象是否实现了某个特定的接口。

System.out.println(user1 instanceof Comparable);//true

与可以建立类的继承关系一样,接口也可以被扩展。这里允许存在多条从具有较高通用性的接口到专用性的接口的链。

   尽管每个类只能够拥有一个超类,但却可以实现多个接口。这就为定义类的行为提供了极大的灵活性。要实现多个接口需要将接口用逗号分隔。

要想创建一个接口需要使用interface关键字替代Class关键字。接口可以继承接口,使用的关键字是extends,且只能继承接口,可以继承多个接口。

二、抽象类

A class containing abstract methods is called an abstract class. Ifa class contains one or more abstract methods, the class itself must bequalified as abstract. (Otherwise, the compiler gives you an errormessage.)——————————————thinking in java

2.1 什么是抽象类

    包含抽象方法的类叫做抽象类,至于包含几个无所谓,甚至不包含任何抽象方法也是可以的,但是抽象类有个关键的标志:必须在类的声明中使用abstract关键字修饰这个类。

抽象类的定义可以表示成:使用abstract修饰的类叫做抽象类。

其实,如果一个类中包含了抽象方法,那么这个类就一定是抽象类,因为在普通的类中,方法是不允许使用abstract修饰的。包含抽象方法的类与使用abstract修饰的类其实是划等号的。

2.2 抽象类的作用

创建抽象类的目的是被继承,只有被继承抽象类才有存在的意义。既然需要被继承,抽象方法需要被子类实现,那么访问权限必须是对外可见的,这也就说明了在抽象类和抽象方法的声明中为什么会对访问权限进行了限制。

其实抽象类完全可以被普通的类替代,但是这么单纯的替换会出现一些问题。抽象类其实是一些类的超类,在这个超类中定义了一些子类公有的域和方法。对于这些域和方法使用普通的类进行替代是没有问题的,但是,抽象方法也用普通类中的方法进行替代就会出现这样的问题,每个子类都会有超类的公有行为,而且所有的子类从超类继承的行为的表现是相同的。实际中可能希望每个子类都有这个行为,但是每个子类的这个行为的表现都不相同。这时,超类中对行为的实现就失去了意义。可以这么解决:每个子类都重写这个行为,但是,这么做会浪费了超类中该行为的实现,而且子类并不知道该行为需要重写。抽象类中的抽象方法就提供了这个问题的完美实现。抽象方法不需要方法体,只要声明好就可以了,子类继承了这个超类就必须实现超类中的抽象方法,给出不同子类中的不同实现,就达到了同一行为不同表现的目的。

2.3 抽象类和普通类的区别

抽象类的声明中必须使用abstract修饰符,普通类不需要使用。这个也是区分普通类和抽象类的标志。

抽象类的声明中修饰符只允许使用公用抽象和默认(也就是不使用权限修饰符)

抽象方法的声明中只能设置可视性修饰符公用受保护中的一个。

而在普通类中不能使用abstract

普通类一般情况下是可以使用new运算符生成实例的,但是不能生成抽象类的实例,如果使用new生成抽象类的实例,编辑器就会提示错误,即使是使用反射,在运行时程序也会报错。

抽象类可以实现一个或多个接口可以继承一个普通类或抽象类。在抽象类中可以选择实现接口中的方法也可以不进行实现。或是重写超类中的方法。但是在重写方法时有个规定:重写方法的时候不能使用比父类中该方法的访问权限更低的权限修饰符。但是普通类需要实现接口中的全部方法以及父类中的所有抽象方法。

2.4 抽象类与接口的区别

抽象类中与接口一样含有抽象方法,在上面的反编译中可以看到即使接口中的方法和常量没有使用abstract修饰,反编译的内容中还是有abstract修饰符的。也就是说接口是更加纯粹的抽象类,在接口中没有任何已经实现的方法,也不具有任何未初始化的域。接口的声明中修饰符可以使用abstract。一个类可以实现多个接口但是只能继承一个抽象类。


你可能感兴趣的:(Java中接口和抽象类及其区别)