15. 类的关系——实现(接口)

15. 类的关系——实现(接口)

1、接口

1.1 接口的引入

Java语言中,类与类的继承只能是单继承。 试想一下,如果一个类中的所有方法都是抽象方法,子类继承后,需要重写所有方法,但是因为单继承,就不能去继承其他有实际方法的父类了。 为了解决这个弊端,Java语言中把一种特殊的抽象类定义成一个新的概念,接口,即interface 接口的本质就是一个类,不过是一个纯的抽象类,就是没有变量,没有具体方法的抽象类。

1.2 接口的定义

​ Java接口是一系列方法的声明,是一些抽象的集合 一个接口只有抽象方法没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。 简单地说,接口就是特殊的抽象类,即所有方法都是抽象方法,抽象类就是Java中的接口(interface)。

1.3 接口的基本格式

 [修饰符] interface 接口名 [extends 父接口名列表]{

[public] [static] [final] 常量; 

 [public] [abstract] 方法; 

}

注意: **·**修饰符:可选,用于指定接口的访问权限,可选值为public。即使省略,也依然是public。 **·**接口名:必选参数,用于指定接口的名称,接口名必须是合法的Java标识符。一般情况下,要求首字母大写。 **·extends 父接口名列表:可选参数,用于指定要定义的接口继承于哪个父接口。当使用·**extends关键字时,父接口名为必选参数。父接口可以存在多个,用逗号隔开。 方法:接口中的方法只有定义而没有被实现。

例:

public interface Flyable extends Runnable , Comparable<Flyable>{

	//常量,没有变量属性	
	public static final double PI = 3.14;
	
	//public static final可以省略,默认会加上
	double LB = 30.0;
	
	//只能是抽象方法,也没有构造方法
	public abstract void fly();
	
	//public abstract可以省略,默认会加上
	void run();
	
	//可以有内部类
	class Inner{
		
	}
	
	static class StaticInner{
		
	}
	
}

1.4 接口的特点

**·**接口是一种特殊的抽象类 **·**接口中没有变量,只能有public static final修饰的静态常量。三个修饰符可以省略。 **·**接口中所有方法都是抽象方法,且默认就是public权限。

2、类实现接口

2.1 类实现接口的引入

​ 抽象类存在的意义是作为父类,也就是定义了子类的共同特征,抽象类中往往既有抽象方法,又有具体方法。 接口的作用和抽象类类似,也不能直接创建对象,都是被其他类实现,implements,本质和extends一样

2.2 类实现接口的特点

​ 类实现接口,本质上与类继承类相似,区别在于“类最多只能继承一个类,即单继承,而一个类却可以同时实现多个接口”,多个接口用逗号隔开即可。实现类需要覆盖所有接口中的所有抽象方法,否则该类也必须声明为抽象类。 接口是抽象的,接口中没有任何具体方法和变量,所以接口不能进行实例化。接口定义的是多个类都要实现的操作,即“what to do”。类可以实现接口,从而覆盖接口中的方法,实现“how to do”。

2.3 类实现接口的格式

[修饰符] class <类名> [extends 父类名] [implements 接口列表]{

}

修饰符:可选参数,用于指定类的访问权限,可选值为public、abstract和final。 类名:必选参数,用于指定类的名称,类名必须是合法的Java标识符。一般情况下,要求首字母大写。 extends 父类名:可选参数,用于指定要定义的类继承于哪个父类。当使用extends关键字时,父类名为必选参数。 implements 接口列表:可选参数,用于指定该类实现的是哪些接口。当使用implements关键字时,接口列表为必选参数。当接口列表中存在多个接口名时,各个接口名之间使用逗号分隔。

2.4 接口继承接口

有些时候,定义了一个接口后,需要对该接口进一步细化,再定义它的子接口。

也就是接口和接口之间也可以继承,使用extends实现。区别是,接口和接口之间继承是一对多继承。

2.5 Java接口继承接口的原则

**·**Java接口可以继承多个接口

**·**接口继承接口依然使用关键字extends,不要错用成implements

2.6 Java接口继承接口的形式

[修饰符] class <类名> [extends 父类名] [implements Interface0, Interface1, interface……]{

}

2.7 实现多重继承

由于Java类要求单继承,如果没有接口的概念,子类一旦继承那些“纯粹”的抽象类,将不能继承其他类。所以Java语言将“纯粹”的抽象类定义为一种新的类型,即“接口”。类可以同时继承类以及实现接口,也就是说extends和implements关键字可以同时使用。而且一个类可以同时实现多个接口,从而实现了对于“纯粹”的抽象类的多重继承,解决了类与类单继承的局限性。

