目录
一、接口
1.1接口的概念
1.2接口的声明&多继承性
1.3接口实现类
1.3.1接口实现类的概念
二、多态 (polymorphic)
2.1什么是多态
2.2多态的作用
2.3多态的使用
2.4多态注意事项
接口是一种约束,一种规范,是多个抽象方法的集合,仅定义了有哪些功能,本身不实现功能,具体实现,还是交给实现类完成。
接口中的方法是抽象方法,并不提供功能实现,体现了规范和实现相分离的思想,也体现了组件之间
低耦合的思想。
所谓耦合度,表示组件之间的依赖关系。依赖关系越多,耦合性越强,同时表明组件的独立性越差,
在开发中往往提倡降低耦合性,可提高其组件独立性,举一个低耦合的例子。
电脑的显卡分为集成显卡和独立显卡:
n 集成显卡:显卡和主板焊死在一起,显卡坏了,只能换主板
n 独立显卡:显卡和主板相分离,显卡插到主板上即可,显卡坏了,只换显卡,不用换主板
接口也体现的是这种低耦合思想,接口仅仅提供方法的定义,却不提供方法的代码实现。那么得专门
提供类并去实现接口,再覆盖接口中的方法,最后实现方法的功能,在多态案例中再说明。
接口可以看成一个特殊的类,声明类我们一般用class,而声明接口用interface关键字。
public interfance 接口名{ 抽象方法1();抽象方法2();抽象方法3();}
接口表示某些功能的事务,接口名使用名词,也有人习惯以I开头
public interface Iwalkable{
public static void walk();
}//接口中public static 是默认的所以可以写成
public interfance Iwalkable{
void walk();
}
类可以继承类,但是只能单继承的,接口也可以继承接口,但是却可以继承多个接口,也就是说一个
接口可以同时继承多个接口,如两栖动物可以行走也可以拥有。
可行走规范
public interface IWalkable {
void walk();
}
可游泳规范:
public interface ISwimable {
void swim();
}
两栖动物规范,即可以游泳,又可以行走。
public interface IAmphibiable extends IWalkable,ISwimable{
}
此时子接口能继承所有父接口的方法。
和抽象类一样接口是不能创建对象的,必须定义一个类去实现接口,并覆盖接口中的方法,这个类称为实现类,这个借口与类的关系称为实现关系。(implements)。
public class 类名 implements 接口1,接口2{覆盖接口中的抽象方法}
在类实现接口后,覆盖接口中的抽象方法,完成功能代码,此时接口和实现类之间的关系:
n 接口:定义多个抽象方法,仅仅定义有哪些功能,却不提供实现。
n 实现类:实现接口,覆盖接口中抽象方法,完成功能具体的实现。
/**
* 1 和抽象类一样,接口是不能创建对象的,此时必须定义一个类去实现接口,并实现接口中的方法,这
个类称之为实现类,类和接口之间的关系称之为实现关系(implements)。
* 2 一个类只能继承一个类,但是一个类可以实现多个接口。
*
* 3 抽象类和接口区别?
* 1)抽象类中可以有实现的方法,而接口中所有方法都不能实现。 jdk1.8以前
* 2)如果继承了抽象类就不能再继承其他类了,但是如果是接口可以多实现接口,还能继承其他类
* 更灵活,那是不是抽象就没用呢? 不是,使用场景都是不一样的!
* ①抽象类是大部分已经实现,少数没用必要再父类实现的时候使用
* ②接口是指定义规范,具体通通由实现类实现。
*
* Person实现IActable接口,所以Person类IActable的一个实现类。而且本案例中
* IActable又继承IRunable和IWalkable,也就是Person也是这两个接口的实现类。
*
*/
public class AImpl implements IC {
@Override
public void text() {
}
@Override
public void text01() {
}
@Override
public void text02() {
}
}
简单来说就是一种事务的多种形态
多态概念:将子类的对象装到父类的变量中保存(向上造型),当父类变量调用方法时,如果子类重写了该方法,就调用重写后的方法。(父类的变量可以装任意子类的对象)
//父类:
public class Animal {
int age = 1;
public void eat() {
System.out.println("吃....");
}
}
//子类:
public class Person extends Animal{
int age = 2;
@Override
public void eat() {
System.out.println("吃肉...");
}
public void coding() {
System.out.println("撸代码...");
}
}
public class Pig extends Animal{
int age = 3;
@Override
public void eat() {
System.out.println("吃白菜");
}
public void gongBaiCai() {
System.out.println("拱白菜");
}
}
//测试代码:
public class AnimalTest {
public static void main(String[] args) {
Animal animal = new Person();//多态的方式(向上造型/向上转型)
Animal animal2 = new Pig();//多态的方式(向上造型/向上转型)
//调用方法
animal.eat();//吃肉... 执行子类重写后的方法
animal2.eat();//吃白菜 执行子类重写后的方法
System.out.println(animal.age);//1 成员变量没有多态
// animal.gongBaiCai();//多态不能调用子类独有方法
}
}
可以屏蔽子类差异性(直接通过父类来调用,但是调用的子类复写的方法),提高代码的扩展性。
比如如果你直接低定义Person p = new Person(); //后面只能是Person,但是如果你以多态的方式来写
Animal a1 = new Person(); //扩展性强了,以后后面可以改成任意Animal的子类。
向上造型
语法:
父类类型 父类变量 = new 子类类型();
父类变量.方法();//子类若重写,则会执行子类重写后的方法
例如:
Animal animal = new Person();//多态的方式(向上造型/向上转型)
Animal animal2 = new Pig();//多态的方式(向上造型/向上转型)
//调用方法
animal.eat();//吃肉... 执行子类重写后的方法
animal2.eat();//吃白菜 执行子类重写后的方法
```
向下造型
例如:(接上面案例)
现在需要调用子类Person中特有的方法或者调用子类Pig中特有的方法,不能调用怎么办?
这个时候就需要强制转换(向下造型/向下转型):
强制转换(向下造型/向下转型)语法:
数据类型 变量 = (数据类型)值/变量;
在向下造型前,必须进行类型判断,需要判断当前父类变量中装的是哪一个子类类型的对象
类型判断方式1:
if(父类变量 instanceof 子类类型1){
//强制类型转换
子类类型1 子类变量 = (子类类型1)父类变量;
//现在就可以调用子类特有方法
子类变量.子类特有方法(...);
}else if(父类变量 instanceof 子类类型2){
//强制类型转换
子类类型2 子类变量 = (子类类型2)父类变量;
//现在就可以调用子类特有方法
子类变量.子类特有方法(...);
}...
------------------------------------------------------------
类型判断方式2:
if(父类变量.getClass() == 子类类型1.class){
//强制类型转换
子类类型1 子类变量 = (子类类型1)父类变量;
//现在就可以调用子类特有方法
子类变量.子类特有方法(...);
}else if(父类变量.getClass() == 子类类型2.class){
//强制类型转换
子类类型2 子类变量 = (子类类型2)父类变量;
//现在就可以调用子类特有方法
子类变量.子类特有方法(...);
}...
如果不进行类型判断再强转,就有可能发生ClassCastException类造型异常
测试类代码如下:
public class AnimalTest {
public static void main(String[] args) {
Animal animal = new Person();//多态的方式(向上造型/向上转型)
Animal animal2 = new Pig();//多态的方式(向上造型/向上转型)
animal = new Pig();//多态的方式(向上造型/向上转型)
//调用方法
animal.eat();
animal2.eat();
System.out.println(animal.age);//1 成员变量没有多态
//如果这里需要调用Pig类中特有方法,就需要将animal强转为Pig类型
//类型判断的方式1
if (animal instanceof Pig) {//判断animal中是不是装的Pig对象,如果是才强转
Pig pig = (Pig)animal;
//调用Pig特有方法
pig.gongBaiCai();
} else if (animal instanceof Person) {
//如果这里需要调用Person类中特有方法,就需要将animal强转为Person类型
Person person = (Person)animal;
//调用Person特有方法
person.coding();
}
//类型判断的方式2
if (animal.getClass() == Pig.class) {//判断animal中是不是装的Pig对象,如果是才强转
Pig pig = (Pig)animal;
//调用Pig特有方法
pig.gongBaiCai();
} else if (animal.getClass() == Person.class) {
//如果这里需要调用Person类中特有方法,就需要将animal强转为Person类型
Person person = (Person)animal;
//调用Person特有方法
person.coding();
}
}
}
-----------------------------------------------------------------------------------
多态案例2:
父类:
public class Vip {
/**
* 会员特权
*/
public void privilege() {
System.out.println("我有特权...");
}
}
子类:
public class Vip1 extends Vip{
/**
* 会员特权
*/
public void privilege() {
System.out.println("我是5000元俱乐部会员");
}
public void low() {
System.out.println("我很low");
}
}
public class Vip2 extends Vip{
/**
* 会员特权
*/
public void privilege() {
System.out.println("我是500000元俱乐部会员");
}
public void normal() {
System.out.println("我很一般");
}
}
public class Vip3 extends Vip{
/**
* 会员特权
*/
public void privilege() {
System.out.println("我是500000000000元俱乐部会员");
}
public void great() {
System.out.println("我很NB....");
}
}
测试类:
public class VipTest {
public static void main(String[] args) {
/*
* 模拟会员登陆的时候特权展示
*
*/
Vip vip = new Vip2();//屏蔽子类差异性
//调用特权
vip.privilege();//调用特权方法,如果子类重写了,会执行对应子类重写后的方法
//判断当前VIP中装的子类是哪一个,展示对应的特权
if (vip instanceof Vip1) {//类型判断
//强制转换
Vip1 vip1 = (Vip1)vip;
//调用特有方法
vip1.low();
}else if (vip instanceof Vip2) {//类型判断
//强制转换
Vip2 vip2 = (Vip2)vip;
//调用特有方法
vip2.normal();
}else if (vip instanceof Vip3) {//类型判断
//强制转换
Vip3 vip3 = (Vip3)vip;
//调用特有方法
vip3.great();
}
}
}
多态案例3:
父类:
public class Dog {
public void eat() {
System.out.println("吃...");
}
}
public class Husky extends Dog {
@Override
public void eat() {
System.out.println("狗粮..");
}
}
public class Teddy extends Dog {
@Override
public void eat() {
System.out.println("吃天吃地吃空气");
}
}
public class Tudog extends Dog {
@Override
public void eat() {
System.out.println("啃骨头。。。");
}
}
public class Person {
/*public void feedDog(Hasky dog) {
dog.eat();
}
public void feedDog(Teddy dog) {
dog.eat();
}
public void feedDog(Tudog dog) {
dog.eat();
}
如果有几万种狗,就需要写几万个方法喂狗,不可取
*/
public void feedDog(Dog dog) {//屏蔽子类差异性。写一个父类类型,所有的子类对象都可以接收
dog.eat();
}
}
测试类:
public class DogTest {
public static void main(String[] args) {
//测试喂狗案例
Hasky hasky = new Hasky();
Tudog tudog = new Tudog();
Teddy teddy = new Teddy();
Person person = new Person();
person.feedDog(hasky);
person.feedDog(tudog);
person.feedDog(teddy);
}
}
1. 成员变量没有多态
2. 不能调用子类特有的方法,如果需要调用子类特有的方法,必须进行强制类型转换(向下造型/向 下转型),向下造型需要进行子类类型判断
父类变量能点(调用)出哪些成员(成员变量和方法),是由当前类和其父类决定,优先从当前类 开始查找,直到找到Object了为止,如果Object中有没有,就不能调用
多态调用方法的优先级顺序为:(难度大)
该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。