多态性的使用
当调用父类同名同参的方法时,实际上是执行的是子类重写父类的方法(虚拟方法调用)
利用如下类进行示范
public class Person
{
private String name;
private int age = 1;
private boolean isMale;
public void eat()
{
System.out.println("人可以吃饭");
}
public void sleep()
{
System.out.println("人可以睡觉");
}
public void talk(String language)
{
System.out.println("人可以说话,使用的是:"+language);
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public boolean isMale() {
return isMale;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setMale(boolean male) {
isMale = male;
}
};
class Chinese extends Person{
private String nation;
public void setNation(String nation) {
this.nation = nation;
}
public String getNation() {
return nation;
}
public void sleep()
{
System.out.println("中国人会睡觉");
}
public void eat()
{
System.out.println("中国人会睡觉");
}
public void talk(String language)
{
System.out.println("中国人可以说话,说的是"+ language);
}
}
测试代码如下
public class Persontext
{
public static void main(String[] args)
{
Chinese c1 = new Chinese();
c1.sleep();
c1.eat();
System.out.println("******************************");
Person p1=new Person();
p1.sleep();
p1.eat();
System.out.println("******************************");
Person p2=new Chinese();
p2.sleep();
p2.eat();
}
};
结果如下
明明是声明为Person类的对象,却是new了一个Chinese,也可以调用Chinese中重写的方法,但是不可以调用Person中没有的属性和方法,Chinese中之后定义的属性和方法,比如说在本例中,p2如果不进行强制转化,就不可以利用setNation和getNation,也不可以直接引用nation这个属性
本质上p2依旧是Person类,仅仅是能利用重写的方法
但是在编译期间,其实本质上Person类依旧是加载的Person类里面自己声明的方法,但是在运行期间就会使用Chinese中对同名方法的重写
编译就看左边,运行要看右边
多态性使用前提
1、有类的继承关系
2、有方法的重写
子类中定义了父类同名同参的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给他不同子类的对象,动态调用子类的方法
多态是运行时行为,编译的时候不体现多态(动态绑定)
重载是早绑定,重写是晚绑定
在这里额外提一下重载和重写
重载在编译的时候,已经确定了要执行的方法,但是重写的方法要在运行的时候才能确定,如果是晚绑定,才能体现多态性,早绑定并不是多态性
instanceof函数
x instanceof A:检验x是否是类A的对象(x为对象,A为类),返回值为boolean类型的数据
public class Persontext
{
public static void main(String[] args) {
Chinese c1 = new Chinese();
Person p1 = new Person();
Person p2 = new Chinese();
System.out.println(p1 instanceof Chinese);
System.out.println(c1 instanceof Person);
System.out.println(p2 instanceof Chinese);
}
};
结果
可以看出来,在这里c1可以是Person的对象,因为Chinese和Person子父类关系,但是p1不可能是Chinese的对象,因为Person是Chinese的父类,但是由于p2利用了多态性,所以p2也可以说是Chinese的对象
如果父类想要强行调用子类特有的属性和方法,就需要提到另一个方法
强制转化
为了使用向下转型,防止出现异常,在转型之前先进行instanceof的判断,但是仍有一个问题,无法判断谁是谁的父类
比如
public class Persontext
{
public static void main(String[] args) {
Chinese c1 = new Chinese();
System.out.println(c1 instanceof Chinese);
System.out.println(c1 instanceof Person);
}
};
结果
如此图,二者的结果都是true,根本上我们是由于创建的过程才知道的Person是Chinese的父类,但是如果只看instanceof返回的结果,我们仍然无法对子父类关系进行精准的判断 ,而这里还有一个误区就是关于“==”这个符号在对象的比较中,实际上是比较二者的地址,并不能起到什么实质性的作用
Object类
1、Object类是根父类,如果一个类没有声明父类,那么默认它的父类是Object类
2、getClass(),getSuperclass()可以获取类的父类
public class Persontext
{
public static void main(String[] args) {
Chinese c1 = new Chinese();
Person p1 = new Person();
System.out.println(c1.getClass());
System.out.println(p1.getClass());
}
};
结果如下
3、Object类中的方法具有通用性, Object类没有属性
4、 Object类只声明了一个空参构造器
此处区分一个函数和“==”
“==”
是一个运算符,在基本数据类型和引用数据类型中都可以使用(boolean不可以使用)
而且“==”会对基本数据类型进行自动提升
1、“==”比较基本数据类型的时候,会比较其中所存的数据是否相等
2、“==”一旦比较引用类型的话,只会比较地址值是否相等
equals()方法的使用
equals()只适用于引用数据类型
1、 Object类中对equals()的的定义与“==”符号的作用相同,都是比较地址值
public class Persontext
{
public static void main(String[] args) {
Chinese c1 = new Chinese();
Chinese c2 = new Chinese();
System.out.println(c2.equals(c1));
//由于两者实际上地址一定是不同的,所以此处就会返回flase
c1=c2;
//之前说过对于对象而言,“==”是传址操作,所以这里就是把c2的地址赋给了c1
System.out.println(c2.equals(c1));
//在这里再次判断的时候,结果就是true
}
};
2、像String、Date、File、包装类中都重写了 Object类中的 equals()方法
3、如果直接调用那就是比较地址值,如果想使用equals()去比较实体内容的话,就要将equals()重写,但是目前的部分编译器对与equals()是可以自动生成的