接口的思想:
小节:
【向下转型的注意事项】
【转型总结】
多态方法调用注意:
举例:笔记本电脑,USB接口的故事。
1,接口的出现对功能是实现了扩展。
2,接口的出现定义了规则。
3,接口的出现降低了耦合性(解耦)。
接口的出现,完成了解耦,说明有两方,一方在使用这个规则,另一方在实现这个规则。
比如笔记本电脑使用这个规则,而外围设备在实现这个规则。
描述事物。
犬。按照功能分类。导盲犬,缉毒犬...
犬:
吼叫();
吃饭();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
abstract
class
犬
{
public
abstract
void
吼叫();
public
abstract
void
吃饭();
}
class
缉毒犬
extends
犬
{
public
void
吼叫(){}
public
void
吃饭(){}
public
void
缉毒(){}
}
//对于缉毒,有可能还有缉毒猪,具备者缉毒功能,应该将缉毒功能抽取。
//对缉毒进行描述。
abstract
class
缉毒
{
public
abstract
void
缉毒();
}
|
缉毒犬既需要犬的功能又需要缉毒的功能。
无法直接多继承。
是否可以多实现呢?可以的。
犬是接口,缉毒也是接口。缉毒犬多实现即可。
类负责描述的是事物的基本功能。接口负责描述事物的扩展功能。
缉毒犬是犬中一种。is a 关系,
将犬定义成类。而缉毒是犬的一个扩展功能。这时将缉毒定义接口。
这时描述就变成了这样:
1
2
3
4
5
6
7
8
9
10
11
|
interface
缉毒able
{
public
abstract
void
缉毒();
}
class
缉毒犬
extends
犬
implements
缉毒able
{
public
void
吼叫(){code..}
public
void
吃饭(){}
public
void
缉毒(){}
}
|
1,抽象类是描述事物的基本功能,可以定义非抽象的方法。
接口中定义只能是抽象方法,负责功能的扩展。
2,类与类之间是继承关系 is a关系。
类与接口之间是实现关系 like a 关系。
1
2
3
4
5
6
7
8
9
10
11
12
|
门
open();
close();
报警门。
class
门
{
}
interface
报警
{
}
|
多态:
【体现】
父类的引用或者接口的引用指向了自己的子类对象。
1
2
|
Dog d =
new
Dog();
//Dog对象的类型是Dog类型。
Animal a =
new
Dog();
//Dog对象的类型右边是Dog类型,左边Animal类型。
|
【好处】
提高了程序的扩展性。
【弊端】
通过父类引用操作子类对象时,只能使用父类中已有的方法,不能操作子类特有的方法。
【前提】
1,必须有关系:继承,实现。
2,通常都有重写操作。
【子类的特有方法如何调用呢?】
Animal a = new Dog();//Animal是父类型,new Dog()是子对象。
但是父类型引用指向子类对象时,这就是让子类对象进行了类型的提升(向上转型)。
向上转型好处:提高了扩展性,隐藏了子类型。弊端:不能使用子类型的特有方法。
如果要想使用子类的特有方法,只有子类型可以用。
可以向下转型,强制转换。
1
2
3
4
|
Animal a =
new
Dog();
a.eat();
Dog d = (Dog)a;
//将a转型为Dog类型。向下转型。
d.lookHome();
|
向下转型什么时候用?当需要使用子类型的特有内容时。
注意:无论向上还是向下转型,最终都是子类对象做着类型的变化。
Animal a = new Dog();
//Cat c = (Cat)a;向下转型因为不明确具体子类对象类型,所以容易引发ClassCastException异常。
所以为了避免这个问题,需要在向下转型前,做类型的判断。
判断类型用的是关键字 instanceof
1
2
3
4
5
6
7
8
9
10
11
|
if
(a
instanceof
Cat)
//a指向的对象的类型是Cat类型。
{
//将a转型Cat类型。
Cat c = (Cat)a;
c.catchMouse();
}
else
if
(a
instanceof
Dog)
{
Dog d = (Dog)a;
d.lookHome();
}
|
1,什么时候使用向上转型呢?
提高程序的扩展性,不关系子类型(子类型被隐藏)。
需要用子类的特有方法吗?不需要,哦了。向上转型。
2,什么时候使用向下转型呢?
需要使用子类型的特有方法时。
但是一定要使用 instanceof 进行类型的判断。避免发生 ClassCastException
如果Student类继承Person类,并且都存在eat方法
1
2
3
4
5
|
Person person=
new
Student();
person.eat();
//发现子类覆写了此方法,调用子类方法
person.study;
//父类没有此方法,编译失败;
Student student=(Student)person;
//person对象向下转型
student.study;
//子类对象有此方法,编译通过;
|
当子类对象向上转型后,调用方法时,先看父类对象有没有方法,有则在看子类是否覆写,覆写了调用子类方法,没有覆写调用父类方法,若父类没有此方法而子类有,则必须向下转型为子类类型,才能调用此方法,否则编译失败。