多态
- 多态的概述
事物存在的多种形态 - 多态的前提
a.要有继承关系
b.要有方法重写
c.要有父类引用指向子类对象
(设父类为animal,子类为cat
Animal a = new cat (); ) (此处为向上转型)
class Demo2_Polymorphic {
public static void main(String[] args) {
/*Father f = new Son(); //父类引用指向子类对象,实现向上提升
System.out.println(f.num);
Son s = new Son();
System.out.println(s.num);*/
Father f = new Son();
//f.print();
f.method(); //相当于是Father.method()
}
}
当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。
理解方法:使用子类构造方法创建一个父类对象:
对成员变量:
编译看左边,执行看左边。
当执行时如果子类没有父类对应重写方法,则自动继承父类方法。
对象的变量为父类对象,体现父类特征
对成员方法:
编译看左边父类有无此方法,保证编译通过,执行看右边子类方法。(动态绑定)
子类方法进栈运行
对静态方法:
编译看左边(父类),执行看左边(父类)
(静态和类相关 ,所以不算重写,依旧访问左边)
总结:
只有非静态成员方法,执行看右边
class Person{}
class SuperMan extands Person{}
Person p = new SuperMan(); //向上转型
SuperMan q= (SuperMan)p; //向下转型(强转)
q的地址=p的地址,但是能看到整个对象
两句代码合起来理解:
SuperMan q=new SuperMan();
多态的好处和弊端:
弊端:
不可使用子类特有属性与行为;
好处:
通过继承来保证提高代码维护性;
通过多态保证提高代码扩展性;应用于当作参数
public static void method(Animal a){
a.eat();
}
一般在开发中在创建对象时直接创建子类对象
关键字 instanseof
判断前边的引用是否是后面的数据类型
if(a instanceof Cat){
Cat c =(Cat)a;
//code
}
else if (a instanceof Dog){
Dog d= (Dog)a;
//code
}
else {
a.eat();
}
抽象类
抽象类和抽象方法必须用abstract关键字修饰
抽象类:
abstract class 类名{};
抽象方法写法:
public sabstract void 函数名();
抽象类不一定有抽象方法,有抽象方法的类一定是抽象类或者接口;
抽象类不能实例化,只能通过具体的子类来实例化,体现多态性。
抽象类的子类有:
1. 抽象类
2. 重写抽象类中的所有抽象方法
抽象类的成员特点
- 成员变量:abstract不可修饰成员变量
- 构造方法,有,用于父类访问数据初始化
- 成员方法:可以抽象可以非抽象。
当无法描述具体成员方法时使用抽象方法,在子类中对抽象方法进行重写
常见抽象类面试题
- 1.一个抽象类没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
可以,目的是不让其他类创建本类对象,交给子类完成。 - 2.abstract不可以和那些关键字共存?
abstract与static
被abstract修饰的方法没有方法体
被static修饰的可以用类名.调用,但是类名.调用抽象方法没有意义。
abstract与final
被abstract修饰的方法强制子类重写
被final
abstract与private
被abstract修饰是让子类看到并强制重写
被private修饰不让子类访问,所以二者矛盾接口
狭义:java中的interface
广义:对外提供规则的都是接口
接口表示方法
1.interface 接口名{} //接口中的方法都是抽象的
2.类实现接口用implement实现
class 类名 implements 接口名 {}
3.接口不能实例化 (父类引用指向子类对象)
按照多态的方式来实现
4.接口的子类
a.可以是抽象类
b.可以是具体类,要重写接口中的所有抽象方法(推荐)
接口成员特点
1.接口中的变量都是静态公共常量,公共抽象方法。
默认修饰符:public static final
2.构造方法:接口没有构造方法,接口没有属性
因为接口没有属性,所以接口可以作为不同类的父类来进行
interface Runable{
public abstract void run():
}
class Dog implements Runable{
public void run(){};
}
class Bus implements Runable{
public void run(){};
}
则可以使用:
Runable r =new Dog();
Runable p= new Bus();//两者都实现了run功能,所以接口Runable中的run被覆盖,且可以分别使用r,p中的run方法,但是要使用其他方法需要对r,p进行装箱操作
3.成员方法:只能是抽象方法
默认修饰符:public abstract
4.接口中的方法都是public abstract,
所有使用接口的类中的方法都是public
## 类,接口之间的关系
1.类与类之间是继承关系,只可单继承,可以多层继承
2.类与接口是实现关系
a.可以单实现,也可以多实现。
class Demo implements InterA,InterB{}
b.可以在继承一个类的同时实现多个接口
3接口与接口是继承关系,可以单继承或多继承
interface InterC extands InterB,InterC{};
抽象类与接口的区别
抽象类 | 接口 |
---|---|
成员变量可以是变量或常量 | 成员变量只可为常量 |
有构造方法 | 无构造方法 |
成员方法可抽象也可非抽象 | 成员方法只可抽象 |
关系区别:
类与类 | 类与接口 | 接口与接口 |
---|---|---|
继承 | 实现 | 继承 |
单继承 | 单实现 | 单继承 |
多实现 | 多继承 |
设计理念区别:
抽象类:定义继承体系中的共性功能
接口,定义继承体系的拓展功能
补充:父类调用指向子类对象
Animal a=new Cat();
Animal b=new Cat(5);
a.run();
System.out.println(a.getClass());
class Animal{
private int animal;
public void setAnimal(int animal) {
this.animal = animal;
}
public int getAnimal() {
return animal;
}
public void run(){
System.out.println("run.");
}
}
class Cat extends Animal{
@Override
public void setAnimal(int animal) {
super.setAnimal(animal);
}
@Override
public int getAnimal() {
return super.getAnimal();
}
public Cat(){
System.out.println("123");
}
public Cat(int a){
System.out.println("456");
}
public void run(){
System.out.println("running");
}
public void eat(){
System.out.println("eating");
}
}
结果:
123
456//可见,先调用父类构造,然后调用子类构造
running
class Cat