接口
当抽象类中的方法都是抽象的时候,这时可以把该类定义成接口的形式。你可以先期将接口理解为特殊的抽象类。
特点:
1.接口的方法都是抽象的。
2.接口不可以被实例化。
3.只有子类实现了接口中的所有抽象方法后,该子类才可以实例化,否则该子类还是一个抽象类。
格式特点:
1.全局常量。
2.抽象方法。
而且接口中的成员都有固定的修饰符:
全局常量:public static final
成员方法:public abstract
这些修饰符即使不写,系统也会自动的加上。
建议一定书写,因为可以提高程序的阅读性。
通过观察你会发现,接口中定义的成员都有一个共同的特点:都是public权限的。
interface Inter
{
public static final int num = 4;
public abstract void show();
}
如果要使用接口中的方法,必须定义一个类实现接口中的所有的抽象方法后,该子类才可以建立对象并调用这些方法。
继承和实现的一点区别:
类与类之间称为继承:因为该类无论是抽象的还是非抽象的,它的内部可以定义非抽象方法,这个方法可以直接被子类使用,所以子类继承就可以了。
类与接口是实现关系:因为接口中的方法全部都是抽象的,必须由子类实现完才可以实例化。所以就用了更确切的关键字来表示。Implements。
类只能单继承,而接口可以被多实现。
Java将多继承机制进行改良,通过多实现接口的形式来体现。
为什么不支持多继承?
因为当东哥父类中定义了相同的方法,而方法的内容不同时,子类对象在调用该方法时,不明确要运行哪一个,有安全隐患,也就是不确定性。
但是,多实现就没有这个问题,因为接口中的方法都没有主体。
class DemoA implements Inter,Inter2//多实现。
{
public void show(){}
//public void method(){}
}
接口的另一个好处:一个类在继承另一个类的同时可以是吸纳多个接口。
接口的出现就皮面了单继承的局限性。
福诶中定义了该功能的基本功能,而接口中定义的是该对象的扩展功能。
class Test extends Demo implements Inter,Inter2
{
public void show(){}
}
接口的基本思想:
1.接口就是对外暴露的规则。
2.接口就是功能的扩展。
3.接口的出现降低了耦合性(紧密联系程度)。
耦合性:耦合性的降低就是实现了模块的开发。比如:两个人一起做事,在做事前先定义好规则,你在实现规则,我在使用规则,至于你怎么实现的和我没关系,因为你已经封装了,我不需要知道细节,只知道规则即可。
接口:
两种理解:1.是java中的interfacejava中的接口的体现。
2.广义的理解:子要对外提供规则的都属于接口范畴。
抽象类和接口的区别:
1.抽象类只能被单继承。接口可以多实现。
2.抽象类中可以定义非抽象方法,直接被子类使用。接口中只有抽象方法,必须被子类实现后才可以被使用。
3.抽象类中定义了体系中的基本公共性功能。接口中通常定义体系中对象的扩展功能。
4.接口的出现避免了单继承的局限性。
5.抽象类被继承,时 is a 关系。xx1是xx2中的一种。接口可以被实现,是like a关系xx1像xx2长的一种。
类与类之间是继承关系。
类与接口之间是实现关系。
接口与接口之间是继承关系,通过接口可以多继承。Java不支持类的多继承。
多态
1.在程序中的体现:
父类引用或者接口引用指向自己的子类对象。
2.好处:
提高了代码的扩展性,后期的可维护性。
3.前提:
(1)类与类之间必须有继承或者实现关系。
(2)通常都需要进行覆盖。
4.弊端:
进行多态应用时,前期并不知道后期会有多少个子类出现,但是可以使用父类的引用来调用父类的方法。而后期那个子类对象出现就执行那个子类的具体方法实现。这就是程序的扩展性。但是,前期调用的时候,只能调用具体子类的特有方法。因为前期还不知道具体的子类是谁。
多态的思想:
以前:定义对象,兵指挥对象做事,当对象多了以后,只会动作就会变得很麻烦。这是重新思考这个问题。找到这些对象的共性类型。直接指挥这个共性类型做事即可。这样反是属于这个类型的个体都会执行。
可以对传入的对象进行类型的判断。
//通过一个关键字来完成 instanceof : 对象 instanceof 类型 用于判断该对象是否所属于该类型。
public static void method(Animal a)
{
//可以对传入的对象进行类型的判断。
//通过一个关键字来完成 instanceof : 对象 instanceof 类型 用于判断该对象是否所属于该类型。
if(a instanceof Cat)
{
Cat c = (Cat)a;
c.eat();
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog d = (Dog)a;
d.eat();
d.lookHome();
}
else
a.eat();
}
多态中的细节:
再多态中:
成员变量:
编译时期:看的引用型变量所属的类中是否有所调用的变量。
运行时期:也是看引用型变量所属的类是否有调用的变量。
简单一句话:成员变量,无论编译还是运行都看引用型变量所属的类。
更简单的一句话:成员变量,编译和运行都看等号的左边。
成员函数:
编译时期:看的引用型变量所属的类中是否有调用的方法。
运行时期:看的对象所属的类中是否有调用的方法,如果父子出现同名的方法,会运行子类中的方法,因为方法有覆盖特性。
简单说:对于成员函数,编译看左边,运行看右边。其实非静态函数,在内存中有一个动态绑定机制。其实就是F指向了具体的子类对象。
编译看到F所属非Fu类中是否有这么一个具体的子类对象上,子类对象运行时会覆盖父类中的相同想法,而运行子类的内容。
静态函数:
编译时期:看的是引用型变量所属的类中是否有调用的方法。
运行时期:也是看的是引用型变量所属的类中是否有调用的方法。
简单说: 对于静态函数,编译看左边,运行也看左边.
静态函数存放于每一个所属类的静态区中,它是被静态绑定,
就是类一加载,就已经有固定所以的调用就是哪个类名。
重点掌握,没有明白原理,就记住结论。
整体总结:
成员变量和静态成员:编译和运行都看左边。
只有非静态的成员函数:编译看左边,运行看右边。