前言
Java中使用类来对现实世界中的实体进行描述,类经过实例化之后的产物对象,就可以用来表示现实中的实体,但是现实世界错综复杂,事物之间可能会存在一些关联,那在设计程序时就需要考虑到继承问题。
一、继承
1.1 继承的定义
继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。
继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。
1.2 继承的语法结构
在Java中如果要表示类之间的继承关系,需要借助extends关键字。
语法结构如下:
修饰符 class 子类 extends 父类 {
// … 成员变量/成员 方法
}
1.3 继承的使用
//未使用继承,单独定义多个类
class Dog{
public String name;
public int age;
public String color;
public void eat(){
System.out.println(this.name + "正在进食");
}
public void bark(){
System.out.println(this.name + "正在吠叫");
}
}
class Cat{
public String name;
public int age;
public String color;
public void eat(){
System.out.println(this.name + "正在进食");
}
public void bark(){
System.out.println(this.name + "正在吠叫");
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "月饼";
dog.age = 1;
dog.color = "黄色";
dog.eat();
dog.bark();
System.out.println("=======================");
Cat cat = new Cat();
cat.name = "月亮";
cat.age = 2;
cat.color = "黑色";
cat.eat();
cat.bark();
}
}
结果如下
1.3.1 继承代码示例
//子类继承父类后达到了代码复用的效果,子类会继承父类中的成员方法和成员变量,但不会继承静态成员方法,静态成员变量。
//静态成员方法,静态成员变量 不属于对象所以无法继承。
class Animals{
public String name;
public int age;
public String color;
public void eat(){
System.out.println(this.name + "正在进食");
}
public void bark(){
System.out.println(this.name + "正在吠叫");
}
}
class Dog extends Animals{
public String sex;
}
class Cat extends Animals{
public void swap(){
System.out.println(this.name + "正在摇尾巴");
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "月饼";
dog.age = 1;
dog.color = "黄色";
dog.eat();
dog.bark();
System.out.println("=======================");
Cat cat = new Cat();
cat.name = "月亮";
cat.age = 2;
cat.color = "黑色";
cat.eat();
cat.bark();
}
}
结果如下
1.4 学习小贴士
- 子类会将父类中的成员变量或者成员方法继承到子类中。
- 子类继承父类之后,必须要新添加自己特有的成员(方法/变量),体现出与基类的不同,否则就没有必要继承。
二、父类成员访问
2.1 子类中访问父类的成员变量
2.1.1 子类和父类不存在同名成员变量(一)
class Base{
public int a;
public int b;
}
class Derived extends Base{
public int c;
public void method(){
a = 10;
b = 20;
c = 30;
}
}
public class Test {
public static void main(String[] args) {
Derived derived = new Derived();
derived.method();
System.out.println(derived.a);
System.out.println(derived.b);
System.out.println(derived.c);
}
}
结果如下
2.1.1 子类和父类不存在同名成员变量(二)
class Base{
public int a;
public int b;
}
class Derived extends Base{
public int c;
{
a = 10;
b = 20;
c = 30;
}
}
public class Test {
public static void main(String[] args) {
Derived derived = new Derived();
System.out.println(derived.a);
System.out.println(derived.b);
System.out.println(derived.c);
}
}
结果如下
2.1.2 子类和父类存在同名成员变量(一)
//子类和父类存在同名成员变量时,局部变量优先
class Base{
public int a = 2;
public int b = 5;
}
class Derived extends Base{
public int c = 4;
public int a = 1;
public int b = 2;
public void method(){
System.out.println(this.a);//打印的是子类的成员变量
System.out.println(this.b);
System.out.println(this.c);
}
}
public class Test {
public static void main(String[] args) {
Derived derived = new Derived();
derived.method();
}
}
结果如下
2.1.2 子类和父类存在同名成员变量(二)
//子类和父类存在同名成员变量时,使用super访问父类
class Base{
public int a = 2;
public int b = 5;
}
class Derived extends Base{
public int c = 4;
public int a = 1;
public int b = 2;
public void method(){
System.out.println(this.a);//打印的是子类的成员变量
System.out.println(this.b);//打印的是子类的成员变量
System.out.println(this.c);
System.out.println(super.a);//打印的是父类的成员变量
System.out.println(super.b);//打印的是父类的成员变量
}
}
public class Test {
public static void main(String[] args) {
Derived derived = new Derived();
derived.method();
}
}
结果如下
2.1.2 子类和父类存在同名成员变量(三)
//子类和父类存在同名成员变量时,使用super访问父类
class Base{
public int a = 2;
public int b = 5;
public int d = 5;
}
class Derived extends Base{
public int c = 4;
public int a = 1;
public int b = 2;
public void method(){
System.out.println(this.a);
System.out.println(this.b);
System.out.println(this.c);
System.out.println(super.a);//2
System.out.println(super.b);//5
System.out.println("=====================");
System.out.println(this.a);//1
System.out.println(this.b);//2
System.out.println(this.c);//4
System.out.println(this.d);//5
}
}
public class Test {
public static void main(String[] args) {
Derived derived = new Derived();
derived.method();
}
}
结果如下
2.1.2 子类和父类存在同名成员变量(四)
class Animals{
public String name;
public int age;
public String color;
public Animals(){
}
public Animals(String name){
this.name = name;
}
public void eat(){
System.out.println(this.name + "正在进食");
}
public void bark(){
System.out.println(this.name + "正在吠叫");
}
}
class Dog extends Animals{
public Dog(){
super();
}
public Dog(String name){
super(name);
}
public String sex;
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
}
}
结果如下
2.2 学习小贴士
1、当子类继承父类的成员方法和成员变量时,如果子类和父类中有同名的成员变量时,this优先访问子类中的成员变量和成员方法,如果想要访问父类就需要使用关键字super。
2、如果子类和父类中没有同名的成员变量和成员方法时,this可以直接调用子类和子类继承到的成员方法和成员变量。
总结:在子类方法中 或者 通过子类对象访问成员时:
如果访问的成员变量子类中有,优先访问自己的成员变量。
如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
如果访问的成员变量与父类中成员变量同名,则优先访问自己的。
成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。
通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到
则访问,否则编译报错。
通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错;
与this相似的,super只能在非静态方法中使用。且需要在子类方法中,才能访问父类的成员变量和方法。
三、子类构造方法
在子类构造方法中,并没有写任何关于基类构造的代码,但是在构造子类对象时,先执行基类的构造方法,然后执行子类的构造方法。因为:子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。所以在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整 。
3.1 子类构造方法代码示例(一)
class Animal{
public String name;
public int age;
public String color;
public Animal(){
}
public void eat(){
System.out.println(name + "正在吃粮");
}
public void swap(){
System.out.println(name + "正在摇尾巴");
}
}
class Dog extends Animal{
{
name = "初一";
age = 1;
}
public void wangWang(){
System.out.println(name + "正在汪汪叫");
}
public Dog() {
super();
System.out.println("姓名:" + name + " 年龄" + age);
}
}
class Cat extends Animal{
public void miMi(){
System.out.println(name + "正在喵喵叫");
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
Cat cat = new Cat();
}
}
结果如下
3.1 子类构造方法代码示例(二)
class Animal{
public String name;
public int age;
public String color;
public Animal(){
}
public Animal(String name) {
this.name = name;
}
public Animal(int age) {
this.age = age;
}
public Animal(String name,String color){
this.name = null;
this.color = color;
}
public void eat(){
System.out.println(name + "正在吃粮");
}
public void swap(){
System.out.println(name + "正在摇尾巴");
}
}
class Dog extends Animal{
public void wangWang(){
System.out.println(name + "正在汪汪叫");
}
{
name = "初一";
age = 19;
}
public Dog() {
super();
}
public Dog(String name) {
super(name);
}
public Dog(int age) {
super(age);
}
public Dog(String name,String color) {
super(name,color);
}
}
class Cat extends Animal{
{
name = "初二";
age = 10;
}
public Cat() {
super();
}
public Cat(String name) {
super(name);
}
public void miMi(){
System.out.println(name + "正在喵喵叫");
}
public Cat(String name,String color) {
super(name,color);
}
public Cat(int age) {
super(age);
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat();
dog.swap();
System.out.println("=============");
Cat cat = new Cat();
cat.eat();
cat.miMi();
}
}
结果如下
3.1 子类构造方法的使用
学习小贴士:
- 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构
造方法。 - 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的
父类构造方法调用,否则编译失败。 - 在子类构造方法中,super(…)调用父类构造时,必须是子类构造函数中第一条语句。
- super(…)只能在子类构造方法中出现一次,并且不能和this同时出现
四、this 和 super 的区别
super和this都可以在成员方法中用来访问:成员变量和调用其他的成员函数,都可以作为构造方法的第一条语 句,那他们之间有什么区别呢?
【相同点】
- this 和 super都是Java中的关键字
- this 和 super只能在类的非静态方法中使用,用来访问非静态成员方法和字段
- 在构造方法中调用时,this( ) 和 super( )必须是构造方法中的第一条语句,且不能同时存在。
【不同点】
- this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员。
- 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性。
- 在构造方法中:this(…)用于调用本类构造方法,super(…)用于调用父类构造方法,两种调用不能同时在构造 方法中出现。
- 构造方法中一定会存在super(…)的调用,用户没有写编译器也会增加,但是this(…)用户不写则没有。
五、继承当中的初始化顺序
5.1 基类初始化顺序代码示例(一)
class Animal{
public String name;
public int age;
public String color;
static {
System.out.println("Animal的静态代码块");
}
{
System.out.println("Animal的实例代码块");
}
public Animal(String name,int age,String color){
this.name = name;
this.age = age;
this.color = color;
System.out.println("姓名:" + name + " 年龄:" + age + " 颜色:" + color);
}
public void eat(){
System.out.println(name + "正在吃粮食");
}
public void swap(){
System.out.println(name + "正在摇尾巴");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Animal("Animal",1,"黑色");
animal.eat();
animal.swap();
}
}
结果如下
5.1 基类初始化顺序代码示例(二)
class Animal{
public String name;
public int age;
public String color;
static {
System.out.println("Animal的静态代码块");
}
{
System.out.println("Animal的实例代码块");
}
public Animal(String name,int age,String color){
this.name = name;
this.age = age;
this.color = color;
System.out.println("姓名:" + name + " 年龄:" + age + " 颜色:" + color);
}
public void eat(){
System.out.println(name + "正在吃粮食");
}
public void swap(){
System.out.println(name + "正在摇尾巴");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Animal("Animal",1,"黑色");
animal.eat();
animal.swap();
System.out.println("==========================");
Animal animal1 = new Animal("Animal1",2,"白色");
animal1.eat();
animal1.swap();
}
}
结果如下
5.2 子类初始化顺序代码示例(一)
class Animal{
public String name;
public int age;
public String color;
static {
System.out.println("Animal的静态代码块");
}
{
System.out.println("Animal的实例代码块");
}
public Animal(){
}
public Animal(String name,int age,String color){
this.name = name;
this.age = age;
this.color = color;
System.out.println("Animal的构造函数");
}
}
class Dog extends Animal{
static {
System.out.println("子类的静态代码块");
}
{
name = "初一";
age = 19;
System.out.println("子类的示例代码块");
}
public Dog(String name,int age,String color) {
super(name,age,color);
System.out.println("子类的构造方法");
}
}
public class Test {
public static void main(String[] args) {
Dog dog1 = new Dog("Dog1",2,"白色");
}
}
//先执行所有的静态代码块,再执行父类的实例化代码块以及父类的构造方法。最后再执行子类的实例化代码和构造方法。
//1. 静态代码块先执行,并且只执行一次,在类加载阶段执行
//2. 当有对象创建时,才会执行实例代码块,实例代码块执行完成后,最后构造方法执行
结果如下
5.2 子类初始化顺序代码示例(二)
class Animal{
public String name;
public int age;
public String color;
static {
System.out.println("Animal的静态代码块");
}
{
System.out.println("Animal的实例代码块");
}
public Animal(){
}
public Animal(String name,int age,String color){
this.name = name;
this.age = age;
this.color = color;
System.out.println("Animal的构造函数");
}
}
class Dog extends Animal{
static {
System.out.println("子类的静态代码块");
}
{
name = "初一";
age = 19;
System.out.println("子类的示例代码块");
}
public Dog(String name,int age,String color) {
super(name,age,color);
System.out.println("子类的构造方法");
}
}
public class Test {
public static void main(String[] args) {
Dog dog1 = new Dog("Dog1",2,"白色");
System.out.println("==================");
Dog dog2 = new Dog("Dog2",1,"黄色");
}
}
结果如下
5.3 学习小贴士
1、父类静态代码块优先于子类静态代码块执行,且是最早执行。父类实例代码块和父类构造方法紧接着执行。
2、子类的实例代码块和子类构造方法紧接着再执行。
2、第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行。
六、 继承方式
6.1 final 关键字
final关键可以用来修饰变量、成员方法以及类。
- 修饰变量或字段,表示常量(即不能修改)
- 修饰类:表示此类不能被继承。我们平时是用的 String 字符串类, 就是用 final 修饰的, 不能被继承。
- 修饰方法:表示该方法不能被重写(
public class Test {
public static void main(String[] args) {
int a = 20;
a = 10;
System.out.println(a);
final int b = 10;
b = 20;//errer
System.out.println(b);
}
}
结果如下
6.2 多态
6.2.1多态的概念
通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
6.2.2 动态绑定代码示例(一)
class Animal{
public String name;
public int age;
public String color;
public Animal(){
}
public Animal(String name) {
this.name = name;
}
public Animal(int age) {
this.age = age;
}
public Animal(String name, String color) {
this.name = name;
this.color = color;
}
public void eat(){
System.out.println(name + "正在吃粮 ———— Animal" );
}
public void swap(){
System.out.println(name + "正在摇尾巴———— Animal");
}
}
class Dog extends Animal{
public Dog() {
}
public Dog(String name){
super(name);
this.name = name;
}
public Dog(int age){
super(age);
this.age = age;
}
public Dog(String name,String color){
super(name,color);
this.name = name;
this.color = color;
}
public void eat(){
System.out.println(name + "正在吃狗粮 ———— Dog");
}
public void swap(){
System.out.println(name + "正在摇尾巴 ———— Dog");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Animal("初三","黄色");
animal.eat();
animal.swap();
System.out.println("================");
Animal animal1 = new Dog("初一","白色");
animal1.eat();
animal1.swap();
}
}
结果如下
6.2.2 动态绑定代码示例(二)
class Animal {
public String name;
public int age;
public String color;
public Animal(){
}
public Animal(String name){
this.name = name;
}
public Animal(int age){
this.age = age;
}
public Animal(String name,String color){
this.name = name;
this.color = color;
}
public void eat(){
System.out.println(name + "正在吃粮");
}
public void swap(){
System.out.println(name + "正在摇尾巴");
}
}
class Dog extends Animal {
public Dog(){
super();
}
public Dog(String name){
super(name);
}
public Dog(int age){
super(age);
}
public Dog(String name,String color){
super(name,color);
}
public void wangWang(){
System.out.println(name + "正在吠叫");
}
}
class Bird extends Animal{
public Bird(){
super();
}
public Bird(String name){
super(name);
}
public Bird(int age){
super(age);
}
public Bird(String name,String color){
super(name,color);
}
public void fly(){
System.out.println(name + "正在飞翔");
}
}
public static void main(String[] args) {
Animal animal = new Dog(("小鸟");
Animal animal1 = new Bird(("小鸟");
}
}
结果如下
6.2.3 动态绑定直接赋值代码示例
class Animal {
public String name;
public int age;
public String color;
public Animal(){
}
public Animal(String name){
this.name = name;
System.out.println("姓名:" + name);
}
public Animal(int age){
this.age = age;
System.out.println("年龄:" + age);
}
public Animal(String name,String color){
this.name = name;
this.color = color;
System.out.println("姓名:" + name + "颜色" + color);
}
public void eat(){
System.out.println(name + "正在吃粮");
}
public void swap(){
System.out.println(name + "正在摇尾巴");
}
}
class Dog extends Animal {
public Dog(){
super();
}
public Dog(String name){
super(name);
}
public Dog(int age){
super(age);
}
public Dog(String name,String color){
super(name,color);
}
public void wangWang(){
System.out.println(name + "正在吠叫");
}
}
class Bird extends Animal {
public Bird() {
super();
}
public Bird(String name) {
super(name);
}
public Bird(int age) {
super(age);
}
public Bird(String name, String color) {
super(name, color);
}
public void fly() {
System.out.println(name + "正在飞翔");
}
public static void main(String[] args) {
Animal animal = new Dog("小狗");
Animal animal1 = new Bird("小鸟");
}
}
结果如下
6.2.4 动态绑定方法传参代码示例
class Animal {
public String name;
public int age;
public String color;
public Animal(){
}
public Animal(String name){
this.name = name;
System.out.println("姓名:" + name);
}
public Animal(int age){
this.age = age;
System.out.println("年龄:" + age);
}
public Animal(String name,String color){
this.name = name;
this.color = color;
System.out.println("姓名:" + name + " 颜色:" + color);
}
public void eat(){
System.out.println(name + "正在吃粮");
}
public void swap(){
System.out.println(name + "正在摇尾巴");
}
}
class Dog extends Animal {
public Dog(){
super();
}
public Dog(String name){
super(name);
}
public Dog(int age){
super(age);
}
public Dog(String name,String color){
super(name,color);
}
public void wangWang(){
System.out.println(name + "正在吠叫");
}
}
class Bird extends Animal{
public Bird(){
super();
}
public Bird(String name){
super(name);
}
public Bird(int age){
super(age);
}
public Bird(String name,String color){
super(name,color);
}
public void fly(){
System.out.println(name + "正在飞翔");
}
}
public class Test {
public static void func(Animal animal){
}
public static void main(String[] args) {
Dog dog = new Dog("初一");
Bird bird = new Bird("小鸟");
func(dog);
func(bird);
}
}
结果如下
6.2.5 动态绑定返回值代码示例
class Animal {
public String name;
public int age;
public String color;
public Animal(){
}
public Animal(String name){
this.name = name;
System.out.println("姓名:" + name);
}
public Animal(int age){
this.age = age;
System.out.println("年龄:" + age);
}
public Animal(String name,String color){
this.name = name;
this.color = color;
System.out.println("姓名:" + name + " 颜色:" + color);
}
public void eat(){
System.out.println(name + "正在吃粮");
}
public void swap(){
System.out.println(name + "正在摇尾巴");
}
}
class Dog extends Animal {
public Dog(){
super();
}
public Dog(String name){
super(name);
}
public Dog(int age){
super(age);
}
public Dog(String name,String color){
super(name,color);
}
public void wangWang(){
System.out.println(name + "正在吠叫");
}
}
class Bird extends Animal{
public Bird(){
super();
}
public Bird(String name){
super(name);
}
public Bird(int age){
super(age);
}
public Bird(String name,String color){
super(name,color);
}
public void fly(){
System.out.println(name + "正在飞翔");
}
}
public class Test {
public static Animal func(){
return new Dog("初一","黑色");
}
public static Animal func1(){
return new Bird("初二","白色");
}
public static void main(String[] args) {
Animal animal1 = func();
Animal animal2 = func1();
}
}
结果如下
6.3 重写
6.3.1 重写的概念
重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
6.3.2 方法重写的规则
1、子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 (参数列表) 要完全一致。
被重写的方法返回值类型可以不同,但是必须是具有父子关系的。
2、访问权限不能比父类中被重写的方法的访问权限更低。private < default < protected < public
3、父类被static、private、final(密封方法)修饰的方法、构造方法都不能被重写。
4、重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心将方法名字拼写错, 那么此时编译器就会发现父类中没有该方法, 就会编译报错, 提示无法构成重写。
6.4.1 方法重写的代码示例(运行时绑定)
class Animal {
public String name;
public int age;
public String color;
public Animal(){
}
public Animal(String name){
this.name = name;
}
public Animal(int age){
this.age = age;
System.out.println("年龄:" + age);
}
public Animal(String name,String color){
this.name = name;
this.color = color;
System.out.println("姓名:" + name + " 颜色:" + color);
}
public void eat(){
System.out.println(name + "正在吃粮");
}
public void swap(){
System.out.println(name + "正在摇尾巴");
}
}
class Dog extends Animal {
public Dog(){
super();
}
public Dog(String name){
super(name);
}
public Dog(int age){
super(age);
}
public Dog(String name,String color){
super(name,color);
}
public void wangWang(){
System.out.println(name + "正在吠叫");
}
public void eat(){
System.out.println(name + "正在吃狗粮");
}
}
class Bird extends Animal{
public Bird(){
super();
}
public Bird(String name){
super(name);
}
public Bird(int age){
super(age);
}
public Bird(String name,String color){
super(name,color);
}
public void fly(){
System.out.println(name + "正在飞翔");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Dog("初一");
animal.eat();//向上转型并调用了子类中父类重写的方法,结果就是调用了子类自己的重写方法
//在编译时确实认为需要调用父类的eat(),但是运行时发现子类重写了eat(),所以直接调用子类自己的方法。
Animal animal1 = new Bird("小鸟");
animal1.eat();//只向上转型,所以仍然调用父类的方法
}
}
结果如下
6.4 静态绑定与动态绑定
静态绑定:也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。
动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。
6.5 向上转移和向下转型
6.5.1 向上转型
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。父类类型引用子类对象,从小范围向大范围的转换。
语法格式:父类类型 对象名 = new 子类类型();
向上转型的优点:让代码实现更简单灵活。
向上转型的缺陷:不能调用到子类特有的方法。
6.5.2 向下转型
向下转型:将一个子类对象经过向上转型之后当成父类方法使用,在无法调用子类的方法,但有时候可能需要调用子类特有的方法时,将父类引用再还原为子类对象即可,即向下转换。
6.5.2.1 向下转型错误代码示例
class Animal{
public String name;
public int age;
public String color;
public Animal(){
}
public Animal(String name){
this.name = name;
}
public Animal(int age){
this.age = age;
System.out.println("年龄:" + age);
}
public Animal(String name,String color){
this.name = name;
this.color = color;
System.out.println("姓名:" + name + " 颜色:" + color);
}
public void eat(){
System.out.println(name + "正在吃粮");
}
public void swap(){
System.out.println(name + "正在摇尾巴");
}
}
class Dog extends Animal {
public Dog(){
super();
}
public Dog(String name){
super(name);
}
public Dog(int age){
super(age);
}
public Dog(String name,String color){
super(name,color);
}
public void wangWang(){
System.out.println(name + "正在吠叫");
}
public void eat(){
System.out.println(name + "正在吃狗粮");
}
}
class Bird extends Animal{
public Bird(){
super();
}
public Bird(String name){
super(name);
}
public Bird(int age){
super(age);
}
public Bird(String name,String color){
super(name,color);
}
public void fly(){
System.out.println(name + "正在飞翔");
}
public static void main(String[] args) {
Animal animal = new Bird("小鸟");
Bird bird = (Bird) animal;
bird.fly();
Animal animal1 = new Dog("小狗");
Bird bird1 = (Bird) animal1;
bird1.fly();
}
}
结果如下
6.5.2.2 向下转型正确代码示例
class Animal{
public String name;
public int age;
public String color;
public Animal(){
}
public Animal(String name){
this.name = name;
}
public Animal(int age){
this.age = age;
System.out.println("年龄:" + age);
}
public Animal(String name,String color){
this.name = name;
this.color = color;
System.out.println("姓名:" + name + " 颜色:" + color);
}
public void eat(){
System.out.println(name + "正在吃粮");
}
public void swap(){
System.out.println(name + "正在摇尾巴");
}
}
class Dog extends Animal {
public Dog(){
super();
}
public Dog(String name){
super(name);
}
public Dog(int age){
super(age);
}
public Dog(String name,String color){
super(name,color);
}
public void wangWang(){
System.out.println(name + "正在吠叫");
}
public void eat(){
System.out.println(name + "正在吃狗粮");
}
}
class Bird extends Animal{
public Bird(){
super();
}
public Bird(String name){
super(name);
}
public Bird(int age){
super(age);
}
public Bird(String name,String color){
super(name,color);
}
public void fly(){
System.out.println(name + "正在飞翔");
}
public static void main(String[] args) {
Animal animal = new Bird("小鸟");
Bird bird = (Bird) animal;
bird.fly();
Animal animal1 = new Dog("小狗");
if(animal1 instanceof Bird){
Bird bird1 = (Bird) animal1;
bird1.fly();
}else {
System.out.println("飞不起来");
}
}
}
结果如下
6.6 多态代码示例
普通代码(一)
class Shape{
public void drap(){
System.out.println("画图形");
}
}
class Rect extends Shape{
@Override
public void drap() {
System.out.println("◊");
}
}
class Circle extends Shape{
@Override
public void drap(){
System.out.println("○");
}
}
class Flower extends Shape{
@Override
public void drap(){
System.out.println("❀");
}
}
public class Test {
public static void main(String[] args) {
Rect rect = new Rect();
Circle circle = new Circle();
Flower flower = new Flower();
String strings[] = {"rect","circle","rect","circle","flower"};
for (String s: strings) {
if(s.equals("rect")){
rect.drap();
} else if (s.equals("circle")){
circle.drap();
}else if (s.equals("flower")){
flower.drap();
}
}
}
}
结果如下
多态代码(一)
class Shape{
public void drap(){
System.out.println("画图形");
}
}
class Rect extends Shape{
@Override
public void drap() {
System.out.println("◊");
}
}
class Circle extends Shape{
@Override
public void drap(){
System.out.println("○");
}
}
class Flower extends Shape{
@Override
public void drap(){
System.out.println("❀");
}
}
public class Test {
public static void drapMaps() {
Rect rect = new Rect();
Circle circle = new Circle();
Flower flower = new Flower();
Shape[] shapes = {rect, circle, rect, circle, flower};
for (Shape shape : shapes) {
shape.drap();
}
}
public static void main(String[] args) {
drapMaps();
}
}
结果如下
普通代码(二)
class Shape{
public void drap(){
System.out.println("画图形");
}
}
class Rect extends Shape{
@Override
public void drap() {
System.out.println("◊");
}
}
class Circle extends Shape{
@Override
public void drap(){
System.out.println("○");
}
}
class Flower extends Shape{
@Override
public void drap(){
System.out.println("❀");
}
}
public class Test {
public static void drapMaps() {
Rect rect = new Rect();
Circle circle = new Circle();
Flower flower = new Flower();
String strings[] = {"rect", "circle", "rect", "circle", "flower"};
for (String s : strings) {
if (s.equals("rect")) {
rect.drap();
} else if (s.equals("circle")) {
circle.drap();
} else if (s.equals("flower")) {
flower.drap();
}
}
}
public static void main(String[] args) {
drapMaps();
}
}
结果如下
多态代码
class Shape{
public void draw(){
System.out.println("画图形");
}
}
class Rect extends Shape{
@Override
public void draw(){
System.out.println("◊");
}
}
class Circle extends Shape{
@Override
public void draw(){
System.out.println("○");
}
}
class Flower extends Shape{
@Override
public void draw() {
System.out.println("❀");
}
}
public class Test {
public static void drawMap(Shape shape){
shape.draw();
}
public static void main(String[] args) {
Rect rect = new Rect();
Circle circle = new Circle();
Flower flower = new Flower();
drawMap(rect);
drawMap(circle);
drawMap(flower);
}
}
结果如下
总结
在书写代码的时候,适当的使用多态是有不少好处的,它不仅能够降低代码的 “圈复杂度”, 避免使用大量的 if - else,也可以让代码的扩展能力更强。
但这并不意味着多态没有缺陷,多态代码的运行效率降低且属性没有多态性,当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性,并且构造方法没有多态性。