继承是希望得到父类的特性,所以子类可以访问父类的静态属性和方法,实现只是实现一种规则,不需访问特性,所以接口的静态成员不能被子类访问 https://github.com/niliv/practice/tree/master/java/bz/InterfaceProject/src
定义:事物在运行过程中存在不同的状态 猫既是猫也是动物 猫 cat = new 猫 动物 cat = new 猫 一个对象对象这不同类型
指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法.
Java实现多态有三个必要条件:继承、重写、向上转型
在Java中有两种形式可以实现多态。继承和接口
public class Animal {
int num = 10;
public void eat(){
System.out.println("动物吃饭");
}
}
public class Cat extends Animal {
int num = 80;
int age = 10;
public void eat(){
System.out.println("猫吃饭");
}
public void catchMouse(){
System.out.println("猫在抓老鼠");
}
}
public static void main(String[] args) {
Animal am = new Animal();
System.out.println(am.num);
am.eat();
Animal amCat = new Cat();
System.out.println(amCat.num);
//System.out.println(amCat.age); 报错
amCat.eat();
//amCat.catchMouse(); 报错
}
基于继承实现的多态可以总结如下:
自动类型提升:Animal a = new Cat()
向上转型,子类特有方法无法访问 向下转型:Cat c = (Cat)a
为了使用子类特有方法 转型都是子类在变化,一会猫一会动物,不能是一会猫一会狗,也不能是父类一会是动物一会是猫
a可以使用Animal的所有方法,也可以使用cat继承的所有方法,不能使用cat特有方法
在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。
继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。
如果一个类没有足够的信息来描述一个具体的对象,而需要其他具体的类来支撑它,那么这样的类我们称它为抽象类。
我们都知道这个是产生一个动物Animal对象,但是这个Animal具体长成什么样子我们并不知道,它没有一个具体动物的概念,所以他就是一个抽象类,需要一个具体的动物,如狗、猫来对它进行特定的描述,我们才知道它长成啥样。
同时,抽象类体现了数据抽象的思想,是实现多态的一种机制。它定义了一组抽象的方法,至于这组抽象方法的具体表现形式有派生类来实现。同时抽象类提供了继承的概念,它的出发点就是为了继承,否则它没有存在的任何意义。所以说定义的抽象类一定是用来继承的。
在使用抽象类时需要注意几点:
抽象类不能被实例化,实例化的工作应该交由它的子类来完成
抽象类有构造函数,用于给子类对象初始化
抽象方法必须由子类来进行重写。
只要包含一个抽象方法的抽象类,该方法必须要定义成抽象类,不管是否还包含有其他方法。
抽象类中可以包含具体的方法,当然也可以不包含抽象方法。
子类中的抽象方法不能与父类的抽象方法同名。
abstract 不能与final并列修饰同一个类。
abstract 不能与private、static、final或native并列修饰同一个方法。
public abstract class Animal {
int num = 10;
public void eat(){
System.out.println("动物吃饭");
}
public abstract void cry();
}
public class Cat extends Animal {
int num = 80;
int age = 10;
public void eat(){
System.out.println("猫吃饭");
}
public void catchMouse(){
System.out.println("猫在抓老鼠");
}
public void cry(){
System.out.println("喵喵喵!");
}
}
public static void main(String[] args) {
Animal amCat = new Cat();
System.out.println(amCat.num);
//System.out.println(amCat.age); 报错
amCat.eat();
//amCat.catchMouse(); 报错
amCat.cry();
}
接口是抽象类的延伸,java了保证数据安全是不能多重继承的,也就是说继承只能存在一个父类,但是接口不同,一个类可以同时实现多个接口,不管这些接口之间有没有关系,所以接口弥补了抽象类不能多重继承的缺陷,但是推荐继承和接口共同使用,因为这样既可以保证数据安全性又可以实现多重继承。
在使用接口过程中需要注意如下几个问题:
Interface的所有方法的访问权限,自动被声明为public。确切的说只能为public,当然你可以显示的声明为protected、private,但是编译会出错!
接口中可以定义“成员变量”,或者说是不可变的常量,因为接口中的“成员变量”会自动变为public static final。可以通过类命名直接访问:ImplementClass.name
在jdk1.8中可以用default来修饰实现的非抽象方法,接口对象可以直接调用,也可以声明静态方法,但要注意静态方法只能用类名调用,默认方法只能用实例调用
实现接口的非抽象类必须要实现该接口的所有方法。抽象类可以不用实现。
不能使用new操作符实例化一个接口,但可以声明一个接口变量,该变量必须引用一个实现该接口的类的对象。可以使用 instanceof 检查一个对象是否实现了某个特定的接口。例如:if(anObject instanceof Comparable){}。
在实现多接口的时候一定要避免方法名的重复。
接口与接口之间可以继承 extends,而且可以多继承
https://blog.csdn.net/aitangyong/article/details/54134385 https://blog.csdn.net/sun_promise/article/details/51220518
public interface Play {
String name="Play"; //默认被public static final修饰 必须初始化
public abstract void show();
public void cry(String name); //可以省略public abstract
void eat();
//1.8新特性 定义非抽象方法 默认方法可以被子类覆盖
public default void method() {
System.out.println("Play-method");
}
//默认方法
public default void defaultMethod() {
System.out.println("Play-default");
}
//静态方法
public static void staticMehtod() {
System.out.println("Play-static");
}
}
public abstract class Person {
public static String name="Person";
public static void study() {
System.out.println("abstract-static");
}
public abstract void show();
public abstract void cry();
}
public class Student extends Person implements Play {
@Override
public void eat() {
// TODO Auto-generated method stub
}
//实现的是Person的show方法 血缘关系
@Override
public void show() {
// TODO Auto-generated method stub
}
//接口中的cry
@Override
public void cry(String name) {
// TODO Auto-generated method stub
}
//Person中的cry 必须构成重载,否则报错,无法同时实现
@Override
public void cry() {
// TODO Auto-generated method stub
}
//覆盖接口默认方法
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("student-method");
}
}
public class TestInterface {
public static void main(String[] args) {
//接口实例化
Play play = new Student();
play.method(); //student-method
System.out.println(play.name); //静态变量可以用实例调用 Play
//为什么默认方法只能通过对象调用?
//为什么接口的静态方法只能用类名调用?
play.defaultMethod(); //Play-default
Play.staticMehtod(); //Play-static
//抽象类实例化
//为什么抽象类的静态方法和属性,用实例都可以调用?
Person person = new Student();
person.study(); //abstract-static
Person.study();
System.out.println(person.name); //Person
}
}
接口的传递性
public interface InterfaceA {
public void show();
}
interface InterfaceB extends InterfaceA {
}
interface InterfaceC extends InterfaceB {
}
class MyClass implements InterfaceC{
//实现的是A的show
@Override
public void show() {
// TODO Auto-generated method stub
}
}
接口的多继承
public interface InterfaceA {
public void show();
}
interface InterfaceB extends InterfaceA {
//实现A的show
public void show();
}
class MyClass implements InterfaceA,InterfaceB{
//实现A的show
@Override
public void show() {
// TODO Auto-generated method stub
}
}
为了更好的阐述他们之间的区别,下面将使用一个例子来说明。该例子引自: http://blog.csdn.net/ttgjz/article/details/2960451
我们有一个Door的抽象概念,它具备两个行为open()和close(),此时我们可以定义通过抽象类和接口来定义这个抽象概念:
//抽象类
abstract class Door{
abstract void open();
abstract void close();
}
//接口
interface Door{
void open();
void close();
}
现在如果我们需要门具有报警的功能,那么该如何实现呢?
解决方案一:给Door增加一个报警方法:clarm();
//抽象类
abstract class Door{
abstract void open();
abstract void close();
abstract void alarm();
}
//接口
interface Door{
void open();
void close();
void alarm();
}
这种方法违反了面向对象设计中的一个核心原则 ISP (Interface Segregation Principle)—见批注,在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方 法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变而改变,反之依然。
解决方案二
既然open()、close()和alarm()属于两个不同的概念,那么我们依据ISP原则将它们分开定义在两个代表两个不同概念的抽象类里面,定义的方式有三种:
1、两个都使用抽象类来定义。
2、两个都使用接口来定义。
3、一个使用抽象类定义,一个使用接口定义。
由于java不支持多继承所以第一种是不可行的。后面两种都是可行的,但是选择何种就反映了你对问题域本质的理解。
如果选择第二种都是接口来定义,那么就反映了两个问题:1、我们可能没有理解清楚问题域,AlarmDoor在概念本质上到底是门还报警器。2、如果我们对问题域的理解没有问题,比如我们在分析时确定了AlarmDoor在本质上概念是一致的,那么我们在设计时就没有正确的反映出我们的设计意图。因为你使用了两个接口来进行定义,他们概念的定义并不能够反映上述含义。
第三种,如果我们对问题域的理解是这样的:AlarmDoor本质上是Door,但同时它也拥有报警的行为功能,这个时候我们使用第三种方案恰好可以阐述我们的设计意图。AlarmDoor本质是们,所以对于这个概念我们使用抽象类来定义,同时AlarmDoor具备报警功能,说明它能够完成报警概念中定义的行为功能,所以alarm可以使用接口来进行定义。如下:
abstract class Door{
abstract void open();
abstract void close();
}
interface Alarm{
void alarm();
}
class AlarmDoor extends Door implements Alarm{
void open(){}
void close(){}
void alarm(){}
}
用于判断对象的具体类型,只能用于引用类型判断 a instanceof Cat
通常在向下转型前进行健壮性判断
成员变量 编译时:参照引用变量所属类,没有就报错 编译和运行都看左边 成员函数 编译时:参考引用类中是否有,没有就报错 编译看左边,运行看右边 静态函数 多态是对象的多态,静态函数不涉及对象,跟到类走 编译和运行都看左边