接口(协议)
有时候考虑到子类的有些行为大有不同,有些子类会用到这些方法有些不会。如Animal下的Cat, Dog, Lion, Tiger。此时想要向Animal中添加一个Pet()方法返回一些Frindly程度Cut值。
显然Pet()对于Lion和Tiger根本不会用到,Lion可以重写Pet()以返回一个'Gun'但是显然不优雅。
可能会有人想到再创建一个父类Pet,只让Cat, Dog同时继承Pet和Animal。但是这会导致继承的“致命方块”的问题,有可能子类想要调用父类的一个foo()方法,但两个父类都实现了此方法,此时子类就不知道要调用哪一个父类的foo()方法了。
此时有了 接口 概念。被定义为接口的类是一个100%纯抽象的类,所有方法都是抽象的。我们知道,抽象类不可被实例化,抽象方法必须要重写。这里,子类必须重写接口类的所有方法,也就不会再调用父类的方法以至于不知道要用哪个。这里的接口是一种协议,与API毫无关系。
接口的定义:public interface Pet {....}
使用interface代替class
实现接口:public class Dog extends Canine implements Pet {...}
public interface Pet { //interface代替class
public abstract void beFriendly();
void play(); //接口方法可以不像上面一样写public abstract。接口方法本身带有public abstract的意思,这是他们的天赋
}
public class Dog extends Animal implements Pet { //继承一个类后实现接口
public void BeFriendly() {...} //必须要覆盖的方法
public void play() {...}
public void eat(){...} //覆盖Animal类的方法
public void roam() {...}
}
public class Lion extends Animal { //不需要Pet行为的Lion
public void eat() {...}
}
//接口可以很方便的对特殊个体添加特殊行为,可以实现多个接口
public class Dog extends Animal implements Pet, fourFooted,... {...}
接口也适用多态的概念:Pet Dog = new Dog()
jar = Java Archive
由于接口只是定义了一个方法声明,并没有具体实现。所以当接口类有一个新方法的需要时就要把实现它的子类都挨个重写该方法,不想普通继承直接调用父类的方法。(接口的扩充关键字不属于标准设计,属于代码维护时添加新方法时的无奈之举)
所以就有了两种关键字,用来在接口类中写带有内容的方法。
1.可以使用default来定义普通方法,普通方法需要通过对象调用
2.可以使用static来定义静态方法,可以直接通过接口名来调用
package cn.yang.demo;
interface IMessage {
public void fun();
public default void foo() { //default关键字可以追加方法体
System.out.println("杨优秀");
}
public static IMessage getInstance() { //static关键字说明可以直接用类名调用
return new Message(); //返回Message对象
}
}
class Message implements IMessage {
@Override
public void fun() {
System.out.println("杨不优秀");
};
}
public class TestDemo {
public static void main(String[] args) {
Message msg = new Message(); //或IMessage msg = new Message(); 多态
msg.foo(); //可以直接调用接口的default关键字普通方法
IMessage msg1 = IMessage.getInstance(); //类型是IMessage类型的
msg1.fun();
}
}
接口有了这些功能更像是抽象类了,但是接口可以多继承,而类只能单继承
内建函数时接口(泛型)(引用)
1.功能性接口Function
功能性接口:输入一个数据,将数据处理后返回
@FunctionalInterface
public interface Function {
T apply(R);
}
//唯一的apply方法
package cn.yang.demo;
import java.util.function.Function;
public class TestDemo {
public static void main(String[] args) {
Function fun = String::valueOf; //将valueOf方法引用到接口中的方法中
System.out.println(fun.apply(1000));
}
}
//输出:String类型的1000
2.消费性接口Consumer:只有输入没有输出
@FunctionalInterface
public interface Consumer {
void accept(T);
}
package cn.yang.demo;
import java.util.function.Consumer;
public class TestDemo {
public static void main(String[] args) {
Consumer c = System.out :: println; //引用println方法
c.accept("Hello"); //相当于System.out.print()
}
}
3.供给型接口Supplier:无输入有输出
@FunctionalInterface
public interface Supplier {
T get();
}
package cn.yang.demo;
import java.util.function.Supplier;
public class TestDemo {
public static void main(String[] args) {
Supplier s = "hello" :: toUpperCase;
System.out.println(s.get());
}
}
4.断言型接口Predicate:判断输入是否为True
@FunctionalInterface
public interface Predicate {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
//该接口有唯一的一个方法:test。返回布尔值。
package cn.yang.demo;
import java.util.function.Predicate;
public class TestDemo {
public static void main(String[] args) {
Predicate p = "Hello" :: startWith;
System.out.println(p.test("H"));
}
}
函数式编程接口
note:函数式编程接口的静态方法只能通过 接口名.静态方法 来实现。
note:default方法实现接口的子类不需要实现,直接继承
java 8中抽象类与接口的异同
相同点:
1)都是抽象类型;
2)都可以有实现方法(以前接口不行);
3)都可以不需要实现类或者继承者去实现所有方法,(以前不行,现在接口中默认方法不需要实现者实现)
不同点:
1)抽象类不可以多重继承,接口可以(无论是多重类型继承还是多重行为继承);
2)抽象类和接口所反映出的设计理念不同。其实抽象类表示的是"is-a"关系,接口表示的是"like-a"关系;
3)接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值;抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
Note:friendly 型:如果一个类、类属变量及方法不以public,protected,private这三种修饰符来修饰,它就是friendly类型的,那么包内的任何类都可以访问它,而包外的任何类都不能访问它(包括包外继承了此类的子类),因此,这种类、类属变量及方法对包内的其他类是友好的,开放的,而对包外的其他类是关闭的。