目录
面向对象的特征三:多态性
1. 多态的概念:通俗来说,就是多种形态,那么在Java中,就是去完成某个行为,当不同的对象去完成时会产生不同的状态和表现。
2.在Java中要实现多态,那么必须要满足以下几个条件,缺一不可:
必须在继承体系下;
子类必须要对父类中的方法进行重写;
通过父类的引用调用重写的方法;
3.Java中多态性的体现:
子类对象的多态性:父类的引用指向子类的对象。(或子类的对象赋给父类的引用)比如:
Person p2 = new Man();//Man是Person的子类
4.多态性的应用:
多态性的应用:虚拟方法调用在多态的场景下,调用方法:
编译时,认为方法是左边的父类的类型的方法(即被重写的方法)
执行时,实际执行的是子类重写父类的方法。简称为:编译看左边,运行看右边。
public class Animal {
String name;
int age;
public Animal(String name,int age){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(name+"吃饭");
}
}
public class Cat extends Animal{
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(name+"吃老鼠");
}
}
public class Dog extends Animal{
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(name+"吃肉骨头");
}
}
//分割线
public class TestAnimal {
//编译器在编译代码的时候,并不知道要调用Dog还是Cat中eat的方法
//等程序运行起来之后,形参a引用的具体对象确定后,才知道调用哪个方法
//此时要注意:此处的形参类型必须是父类类型才可以,也就是向上转型
public static void eat(Animal animal){
animal.eat();
}
public static void main(String[] args){
Cat cat = new Cat("笨笨",2);
Dog dog = new Dog("问问",1);
eat(cat);
eat(dog);
}
}
5.多态的好处与弊端
弊端:
在多态的场景下,我们创建了子类的对象,也加载了子类特有的属性和方法。但是由于声明为父类的引用,导致我们没有办法直接调用子类特有的属性和方法。
好处:
极大的减少了代码的冗余,不需要定义多个重载的方法。
多态的向下转型
因为多态,就一定会有把子类对象赋值给父类变量的时候,这个时候,在编译期间,就会出现类型转换的现象。
但是,使用父类变量接收了子类对象之后,我们就不能调用子类拥有,而父类没有的方法了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做类型转换,使得 编译通过。
//向下转型
Man m1=(Man)p1; m1.earnMoney();
System.out.println(m1isSmoking);
System.out.println(p1==m1);
/*向下转型可能会出现:类型转换异常(ClassCastException)* */
Person p2=new Woman();
// Man m2 = (Man)p2;
// m2.earnMoney();
/*
*1.建议在向下转型之前,使用instanceof进行判断,避免出现类型转换异常*2.格式:ainstancefA:判断对象a是否是类A的实例。
* */
if(p2 instanceof Man){
Man m2 = (Man)p2;
m2.earnMoney();
/*
*1.建议在向下转型之前,使用instanceof进行判断,避免出现类型转换异常
*2.格式:a instanceofA:判断对象a是否是类A的实例。
*3.如果a instanceof A 返回true则:
a instanceofsuperA 返回也是true。其中,A是superA的子类。
* */
if(p2 instanceof Man){
Man m2 = (Man)p2; m2.earnMoney();}
if(p2 instanceof Woman){
System.out.println("Woman");}
if(p2 instanceof Person){
if(p2 instanceof Object){
}
equals()方法
equals()方法是用来判断其他的对象是否和该对象相等。
equals()方法在object中定义:
public boolean equals(Object obj) {
return (this == obj);
}
上边我们很明显看出是比较2个对象引用地址是否相同,但是我们平时在调用String、Integer等封装类型时的equals方法时是比较的内容是否一致而不是地址一致,如果是地址一致,那所有的String比较都是相等的,所以封装类型都重写了equals方法。
public boolean equals(Object anObject) {
//判断是否为同一个值,如X=X
if (this == anObject) {
return true;
}
//判断是否为String对象
if (anObject instanceof String) {
String anotherString = (String)anObject;
//此处value是String类中定义的当前调用此方法的String转换成的char数组
int n = value.length;
//判断调用String的char数组和比较String的char数组长度是否一致
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
//循环判断每个字符是否一致
while (n– != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
toString方法
Java默认的toString方法来自Object类
在没有重写toString
的前提下,每次执行System.out.println(对象引用)
,这个方法就会默认调用一个继承来自Object类型对象的toString方法。其打印出来的是一个引用数据的地址。
重写toString()方法意义:
重写toString()
可以理解为是对对象打印输出时候的一种格式化。这样符合业务逻辑,显示结果人性化。
public final class Integer extends Number implements Comparable<Integer> {
public String toString() {
return toString(value);
}
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
}