
什么是抽象类?
在接触接口之前,我们还需要认识到什么是抽象类,简单来说,接口可以认为是一个比抽象类更抽象的类 那么先来说说什么是抽象类?包含一个或者多个抽象方法的类就是抽象类,抽象方法就是没有方法体的方法,而且抽象方法和抽象类都必须声明为abstract类型。
public abstract class Person {
public abstract String getDescription();
}
注意!抽象类必须包含抽象方法,但是也可以同时包含具体数据和具体方法!!,看如下例子
public abstract class Person{
private String name;
public Person(String name){
this.name = name ;
}
public abstract String getDescription();
public String getName(){
return name;
}
}
许多人都可能误以为抽象类不能有具体方法,其实是错误的,这也是抽象类和接口的不同之处,接口是不允许含有具体方法的
而且抽象类不能被实例化,也就是说abstract修饰的类不能拥有对象!
new Person();
但是虽然不可以实例化抽象类,但是我们可以定义抽象引用变量,但是这个引用只能对应非抽象子类的对象,假设Student类是Person类的非抽象子类
Person p=new Student();
所谓非抽象子类就是说,如果创建一个继承抽象类的子类并为之创建对象,那么就必须为父类的所有抽象方法提供方法定义。如果不这么做(可以选择不做),子类仍然是一个抽象类,编译器会强制我们为新类加上 abstract 关键字。(就是说如果没有重写抽象父类的所有抽象方法,还是会被强制转换成abstract类)
public class Student extends Person {
private String major;
public Student(String name, String major) {
super(name);
this.major = major;
}
@Override
public String getDescription(){
return "a student majoring in " + major;
}
}
调用如下
Person p = new Student("Jack","Computer Science");
p.getDescription();
注意此时的p引用的是Student对象,而且引用的对象对应的类都是非抽象的
什么是接口
接口的本质其实也是一个类,而且是一个比抽象类还要抽象的类。怎么说呢?抽象类是能够包含具体方法的,而接口杜绝了这个可能性,在 Java 8 之前,接口非常纯粹,只能包含抽象方法,也就是没有方法体的方法。在Java8之后出现了一些改变,允许接口包含默认方法和静态方法。 Java 使用关键字 interface 而不是 class 来创建接口。和类一样,通常我们会在关键字 interface 前加上 public 关键字,否则接口只有包访问权限,只能在接口相同的包下才能使用它。
public interface Concept {
void idea1();
void idea2();
}
我们已经定义好了一个接口,而且接口里只存在抽象方法,那么肯定是需要扩展(继承)接口,重写里面的抽象方法的,那么该如何去做。 答:使用 implements 关键字使一个类扩展某个特定接口(或一组接口),通俗来说:接口只是外形,现在这个扩展子类要说明它是如何工作的。
class Implementation implements Concept {
@Override
public void idea1() {
System.out.println("idea1");
}
@Override
public void idea2() {
System.out.println("idea2");
}
}
你可以选择显式地声明接口中的方法为 public,但是即使你不这么做,它们也是 public 的。所以当实现一个接口时,来自接口中的方法必须被定义为 public。否则,它们只有包访问权限,这样在被继承时,它们的可访问权限就被降低了,这是 Java 编译器所不允许的。 另外,接口中是允许出现常量的,与接口中的方法都自动地被设置为 public —样,接口中的域将被自动被设置为 public static final 类型,
public interface Concept {
void idea1();
double item = 95;
}
接口的特性
接口和类其中不同的一点就是,我们无法像类一样使用 new 运算符来实例化一个接口:
x = new Concept(. . .);
原因也很简单,接口连具体的构造方法都没有,肯定是无法实例化的。
当然, 尽管不能构造接口的对象,声明接口的变量还是可以的(和抽象类一样只可以声明引用变量):
Concept x;
那么声明的接口变量只可以引用实现了这个接口的类
x = new Implementation(. . .);
接下来, 如同使用 instanceof 检查一个对象是否属于某个特定类一样, 也可以使用 instanceof 检查一个对象是否实现了某个特定的接口:
if(x instanceof Concept){
...
}
而且接口也可以被继承(接口只能被接口继承)
public interface Concept1 {
void idea1();
void idea2();
}
-------------------------------------------
public interface Concept2 extends Concept1{
double idea3();
}
但是说了这么多,接口和抽象类也仅仅是差在接口不能拥有具体的方法和具体变量罢了,为什么Java要引入接口而不是直接使用抽象类? 答:因为一个类可以实现多个接口!!而只可以继承一个父类 接口的出现打破了Java单继承的限制,为类的定义提供了很大的灵活性 在合理的范围内尽可能地抽象。显然,接口比抽象类还要抽象。因此,一般更倾向使用接口而不是抽象类。
Java8接口的新特性(静态方法和默认方法) 但是理论上讲,没有理由证明这是不合法的,只是这有违于将接口作为抽象规范的初衷。举个例子:
public interface Concept {
public static void get(String name){
System.out.println("hello " + name);
}
default void idea1(){
System.out.println("this is idea1");
};
}
用default修饰的就是默认方法,这样类就不需要实现这个默认方法了
不过,引入默认方法后,就出现了一个默认方法冲突的问题。如果先在一个接口 A 中将一个方法 idea 定义为默认方法, 然后又在另一个接口 B 或者超类 C 中定义了同样的方法 idea,然后类 D 实现了这两个接口 A 和 B(或超类 C)。于是类 D 中就有了方法 idea 的两个默认实现,出现了冲突,为此,Java 制定了一套规则来解决这个二义性问题: 1 ) **超类优先。**如果超类提供了一个具体方法,接口中的同名且有相同参数类型的默认方法会被忽略。
2 ) 接口冲突。 如果一个父类接口提供了一个默认方法,另一个父类接口也提供了一个同名而且参数类型相同的方法,子类必须覆盖这个方法来解决冲突
interface A {
default void idea(){
System.out.println("this is A");
}
}
interface B {
default void idea(){
System.out.println("this is B");
}
}
class D implements A, B{
public void getName(){
System.out.println("this is D");
}
}
只要有一个接口提供了一个默认实现,编译器就会报告错误, 我们就必须解决这个二义性。 假设B中的idea()不是default,那么D会自动继承A中的默认方法吗,并不会!
接口存在的意义
为什么要定义接口,感觉定义接口只是提前做了个多余的工作。 其实不是,定义接口并非多余,**接口是用来提供公用的方法,规定子类的行为的。**举个例子,让大家直观的感受下接口的作用: 比如一个网站,需要保存客户的信息,但是客户的信息来源却是各种各样的,比如从web端,客户端,手机端等,假设来源不同的客户信息需要有不同的逻辑处理业务,这时候我们定义一个提供客户信息存储方法的接口,然后不同的平台就存储我们定义的这个接口,以后有客户信息需要存储,我们只需要知道这个接口就可以了,具体的Java代码封装在黑盒子里,这也就是 Java 的多态的体现,接口帮助我们对这些有相同功能的方法做了统一管理。 
|