多态
引言:
什么叫作多态呢?
用通俗的话来说就是在同一时刻事物所呈现的不同状态
例如 水:
多态 固态 液态 气态
1)必须有继承关系
2)必须有方法重写
3)必须有父类的引用指向子类对象(向上转型)
父类名 fu = new 子类名() ;
父类引用的创建是通过子类在堆内存中新建了(new)一个对象,也就是说父类的引用是通过子类新建对象进行的。
1)成员变量: 编译看左,运行看左
2) 非静态成员方法 : 编译看左,运行看右(存在方法重写)
4)静态成员方法: 编译看左,运行看左(静态跟类有关,算不上方法重写)
代码示例
package org.westos; class Fu{ int num = 20 ;// public void show() { System.out.println("show Fu...."); } public Fu(){ } public static void function() { System.out.println("function Fu..."); } } //子类 class Zi extends Fu{ int num = 30 ; public void show() { System.out.println("show Zi...."); } public static void function() { System.out.println("function Zi..."); } public void method() { System.out.println("----4"); } } public class ExtendsDemo2{ public static void main(String[] args) { Fu f = new Zi() ; System.out.println(f.num); f.show(); f.function(); } }
多态的好处
1)可以提高代码的复用性:由继承保证
2)可以提高代码的扩展性:由多态保证
代码示例
package org.westos; class Animal { public void eat() { System.out.println("eat"); } public void sleep() { System.out.println("sleep"); } } // 猫类 class Cat extends Animal { public void eat() { System.out.println("猫吃鱼..."); } public void sleep() { System.out.println("猫趴着睡觉..."); } } // 狗类 class Dog extends Animal { public void eat() { System.out.println("狗吃骨头..."); } public void sleep() { System.out.println("狗卧着睡觉..."); } } // pig类 class Pig extends Animal { public void eat() { System.out.println("猪吃白菜..."); } public void sleep() { System.out.println("猪躺着睡觉..."); } } // 可以定义一个动物的工具类AnimalTool class AnimalTool { private AnimalTool() { } // 静态功能 // 调用猫的功能 /* * public static void useCat(Cat c) { c.eat(); c.sleep(); * * } //调用猪的功能 public static void usePig(Pig p) { p.eat(); p.sleep(); } * * //调用狗的功能 public static void useDog(Dog d) { d.eat(); d.sleep(); } */ public static void useAnimal(Animal a) { // 需要他的子类对象 Animal a = new Cat()/new Dog()/new Pig(); a.eat();//eat()非静态的,编译看左,运行看右,即调用子类的eat() a.sleep();//sleep()非静态的,编译看左,运行看右,即调用子类的sleep() } } public class ExtendsDemo2 { public static void main(String[] args) { // //我喜欢猫,要养一只猫 // Cat c = new Cat() ; // c.eat(); // c.sleep(); // System.out.println("-------------"); // // //还喜欢猫,又养一只 // Cat c2 = new Cat() ; // c2.eat(); // c2.sleep(); // // Dog d = new Dog() ; // // System.out.println("-------------"); // //我很喜欢猫 // Cat c3 = new Cat() ; // c3.eat(); // c3.sleep(); // // System.out.println("-----------------"); // // // //上述的方法非常麻烦..,可以通过调用方法进行改进 // useCat(c); // useCat(c2); // useCat(c3); // // System.out.println("----------"); //// //定义了动物工具类的改进... //// AnimalTool.useCat(c); //// AnimalTool.useCat(c2); //// AnimalTool.useCat(c3); // // 改进之后 Animal c = new Cat(); //向上引用 Animal d = new Dog(); //向上引用 Animal p = new Pig(); //向上引用 AnimalTool.useAnimal(c);//因为useAnimal()为静态的(static),所以可以由类名AnimalTools直接去调用 AnimalTool.useAnimal(d);//因为useAnimal()为静态的(static),所以可以由类名AnimalTools直接去调用 AnimalTool.useAnimal(p);//因为useAnimal()为静态的(static),所以可以由类名AnimalTools直接去调用 } }
万物有利则必有弊,此乃真理也!!!下面来说说多态的弊端
多态的弊端
不能通过父类的引用去调用子类中特有的功能
代码实例
package org.westos; class Father2{ public void show() { System.out.println("show father2..."); } } class Son2 extends Father2{ public void show() { System.out.println("show son2..."); } //子类的特有关功能 public void method() { System.out.println("method son2..."); } } public class ExtendsDemo2 { public static void main(String[] args) { Father2 f = new Son2() ; f.show();//编译看左边,运行看右边 f.method() ; 编译通过了,但是Father2这个类中没有method()方法,则程序报错 } }
可不可以将子类的引用指向父类的引用呢? (向下转型)
格式: 子类名 s=(子类名) f;
将父类的引用强制转换为子类的引用
代码示例
package org.westos; class Father3 { public void show() { System.out.println("show father2..."); } } class Son3 extends Father3 { public void show() { System.out.println("show son2..."); } // 子类的特有关功能 public void method() { System.out.println("method son2..."); } } public class ExtendsDemo2 { public static void main(String[] args) { Father3 f = new Son3();// 向上转型 f.show(); Son3 s = (Son3) f; // 前提是必须要有父类的引用 // 将父类的引用强制转换子类的引用 ,向下转型使用不当,会出现一个异常:属于运行时期异常:ClassCastException s.method(); } }向下转型使用不当,会出现一个异常:属于 运行时期异常:ClassCastException
图解如下
代码示例
package org.westos.多态; /*** * 将父类的引用强制转换子类的引用 ,向下转型使用不当,会出现一个异常:属于运行时期异常:ClassCastException * @author Administrator * */ class Animal2{ public void eat() { } } //猫类 class Cat2 extends Animal2 { public void eat() { } public void playGame() { } } //狗类: class Dog2 extends Animal2{ public void eat() {} public void lookDoor() {} } //测试类 public class DuoTaiDemo5 { public static void main(String[] args) { //内存中是猫 Animal a = new Cat() ;//向上转型 Cat c = (Cat)a;//向下转型,还原成猫 //内存中变成了Dog a = new Dog() ; //还原成狗 Dog d = (Dog)a ; Cat cc = (Cat)a ; } }
多态Test
需求:南北方的饮食文化不同
南方人和北方人(使用多态可以测试)
自己分析功能
代码示例
package org.westos; class Person { public void eat() { System.out.println("吃饭..."); } } // 南方人呢 class SourthPeople extends Person { public void eat() { System.out.println("南方人吃米饭..."); } // 特有功能 public void business() { System.out.println("南方人爱经商..."); } } // 北方人 class NorthPeople extends Person { public void eat() { System.out.println("北方人爱吃面..."); } // 特有功能 public void yanJiu() { System.out.println("北方人爱钻研..."); } } public class ExtendsDemo2 { public static void main(String[] args) { Person p = new SourthPeople();//向上转型 p.eat();//调用子类的eat()方法 SourthPeople sp = (SourthPeople) p;//向下转型 sp.business(); System.out.println("-------"); NorthPeople nop = new NorthPeople(); nop.eat(); nop.yanJiu(); } }面试题:
final,finally,finalize的区别?
final:表示最终,终态(不能被更改的)
它可以修饰类,那么该类不能继承
它可以修饰成员方法,成员方法不能被重写
它可以修饰变量,此时这个变量是一个常量
常量的分类:
字面值常量:
字符串常量,字符常量,,,,
自定义常量(final修饰的)
pubic final int num = 100 ;final
final不仅可以修饰基本数据类型
还可以修饰引用类型
如果final修饰的是一个基本类型数据,则基本数据类型的值不能再改变了
如果final修饰的是一个引用类型数据,则引用类型的地址值不能再改变了,但是堆内存中的成员变量的值可以改变
final的初始化时机:
1)被final只能赋值一次(final int a = 10 )
2)final int a ;
//在使用之前进行初始化,在构造方法之前进行赋值(非静态的)代码示例
package org.westos; class Father{ int num = 10; final int num2 = 20 ;//num2被final修饰,则为常量 public void method() { System.out.println("method father..."); } // public final void show() { //show()方法被final修饰,则不能再被重写 // System.out.println("show father...."); // } public void function() { num = 200 ; // num2 = 30 ;//num2为常量,不能再被赋值 System.out.println(num); System.out.println(num2); } } //子类 class Son extends Father{ public void method() { System.out.println("method son...."); } /*public void show() { }*/ } public class ExtendsDemo2 { public static void main(String[] args) { Son s = new Son() ; s.function(); s.method(); } }
package org.westos.finaldemo; class Student{ int age = 20 ; } public class FinalTest { public static void main(String[] args) { //定一个变量 int x = 10 ; x = 100 ; System.out.println(x); System.out.println("------------"); final int y = 20 ; //y = 200 ;// 不能被赋值了,变量y此时常量... System.out.println("-------------"); //创建Student类对象 Student s = new Student() ; s.age = 56 ; System.out.println(s.age); System.out.println("-----------------"); //另一种情况: final Student ss = new Student() ; ss.age = 70 ; System.out.println(ss.age); //给堆内存开辟一个新的空间 // ss = new Student() ;//the final local variable ss cannot be assigned } }
代码块
用{}括起来的代码,统称为代码块;
根据其所处位置的不同分为以下几类:
1)局部代码块: 在main()里面,作用是限定变量的生命周期
2)构造代码块:在一个类的成员位置上,用{}括起来。作用:将多个构造方法中相同的代码放到构造代码块中,对对象
进行初始化.在每次执行构造方法之前,先执行构造代码块.
3)静态代码块:在一个类的成员位置上,也是用{}包起来,但是被static修饰。作用:一般情况下给类进行初始化
面试题:
构造代码块,构造方法,静态代码块的优先级?
静态代码块>构造代码块>构造方法
静态代码块:只能执行一次
构造代码块在每次执行构造方法之前都会被执行.
代码示例
package org.westos; class Code{ //静态代码块 static{ int x = 1000 ; System.out.println(x); } //构造代码块 { int x = 100 ; System.out.println(x); } //构造方法 public Code() { System.out.println("code11"); } //构造代码块 { int y = 200 ; System.out.println(y); } //有参构造 public Code(int a) { System.out.println("code2"); } //静态代码块 static { int y = 2000 ; System.out.println(y); } } public class AbstractDemo11 { public static void main(String[] args) { Code code = new Code() ; System.out.println("------不再执行静态代码块-----"); Code code2 = new Code() ; System.out.println("--------------------"); Code code3 = new Code(100) ; } }