多态
引言:
什么叫作多态呢?
用通俗的话来说就是在同一时刻事物所呈现的不同状态
例如 水:
多态 固态 液态 气态
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) ;
}
}