在上海乐字节学习Java的第十五天
Java多态(上)
多态意味着允许不同类的对象对同一消息做出不同的响应
编译时多态(设计时多态,一般为方法重载)
运行时多态(程序运行时动态决定调用哪个方法)
必要条件:
满足继承关系
父类引用指向子类对象
从一定角度来看,封装和继承几乎都是为多态准备的
现实中,多态的例子数不胜数
动物们都有吃东西、跑、跳、叫的方法,不同的动物表现方式不同
类型转换向上转型(Upcast):将子类型转换为父类型
隐式/自动类型转换,是小类型到大类型的转换
对于向上的类型转换,不需要显示指定,即不需要加上前面的小括号和父类类型名
向下转型(Downcast):将父类型转换为子类型
将一个指向子类对象的父类引用赋值给一个子类的引用
强制类型转换,是大类型到小类型
父类型的引用必须指向转型的子类的对象,即指向谁才能转换谁。不然也会编译出错
通过instanceof运算符,来解决引用对象的类型,避免类型转换的安全性问题,提高代码的强壮性
注意
父类引用指向子类实例时,可以调用子类重写父类的方法以及直接继承父类的方法,无法调用子类的特有的方法
静态static方法属于特殊情况,静态方法只能继承,不能重写。调用的时候用谁的引用,则调用谁的版本
代码实现
Animal类
package com.SH.animal;
//抽象类:不允许实例化,可以通过向上转型,指向子类实例
public abstract class Animal {
//属性:昵称、年龄
private String name;
private int month;
public Animal(){
}
public Animal(String name,int month){
this.name=name;
this.month=month;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
//方法:吃东西
//抽象方法:不允许包含方法体;子类中需要重写父类的抽象方法,否则,子类也是抽象类
//static final private不能与abstract并存
public abstract void eat();
public static void say(){
System.out.println("动物间打招呼");
}
}
Cat类
package com.SH.animal;
public class Cat extends Animal {
//属性:体重
private double weight;
public Cat(){
}
public Cat(String name,int month,double weight){
super(name,month);
// this.setMonth(month);
this.weight=weight;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
//方法:跑动
public void run(){
System.out.println("小猫快乐的奔跑");
}
//方法:吃东西(重写父类方法)
@Override
public void eat() {
System.out.println("猫吃鱼~~");
}
public static void say(){
System.out.println("小猫碰胡须");
}
public void playBall() {
// TODO Auto-generated method stub
System.out.println("小猫喜欢玩线球");
}
Dog类
package com.SH.animal;
public class Dog extends Animal{
//属性:性别
private String sex;
public Dog(){
}
public Dog(String name,int month,String sex){
this.setMonth(month);
this.setName(name);
this.setSex(sex);
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
//方法:睡觉
public void sleep(){
System.out.println("小狗有午睡的习惯");
}
//方法:吃东西(重写父类方法)
@Override
public void eat() {
System.out.println("狗吃肉~~");
}
}
Test类
package com.SH.test;
import com.SH.animal.Animal;
import com.SH.animal.Cat;
import com.SH.animal.Dog;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
// Animal one=new Animal();//1
向上转型、隐式转型、自动转型
父类引用指向子类实例,可以调用子类重写父类的方法以及父类派生的方法,无法调用子类独有方法
注意:父类中的静态方法无法被子类重写,所以向上转型之后,只能调用到父类原有的静态方法
小类转型为大类
*/
Animal two=new Cat();//2
two.say();
Cat cat=(Cat)two;
cat.say();
Cat cat=new Cat();
two=cat;
Animal three=new Dog();//3
one.eat();
two.eat();
two.setMonth(2);
two.getMonth();
two.run();
three.eat();
System.out.println("=================");
/*向下转型、强制类型转换
* 子类引用指向父类对象,此处必须进行强转,可以调用子类特有的方法
* 必须满足转型条件才能进行强转
* instanceof运算符:返回true/false
*/
if(two instanceof Cat){
Cat temp=(Cat)two;
temp.eat();
temp.run();
temp.getMonth();
System.out.println("two可以转换为Cat类型");
}
if(two instanceof Dog){
Dog temp2=(Dog)two;
temp2.eat();
temp2.sleep();
temp2.getSex();
System.out.println("two可以转换为Dog类型");
}
if(two instanceof Animal){
System.out.println("Animal");
}
if(two instanceof Object){
System.out.println("Object");
}
类型转换案例
Master类
package com.SH.animal;
public class Master {
喂宠物
喂猫咪:吃完东西后,主人会带着去玩线球
喂狗狗:吃完东西后,主人会带着狗狗去睡觉
养兔子、养鹦鹉、养乌龟
方案1:编写方法,传入不同类型的动物,调用各自的方法
public void feed(Cat cat){
cat.eat();
cat.playBall();
public void feed(Dog dog){
dog.eat();
dog.sleep();
方案2:编写方法传入动物的父类,方法中通过类型转换,调用指定子类的方法
public void feed(Animal obj){
obj.eat();
if(obj instanceof Cat){
Cat temp=(Cat)obj;
temp.playBall();
}else if(obj instanceof Dog){
Dog temp=(Dog)obj;
temp.sleep();
}
饲养何种宠物
空闲时间多:养狗狗
空闲时间不多:养猫咪
方案1:
public Dog hasManyTime(){
System.out.println("主人休闲时间比较充足,适合养狗狗");
return new Dog();
public Cat hasLittleTime(){
System.out.println("主人平时比较忙碌,适合养猫咪");
return new Cat();
方案2:
public Animal raise(boolean isManyTime){
if(isManyTime){
System.out.println("主人休闲时间比较充足,适合养狗狗");
return new Dog();
}else{
System.out.println("主人平时比较忙碌,适合养猫咪");
return new Cat();
}
MasterTest类
package com.SH.test;
import com.SH.animal.Animal;
import com.SH.animal.Cat;
import com.SH.animal.Dog;
import com.SH.animal.Master;
public class MasterTest {
public static void main(String[] args) {
Master master=new Master();
Cat one=new Cat();
Dog two=new Dog();
master.feed(one);
master.feed(two);
System.out.println("=============");
boolean isManyTime=false;
Animal temp=master.raise(isManyTime);
if(isManyTime){
temp=master.hasManyTime();
}else{
temp=master.hasLittleTime();
System.out.println(temp);
}
抽象类&抽象方法
应用场景:
某个父类只是知道其他子类应该包含怎样的方法,但无法准确知道这些子类如何实现这些方法
abstract定义抽象类
抽象类不能直接实例化,只能被继承,可以通过向上转型完成对象实例
abstract定义抽象方法,不需要具体实现
包含抽象方法的类是抽象类
抽象类中可以没有抽象方法
子类如果没有重写父类所以抽象方法,则也要定义为抽象类
abstract不能与 static、final、private共存
抽象方法在子类实现时访问权限必须大于等于父类方法