//父类
public class Animal {
protected String name;
protected int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name + "在吃东西...");
}
}
接下来再定义三个子类:Dog、Bied、Cat
java复制代码
//Bird
public class Bird extends Animal{
public Bird(String name , int age){
super(name,age);
}
public void eat(){
System.out.println(this.name + "在吃鸟粮");
}
}
java复制代码
//Cat
public class Cat extends Animal{
public Cat(String name, int age) {
super(name, age);
}
public void eat(){
System.out.println(this.name + "在吃猫粮");
}
}
java复制代码
public class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat(){
System.out.println(this.name + "在吃狗粮");
}
}
我们发现了,每个子类都有eat方法,但是全部都是独有的,因为每个动物的食物是不一样的.
这个时候,我们定义一个测试类来看看调用eat()方法会出现什么情况:
java复制代码
public class text_zoo {
public static void main(String[] args) {
Animal animal = new Animal("小黑",7);
Dog dog = new Dog("小白",1);
Cat cat = new Cat("花花",2);
Bird bird = new Bird("啾啾",3);
animal.eat();//调用父类的eat方法
dog.eat();//调用子类Dog的eat方法
cat.eat();//调用子类Cat的eat方法
bird.eat();//调子父类Bird的eat方法
}
}
//直接赋值
public class text_zoo {
public static void main(String[] args) {
Animal a1 = new Dog("小白", 1);
Animal a2 = new Cat("花花", 2);
a1.eat();
a2.eat();
}
}
变量 a1、a2 的编译时类型 是 Animal
但它实际指向的对象 是 Dog和Cat 类型
调用 a1.eat() 时,运行时 会执行 Dog 的 eat() 方法
3.2 参数传递
"父类引用指向子类对象"
java复制代码
public static void fun(Animal a){
a.eat();
}
public static void main2(String[] args) {
Dog dog = new Dog("小白",1);
Cat cat = new Cat("花花",2);
Bird bird = new Bird("啾啾",3);
fun(dog);
fun(cat);
fun(bird);
}
3.3 返回值传递
我们先正常定义子类,也适合上面的例子一样
java复制代码
//子类Dog
public class Dog extends Animal {
public Dog(String name,int age) {
super(name, age);
}
@Override
public void eat(){
System.out.println(this.name + "在吃狗粮...");
}
}
//子类Cat
public class Cat extends Animal{
public Cat(String name,int age) {
super(name, age);
}
public void eat(){
System.out.println(this.name + "在吃猫粮...");
}
}
//Cat
//注意!!!此时Cat是没有继承Animal的
public class Cat{
public void eat(){
System.out.println("在吃猫粮");
}
}
我们用测试类测试一下代码:
java复制代码
public class text_zoo {
public static void main(String[] args) {
Animal animal = new Animal("小黑",7);
Cat cat = new Cat();
animal.eat();//调用父类的eat方法
cat.eat();//调用子类Cat的eat方法
}
}
大家会发现,我们Cat的eat()方法并没有实现多态的效果
4.2子类必须重写父类方法
如果我们不进行重写的话,我们所调用的方法就一直都是父类的方法:
java复制代码
父类:Animal
public class Animal {
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name + "在吃东西...");
}
}
子类:Dog
public class Dog extends Animal {
public Dog(String name,int age) {
super(name, age);
}
}
java复制代码
public class text_zoo{
public static void main(String[] args) {
Animal animal = new Dog("xx",2);
animal.eat();
}
}
4.3 父类引用指向子类对象(向上转型)
使用父类引用来应用子类对象:
java复制代码
Animal animal = new Dog("xx",4);
animal.eat();
五、向上转型和向下转型
5.1 向上转型
5.1.1 向上转型的语法
向上转型:父类引用 引用 子类对象
java复制代码
父类 变量 = new 子类();
我们还是看一下之前的例子:
java复制代码
父类:Animal
public class Animal {
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(this.name + "在吃东西...");
}
}
java复制代码
子类:Dog
public class Dog extends Animal {
public Dog(String name,int age) {
super(name, age);
}
@Override
public void eat(){
System.out.println(this.name + "在吃狗粮...");
}
}
我们现在测试一下会怎么样:
java复制代码
public calss text_zoo{
public static void main(String[] args) {
Animal animal = new Dog("小黑",2);//向上转型
animal.eat();
}
}
这个时候就会调用我们子类的重写方法
5.1.2向上转型的三种场景
直接赋值:
java复制代码
public class xxx{
public static void main1(String[] args) {
//直接赋值
Animal animal = new Dog("小白",3);
animal.eat();
}
}
方法参数:
java复制代码
public class xxx{
public static void feed(Animal animal){
animal.eat();
}
public static void main(String[] args) {
//方法参数
feed(new Cat("小花",3));
}
}
方法返回值
java复制代码
public class xxx{
public static Animal getAnimal(String type) {
if ("cat".equals(type)){
return new Cat("喵喵",2);
}else{
return new Dog("汪汪",5);
}
}
static void main(String[] args) {
Animal animal = getAnimal("cat");//返回Dog,向上转型为Animal
}
}
5.1.2 向上转型的优势和局限
向上转型的优势:
代码更通用,可扩展性强
降低耦合度(两个模块(这里是类)的相互依赖程度,耦合度越高,依赖性越强) 向上转型的局限:
只能调用重写的方法无法调用子类独有的方法
对比一下下面这个代码就能看懂
5.2 向下转型
5.2.1 向下转型的语法
向下转型(Downcasting)是指:将一个父类类型的引用,强制转换为它实际所指向的子类类型。
java复制代码
子类名 变量 = (子类名) 父类引用;
我们先回顾一下向上转型的限制:只能调用重写的方法无法调用子类独有的方法
那么我们有没有什么方法来解决这个限制呢???
那么我们就可以使用我们的向下转型:
java复制代码
publc class xxx{
//向下转型
public static void main(String[] args) {
Animal animal = new Dog("小白",2);
if (animal instanceof Dog){
Dog dog = (Dog)animal;//强转成子类Dog,向下转型
dog.sleep();
}
}
}