3、接口继承与类继承

接口继承与类继承对比:Java类的继承是单一继承,Java接口的继承是多重继承。

·接口可实现多继承原因分析 不允许类多重继承的主要原因是,如果A同时继承B和C,而B和C同时有一个D方法,A无法确定该继承那一个。 接口全都是抽象方法继承谁都可以,所以接口可继承多个接口。

4、接口与抽象类区别

我们一直在强调,接口的本质就是一个纯的抽象类,但是具体细节有些区别。

img

区别总结 abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface. 在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是 static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。 实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。 接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。 接口中的方法默认都是 public,abstract 类型的。

5、接口的作用——面向接口编程

​ 面向接口编程 是一个非常重要的编程原则,意思是,尽量使用接口类型作为编译期类型,以便实现应用的可扩展性。 值得强调的是,抽象类,接口,都是设计层面的概念。在API中,大体结构都是最顶层是接口,然后是抽象类,最后是具体类。 接口是设计层面的概念,往往由设计师设计,将定义与实现分离。

​ 程序员实现接口,实现具体方法。

5.1 面向接口编程

面向接口编程和面向对象编程并不是平级的,它并不是比面向对象编程更先进的一种独立的编程思想,而是附属于面向对象思想体系,属于其一部分。 或者说,它是面向对象编程体系中的思想精髓之一。 面向接口编程的意思是指在面向对象的系统中所有的类或者模块之间的交互是由接口完成的。

要让抽象能工作,必须将实现封装起来。在实践中,这意味着每个类必须有两个部分:一个接口和一个实现。类的接口描述了它的外部视图,包含了这个类所有实例的共同行为的抽象。类的实现包括抽象的表示以及实现期望行为的机制。通过类的接口,我们能知道客户可以对这个类的所有的实例做出哪些假定。实现了封装细节,客户不能对这些细节做出任何假定。 --格雷迪 布谢

5.2 深入了解接口的作用——Comparable接口

Comparable接口中定义了比较方法,compareTo(),返回值为int(忽略泛型,后续学习) 当int值为正数,表示大于;为负数,表示小于;为0,表示等于 API中很多类实现了该接口,很多方法借助该接口。

通过使用Arrays.sort(Object[])方法,理解该接口的作用,进一步理解接口的作用,Arrays.sort(Object[])方法是一个对数组的排序,而排序就会有比较的规则,Comparable接口中的compareTo()方法就是在类里面定义这种比较规则,通过类实现接口,然后重写其中的compareTo()方法来定义自己想要的排序规则。

例如:下述对一个类的数组进行排序,按照其哈希值大小进行排序。

public class Demo implements Comparable<Demo>{

	public String name ;
	
	public Demo() {
		// TODO Auto-generated constructor stub
	}
	
	public Demo(String name) {
		
		this.name = name;
	}

	@Override
	public int compareTo(Demo demo) {
		
		int result = 0;
		if(this.hashCode() > demo.hashCode())
			result = 1;
		else if(this.hashCode() == demo.hashCode())
			result = 0;
		else 
			result = -1;
		
		return result;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

}
	

测试:

import java.lang.reflect.Array;
import java.util.Arrays;

public class Client {
	public static void main(String[] args) {
		Demo[] demos = new Demo[3];
		demos[0] = new Demo("zzz");
		demos[1] = new Demo("yyy");
		demos[2] = new Demo("xxx");
		
		for (Demo demo : demos) {
			System.out.println(demo);
		}
		System.out.println("------------------------");
		Arrays.sort(demos);
		
		for(Demo demo :demos) {
			System.out.println(demo);
		}	
	}	
}

结果:
Demo [name=zzz]
Demo [name=yyy]
Demo [name=xxx]
------------------------
Demo [name=xxx]
Demo [name=yyy]
Demo [name=zzz]

这样就实现了让数组按照对象的哈希值升序排序。

如果需要倒序排序,也只需要改变实现Comparable接口中的compareTo()方法,就可以完成。

@Override
	public int compareTo(Demo demo) {
		
		int result = 0;
		if(this.hashCode() > demo.hashCode())
			result = -1;
		else if(this.hashCode() == demo.hashCode())
			result = 0;
		else 
			result = 1;
		
		return result;
	}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值