java是单继承的可是现实存在着支持多继承,例如“金丝猴”是一个动物,同时他也是一个值钱的东西,在代码中写exrends动物
再extends值钱的 这是确定不能够的,java只支持单继承,这时就能够用接口了
接口是一种特殊的抽象类,也就是说,接口也存在类的特性,假如说这个类中常量是final的而且方法也是抽象的,这时候就能够定义成接口
下面就是一个典型的接口:
public interface Runner{ public static final int id = 1; public void start(); public void run(); public void stop(); }
接口是一种特殊的抽象类,在这个抽象类里面全部的方法都是抽象方法 的而且成员变量都是public static final 类型 常量名,java 默认是public static final 固然能够直接写 类型 常量名 ,例如:java
public static final int id=10,能够写成int id =10,而且接口中的方法也能够不写abstract 关键字来标识,由于在接口中全部的方法默认都是抽象的,虽说在上面的代码中 start方法和run方法与stop方法没有写abstract 可是要知道他们是抽像的,只不过省略了abstract而已,注意:在接口里面声明的抽象方法默认是“public(公共的)”的,也只能是“public(公共的),成员变量是public static final的也只能是public static final 的,”java接口中的成员变量为何要定义成public static final呢,这是腰修正c++中的多继承出现问题,多继承多个父类之间若是出现相同变量的时候,在运行会出现各类问题,因此,java改为static fianal的,让成员变量只属于这个类,不属于某个对象,在多继承中子类包含多个父类对象,而单继承来讲子类里面就只有一个父类对象,多继承子类对象就有多个父类对象,而这些父类对象之间可能会出现有重复的成员变量,这就很是容易出现问题,所以,在java中避免了这种问题的出现,采用了接口来实现多继承,c++
做为接口来讲,一个类从接口继承(或者是实现接口),这也是多继承,接口里面的成员变量不属于某个对象,都是静态的成员变量,是属于整个类,所以一个类去实现多个接口也是无所谓的,不会存在对象之间相互冲突的问题,实现多个接口也就是实现了多继承,并且又避免了多重继承容易出现问题的地方,这就是接口实现的好处ide
接口特性:
下面分析一下一个例子 :函数
package 接口; interface Singer{ public void sing(); public void sleep(); } interface Painter{ public void paint(); public void eat(); } class Student implements Singer{ private String name; Student(String name){ this.name = name; } public void study() { System.out.println("studying"); } public String getName() { return name; } public void sing() { System.out.println("student is singing"); } public void sleep() { System.out.println("student is sleeping"); } } class Teacher implements Singer,Painter{ private String name; public String getString() { return name; } Teacher(String name){ this.name = name; } public void teach() { System.out.println("teachinging"); } public void sing() { System.out.println("teacher is singing"); } public void sleep() { System.out.println("teacher is sleeping"); } public void paint() { System.out.println("treacher is painting"); } public void eat() { System.out.println("teacher is eating"); } } class 接口 { public static void main(String[] args) { // TODO Auto-generated method stub Singer s1 = new Student("le"); s1.sing(); s1.sleep(); Singer s2 = new Teacher("steven"); s2.sing(); s2.sleep(); Painter p1 = (Painter)s2; p1.paint(); p1.eat(); } }
首先从函数的入口main函数开始 this
Singer s1 = new Student("le");lua
定义一个Singer接口的变量叫作s1,接口Singer是Student类实现的,即至关于Student类从Singer接口的继承,所以,s1是父类的一个引用,这句话的意思就是父类的一个对象s1的引用指向了子类对象Student,后面执行spa
Student(String name){3d
this.name = name;指针
}code
经过调用Student的构造方法将Student类中的属性name赋值为"le",
这个Student对象可以访问位于代码区里面的sleep()方法和sing()方法,由于Student类从父类Sing继承而来,所以天然能够访问到这两个方法,除此以外,还能访问Student类里面自定义的Study()方法。所以代码区里面存放着这三个方法等待着Student类的对象去访问,也就是去调用。一个正常的Student能够直接调用这三个方法。那么怎么找获得位于代码区的这三个方法呢?Student对象里面存在着能找获得这个三个方法的函数指针,引用对象经过这个指针的索引指向就能找到代码区里面的这三个方法。
s1是父类对象的索引,但此时s1指向的倒是子类对象,即一个父类对象的索引指向了子类对象。这里很不幸的是,因为这个s1是一个父类对象的引用,站在s1的角度上,它就是只把你这个子类对象Student当成是一个Singer,s1只能看到Student对象里面的sing()和sleep这两个方法的方法指针,所以使用这个s1引用对象只能去访问从父类继承下来的sleep()和sing()这两个方法,但因为这两个方法在子类Student里面被重写了,那么如今就是这种状况了,子类Student从父类Singer继承,在子类里面重写了从父类继承下来的sing()和sleep()这两个方法,父类对象的引用指向了子类对象,这三种状况加在一块儿就使得多态能够存在了,这样调用位于代码区里面的方法时,会根据new出来的实际对象去调用代码区里面的方法,所以这里在s1眼里虽然是把这个new出的Student当成一个Singer,但这个对象实际上就是一个Student,所以使用父类对象的引用s1调用代码区里面的sleep()和sing()方法时,调用的是在子类里面重写事后的sing()和sleep()方法。
此时的内存图以下:
Singer s2 = new Teacher("stven");
Teacher这个类实现了Singer接口和Painter接口,即至关于从两个父类继承,一个父类是Singer,另外一个父类是Painter
这里的s2也是父类对象Singer的引用,指向的倒是子类对象Teacher,所以也是一个父类对象的引用指向子类对象。
创造这个Teacher对象的时候,调用Teacher(String name)构造方法,其定义以下:
Teacher(String name){
this.name=name;
}
调用构造方法后,Teacher有了本身的名字steven,因此Teacher的name属性值为steven,因为这个Teacher实现了Painter接口和Singer接口,所以也继承这两个接口里面的方法,所以一个正常的Teacher能够访问的方法有:paint()、eat()和sing()、sleep。前面两个方法是从Painter类继承过来的,后面两个方法是从Singer类继承过来的。除了这四个方法外,还有本身定义的Teach()方法。但是很不幸的是,因为s2是一个Singer类对象的引用,所以站在s2的角度来看,它只把Teacher当成是一个普通的Singer,所以它看到的只是Teacher对象里面的sing()和sleep()这两方法,而后要调用时就经过Teacher对象里面的函数指针找到位于代码区的sleep()和sing()这两个方法。别的方法s2是看不到的,所以也调用不了。
Painter p1=(Painter)s2;
这里把s2强制转换成Painter,s2对象实际是指向Teacher的,把s2强制转换成Painter之后,就能够把Teacher当成Painter来用,因此p1会把Teacher当成Painter来看待,所以p1只能看到Teacher里面的painter()方法和eat()方法,所以可以访问到的也只有这两个方法。因此接口对于咱们实际当中的对象来讲,每个接口暴露了咱们这个实际对象的一部分方法。你使用什么样的接口,就只能访问这个接口里面定义的方法,别的接口定义的方法就没办法访问获得。
输出:
student is singing
student is sleeping
teacher is singing
teacher is sleeping
treacher is painting
teacher is eating
下面用另外一个例子进行验证接口的近一步特性
package javastudy.summary; /** * 把“值钱的东西”这个类定义成一个接口Valuable。在接口里面定义了一个抽象方法getMoney() * * */ interface Valuable { public double getMoney(); } /** * 把“应该受到保护的东西”这个类定义成一个接口Protectable。 * 在接口里面定义了一个抽象方法beProtected(); * */ interface Protectable { public void beProteced(); } /** * 这里是接口与接口之间的继承,接口A继承了接口Protectable, * 所以天然而然地继承了接口Protectable里面的抽象方法beProtected()。 * 所以某一类去实现接口A时,除了要实现接口A里面定义的抽象方法m()之外, * 还要实现接口A从它的父接口继承下来的抽象方法beProtected()。 * 只有把这两个抽象方法都实现了才算是实现了接口A。 * * */ interface A extends Protectable { void m(); } /** * 这里定义了一个抽象类Animal。 * * */ abstract class Animal { private String name; /** * 在Animal类里面声明了一个抽象方法enjoy() */ abstract void enjoy(); } /** * 这里是为了实现了咱们原来的语义: * “金丝猴是一种动物”同时“他也是一种值钱的东西”同时“他也是应该受到保护的东西”。而定义的一个类GoldenMonKey。 * 为了实现上面的语义,这里把“值钱的东西”这个类定义成了一个接口Valuable, * 把“应该受到保护的东西”这个类也定义成了一个接口Protectable。这样就能够实现多继承了。 * GoldenMonKey类首先从Animal类继承,而后GoldenMonKey类再去实现Valuable接口和Protectable接口, * 这样就能够实现GoldenMonKey类同时从Animal类,Valuable类,Protectable类继承了,即实现了多重继承, * 实现了原来的语义。 * * */ class GoldenMonKey extends Animal implements Valuable,Protectable { /** * 在GoldenMoKey类里面重写了接口Protectable里面的beProtected()这个抽象方法, * 实现了接口Protectable。 */ @Override public void beProteced() { System.out.println("live in the Room"); } /** * 在GoldenMoKey类里面重写了接口Valuable里面的getMoney()这个抽象方法,实现了接口Valuable。 */ @Override public double getMoney() { return 10000; } /** * 这里重写了从抽象类Animal继承下来的抽象方法enjoy()。 * 实现了这抽象方法,不过这里是空实现,空实现也是一种实现。 */ @Override void enjoy() { } public static void test() { /** * 实际当中在内存里面咱们new的是金丝猴,在金丝猴里面有不少的方法, * 可是接口的引用对象v能看到的就只有在接口Valuable里面声明的getMoney()方法, * 所以可使用v.getMoney()来调用方法。而别的方法v都看不到,天然也调用不到了。 */ Valuable v = new GoldenMonKey(); System.out.println(v.getMoney()); /** * 把v强制转换成p,至关于换了一个窗口,经过这个窗口只能看获得接口Protectable里面的beProtected()方法 */ Protectable p = (Protectable)v; p.beProteced(); } } /** * 这里让Hen类去实现接口A,接口A又是从接口Protectable继承而来,接口A本身又定义了一个抽象方法m(), * 因此此时至关于接口A里面有两个抽象方法:m()和beProtected()。 * 所以Hen类要去实现接口A,就要重写A里面的两个抽象方法,实现了这两个抽象方法后才算是实现了接口A。 * * */ class Hen implements A { @Override public void beProteced() { } @Override public void m() { } } /** * java中定义接口 */ public class JavaInterfacesTest { public static void main(String[] args) { GoldenMonKey.test(); } }
接口总结:接口和接口之间能够相互继承,类和类之间能够相互继承,类和接口之间,只能是类来实现接口