Java | 多态
Java的三大特性
java是一个面向对象的语言,所以java也有面向对象语言的三大特性:继承,封装,多态,任何一个java项目,都会用到这三种特性,所以掌握好这三大特性非常的重要。
多态 (polymorphism)
多态指的是同一个方法调用,由于对象不同可能会有不同的行为,比如,现实生活中同一个方法,有不同的具体实现。
多态的特点
- 多态是方法的多态,属性没有多态。
- 多态的存在要有3个必须条件:继承,方法重写,父类引用指向子类对象。
- 父类引用指向子类对象后,该父类引用调用子类重写方法,比时多态就出现了。
public class Animal {
public void call() {
System.out.println("叫----");
}
public static void main(String[] args) {
Animal a1 = new Animal();
a1.call();
//父类引用指向子类对象
Animal a2 = new Cat();
a2.call(); //输出:喵喵喵喵喵!!!
//父类引用指向子类对象
Animal a3 = new Dog();
a3.call(); //输出:汪汪汪汪汪!!
}
}
class Cat extends Animal{
//重写父类的call方法
@Override
public void call() {
System.out.println("喵喵喵喵喵!!!");
}
}
class Dog extends Animal{
//重写父类的call方法
@Override
public void call() {
System.out.println("汪汪汪汪汪!!");
}
}
上面就是多态的使用,就是父类的引用指向子类对象。
向上转型
父类的引用指向子类对象,这个就是向上转型,是自动类型转换。
向上转型后的父类引用变量只能调用它编译类型的方法,不能调用它运行时类型的方法,如果要调用子类里面别的方法,只能强制向下转型。上面的代码就是向上转型
向下转型
在子类对象里面有自己的方法,但是引用是父类对象,所以如果想要使用子类的独有方法,必须要转为子类的类型,所以要强制转型,这就是向下转型。
下面就是向下转型:
在cat里面加上一个独有的方法,然后调用这个方法
public class Animal {
public void call() {
System.out.println("叫----");
}
public static void main(String[] args) {
Animal a1 = new Animal();
a1.call();
//父类引用指向子类对象
Animal a2 = new Cat();
a2.call(); //输出:喵喵喵喵喵!!!
//强制类型转换,从而可以调用cat里面的独有方法
Cat cat = (Cat)a2;
cat.eat();
//父类引用指向子类对象
Animal a3 = new Dog();
a3.call(); //输出:汪汪汪汪汪!!
}
}
class Cat extends Animal{
//重写父类的call方法
@Override
public void call() {
System.out.println("喵喵喵喵喵!!!");
}
//添加的一个新的方法
public void eat() {
System.out.println("吃猫儿粮!");
}
}
向下转型的过程中,必须将保证子类继承父类,然后才可以强制转型,不然会报类型转换异常。
多态的内存模型:
在创建子类对象的时候,会调用构造方法,而构造方法的第一句话永远都是super();来调用父类的构造方法,父类的构造方法调用他的父类的构造方法,一直到object类为止。到现在,他们所有的类的地址都是指向子类的,所以不管再怎么向上转型,向下转型,都是调用的是子类的对象地址,只是在调用的时候,如果子类里面没有该方法,会自动去父类里面找。
下面有一个小例子:
public class HttpServlet {
//父类里面建两个方法
public void service() {
System.out.println("HttpServlet.service()");
doGet();
}
public void doGet() {
System.out.println("HttpServlet.doGet()");
}
}
//子类里面继承一个方法
public class MyServlet extends HttpServlet{
@Override
public void doGet() {
System.out.println("MyServlet.doGet()");
}
}
//下面测试
public class Test {
public static void main(String[] args) {
HttpServlet httpServlet = new MyServlet();
httpServlet.service();
}
}
//输出的结果:
//HttpServlet.service()
//MyServlet.doGet()
原因是因为httpServlet再调用service()的时候,会隐性的传过去一个this,和一个super,这两个第一个指的是当前对象,后面指的是父类,所以通过调用当前对象的父类的方法的时候,在方法里面再一次调用子类重写的方法的时候,会直接调用子类的方法,而不是调用父类的方法。
关注公众号,随时获取最新资讯
细节决定成败!
个人愚见,如有不对,恳请斧正!