JAVA进阶之路---接口与多态

接口与多态

        一、回顾

                多态,从概念上是指一个程序中定义的引用变量,它所指向的具体类型以及它所发出的方法,在编程时并不确定,而是在运行时才确定。换句话说,一个引用变量到底指向哪个类的对象,而这个引用变量发现的方法具体是哪个类的对象发出的方法,这一点需要在运行时才能确定。
                举个例子:
                定义一个接口Swimmer,表示游泳这个动作
public interface Swimmer {
void swim();
}
                定义一个类,实现该接口
public class TestFish implements Swimmer{
@Override
public void swim() {
System.out.println("SmallFish");
}
}

            然后定义一个类,并定义一个doSwim()方法
public class Test {
public static void main(String[] args)
{
TestFish t = new TestFish();
doSwin(t);
}
public static void doSwim(Swimmer swimmer)
{
swimmer.swim();
}
        执行程序,结果输出
SmallFish

        针对上面的例子,我们可以看到,在doSwim()方法中,参数为Swimmer,也就意味着传入的参数只要是实现了Swimmer接口的类的对象就可以,之后会调用该对象的swim()方法。但是在编译时,并不知道具体传入的是什么对象,而这个对象swim()方法又具体是什么。这些只有在运行时才知道。
这里就是多态的一种应用。

二、何谓接口

           前面我们讲了继承,继承其实表达的是一个is-a的关系,子类是属于父类的一种,父类则表示了子类拥有的共同的特点。比如说鲨鱼是鱼的一种,而鱼都会游泳(我也不确定啊,这里只是举例)。
由于JAVA具有单继承性的特性,这一点不同于C++,即一个类只能继承一个父类,那么我们如果想要继承更多的属性和方法,就需要将在这一个父类中定义,因此这父类会很臃肿,可扩展性也很差,因此,提供了接口,而一个类可以实现多个接口。
            接口,不同于继承,它是一种行为的抽象,也就是说我们通常在接口中定义我们需要执行的动作,哪些类需要执行这些动作,则实现接口。

 1、接口的定义

        常见的接口定义如下:

public interface Swimmer {
void swim();
}
        通常我们用interface关键字来定义接口,并且权限修饰符为public。那么其他修饰符是否可以修饰接口呢?接下来我们来看一些常见的修饰符
  •  private/protected    不可以修饰
  • final   不可以修饰
  • static​    不可以修饰
  • 默认 可以修饰,此时接口只能在包中实现​
        原因是,接口本身在设计的时候就是要被其他类实现的,无论是共包还是不共包,因此不应该有这种权限限制。而接口本身也没有办法直接实例化,因此默认我们使用public interface来修饰。

2、接口中方法的定义

        上面的例子中,定义了void swim()方法,其实它隐藏了修饰符,完成的表达是public abstract  void swim();
    我们在定义方法时,可以写public abstract void  swim()
    也可以直接写void swim();编译程序时会自动加上public abstract。
    需要注意,接口中的方法必须为public abstract,不能是其他修饰符,比如private ,此外,接口中定义的方法为抽象方法,不能去实现。

3、接口中的常量的定义

        在接口中我们可以定义一些常量,如下:
public interface Action {
int i = 0;
int m = 0;
void execute();
}
在上面的例子中我们定义了常量i 和 m,同样这里其实隐藏了细节, 完整的定义为:
public static final int i = 0;
我们在定义时可以写int i = 0;      或者    final int i = 0;   或者   static int i = 0;    或者     static final int i = 0;等
需要注意,常量的定义只能是public static final ,不能是其他修饰符,比如private 

三、接口的匿名内部类

       相信很多资料上都说过,抽象类和接口是不能直接通过new来实例化的,这里需要注意,有些面试官会挖坑,他们会问你,抽象类和接口能不能实例化?其实本质上来说有没有这个直接两个字,都是不能实例化的,如果你说不能实例化,面试官不赞同,那么你就需要提到这个特殊的地方,就是接口的匿名内部类的情形。
        匿名内部类,通常是我们在需要一个对象,但是这个对象只使用一次,因此我们不想定义一个引用名称,此时就可以使用匿名内部类。比如:
        我们定义一个类Some,在Some类中我们使用上面定义的Action接口来作为匿名内部类
public class Some {

public static void main(String[] args) {
new Action() {
@Override
public void execute() {

}
};
}
}

可以看到这里我们直接使用new来完成了实例化,看起来违背了我们之前提出的抽象类和接口是不能直接通过new来实例化的原则,但是其实并不违背。
接口的匿名内部类其实本质上,是编译时生成了一个实现了接口的类的对象,也就是说本质上还是生成了一个类,这个类实现了这个接口,而不是直接实例化了一个接口。所以,如果有人说可以实例化,不要怕,拿起你45码的鞋子抽他。

四、接口继承其他接口

        类之间可以互相继承,那么接口之间可以互相继承么?
        答案是可以的,举例说明:
        定义一个接口:Action
public interface Action {
int i = 0;
int m = 0;
void execute();
}

        再定义一个接口Action1,实现Action
public interface Action1 extends Action{
void test();
}

可以看到,Action1实现了Acion接口。


五、接口可以实现接口么?

        不能,实现接口意味着需要在接口中具体实现另一个接口的方法,这违背了接口的定义。

六、抽象类中接口的使用

        我们知道类可以实现接口,那么在抽象类中自然可以实现接口,那么在具体实现时又有哪些特点呢?举例说明:
        首先我们定义一个接口
public interface Swimmer {
void swim();
void test();

        然后我们定义一个抽象类Fish,实现了Swimmer接口

package Demo;

public abstract class Fish implements Swimmer{
private String name;
public Fish(String name)
{
this.name = name;
}

public void test()
{

}
}
         
        可以看到,如果是抽象类实现接口,在抽象类中我们可以实现接口的方法,也可以不实现接口的方法由继承这个抽象类的子类实现。
        我们定义一个实体类,实现Fish抽象类,如下:
public class SmallFish extends Fish {
public SmallFish(String name) {
super(name);
}
@Override
public void swim() {
System.out.println("SmallFish");
}
}        
        总结一点:实现了接口的抽象类,可以选择实现接口方法,也可以选择由继承它的子类来实现该接口的方法。












猜你喜欢

转载自blog.csdn.net/ckq5254/article/details/80511262