JAVA自学教程之(多态及其基本应用)



JAVA自学教程之(多态及其基本应用)。多态:
面向对象的第三个特征,定义:某类事物存在多种形态,比如,函数就具备多态性,同名的一个函数,它的参数列表不一样,它的存在性就不一样,还有同一个函数,放在父类和放在子类,它的存在性也就不一样。
对象也存在多态性。
例子:动物有猪、猫、狗等
猫这个对象对应的类是猫类
猫 x = new 猫();
同时,猫还是动物的一种,也就可以把猫成为动物
动物 y = new 猫(); 动物 z = new 狗();
动物是狗和猫集体事物中抽取出来的父类 父类引用指向了子类对象

一、概述

 

 

  1. //对象的多态性
  2. //多态的表现,父类型在指向自对象
  3. class animal
  4. {
  5. }
  6. class cat extends animal
  7. {
  8. }
  9. class dog extends animal
  10. {
  11. }
  12. public class Main
  13. {
  14.     public static void main(String[] args)
  15.     {
  16.         //一个对象两种形态
  17.         animal 小动物 = new cat();//小动物通过猫创建对象,动物类在指向
  18.         /*
  19.          * 猫这类事物具备猫的形态,又具备动物的形态。
  20.          * 这就是事物的多态性
  21.          * 也就是一个对象对应着不同的类型
  22.          * 多态在代码中的体现:
  23.          * (父类/接口)的引用指向了其子类的对象
  24.          * */
  25.     }
  26. }
//对象的多态性
//多态的表现,父类型在指向自对象

class animal
{

}
class cat extends animal
{

}
class dog extends animal
{

}
public class Main
{
	public static void main(String[] args)
	{
		//一个对象两种形态
		animal 小动物 = new cat();//小动物通过猫创建对象,动物类在指向
		/*
		 * 猫这类事物具备猫的形态,又具备动物的形态。
		 * 这就是事物的多态性
		 * 也就是一个对象对应着不同的类型
		 * 多态在代码中的体现:
		 * (父类/接口)的引用指向了其子类的对象
		 * */
	}
}


二、多态的优点
提供了代码的扩展性,前期定义的代码可以使用后期的内容(先有了动物,才有了猪)
以下述代码体现:

 

 

 

  1. abstract class animal
  2. {
  3.     abstract void sing();//叫
  4. }
  5. class cat extends animal
  6. {
  7.     void sing()
  8.     {
  9.         System.out.println(“喵喵叫”);
  10.     }
  11.     void fun()//猫的特有功能
  12.     {
  13.         System.out.println(“捉老鼠”);
  14.     }
  15. }
  16. class dog extends animal
  17. {
  18.     void sing()
  19.     {
  20.         System.out.println(“汪汪叫”);
  21.     }
  22.     void fun()//狗的特有功能
  23.     {
  24.         System.out.println(“看家”);
  25.     }
  26. }
  27. class pig extends animal
  28. {
  29.     void sing()
  30.     {
  31.         System.out.println(“哼哼叫”);
  32.     }
  33.     void fun()
  34.     {
  35.         System.out.println(“拱地”);
  36.     }
  37. }
  38. public class Main
  39. {
  40.     public static void main(String[] args)
  41.     {
  42.         //一只猫
  43.         cat 小猫 = new cat();
  44.         小猫.sing();
  45.         //很多猫
  46.         cat 二猫 = new cat();
  47.         cat 三猫 = new cat();
  48.         catqun(二猫);
  49.         catqun(三猫);
  50.         //….
  51.         //多态的体现,多只动物
  52.         dog 小狗1号 = new dog();
  53.         cat 小猫1号 = new cat();
  54.         catqun(小狗1号);
  55.         catqun(小猫1号);
  56.         catqun(new pig(););
  57.     }
  58.     static void catqun(animal c)//animal c  = new cat()/dog()/pig();
  59.     {
  60.         c.sing();
  61.     }
  62. }
abstract class animal
{
	abstract void sing();//叫
}
class cat extends animal
{
	void sing()
	{
		System.out.println("喵喵叫");
	}
	void fun()//猫的特有功能
	{
		System.out.println("捉老鼠");
	}
}
class dog extends animal
{
	void sing()
	{
		System.out.println("汪汪叫");
	}
	void fun()//狗的特有功能
	{
		System.out.println("看家");
	}
}
class pig extends animal
{
	void sing()
	{
		System.out.println("哼哼叫");
	}
	void fun()
	{
		System.out.println("拱地");
	}
}
public class Main
{
	public static void main(String[] args)
	{
		//一只猫
		cat 小猫 = new cat();
		小猫.sing();

		//很多猫
		cat 二猫 = new cat();
		cat 三猫 = new cat();
		catqun(二猫);
		catqun(三猫);
		//....

		//多态的体现,多只动物
		dog 小狗1号 = new dog();
		cat 小猫1号 = new cat();

		catqun(小狗1号);
		catqun(小猫1号);
		catqun(new pig(););
	}
	static void catqun(animal c)//animal c  = new cat()/dog()/pig();
	{
		c.sing();
	}
}

三、多态的弊端和前提
1.多态的弊端:
前期定义的内容不能使用后期 子类的特有内容

 

 

  1. static void catqun(animal c)
  2.     {
  3.         c.sing();
  4.     //  c.fun();->animal里没有fun这个方法
  5.     }
static void catqun(animal c)
	{
		c.sing();
	//	c.fun();->animal里没有fun这个方法
	}

PS:当然可以直接使用猫static void catqun(cat c)来调用,但是我们不知道后期到底还会出现多少物种,复用性差
2.多态的前提:
⑴.必须有关系,要么继承,要么实现 ⑵.要有覆盖(父类定义了功能,子类具体实现,狗叫、狼叫,很麻烦。犬科叫,很简单) 如果不满足⑵,没有覆盖就使用多态,比如:狗看家,正常,狼看家,这不就出问题了。
保证了多态的这两个前提,就可以提高程序的扩展性
四、转型
以代码体现:

 

 

 

  1. abstract class animal
  2. {
  3.     abstract void sing();//叫
  4. }
  5. class cat extends animal
  6. {
  7.     void sing()
  8.     {
  9.         System.out.println(“喵喵叫”);
  10.     }
  11.     void fun()//猫的特有功能
  12.     {
  13.         System.out.println(“捉老鼠”);
  14.     }
  15. }
  16. class dog extends animal
  17. {
  18.     void sing()
  19.     {
  20.         System.out.println(“汪汪叫”);
  21.     }
  22.     void fun()//狗的特有功能
  23.     {
  24.         System.out.println(“看家”);
  25.     }
  26. }
  27. class pig extends animal
  28. {
  29.     void sing()
  30.     {
  31.         System.out.println(“哼哼叫”);
  32.     }
  33.     void fun()
  34.     {
  35.         System.out.println(“拱地”);
  36.     }
  37. }
  38. public class Main
  39. {
  40.     public static void main(String[] args)
  41.     {//以前指挥对象做事
  42.         /*
  43.          * cat 小猫 = new cat();
  44.               小猫.sing();
  45.         */
  46.         animal a = new cat();//自动类型提升,猫对象提升到了动物,类似byte x = 3;int y = x;
  47.         a.sing();
  48.         //PS:猫一旦提升到了动物,但是其特有功能无法访问。
  49.         //专业说法,向上转型。目的:限制对特有功能的访问
  50.         //如果还行用猫的特有功能
  51.         //就可以将该对象,向下转型
  52.         cat c = (cat)a;//将动物a,向下转型为了猫c
  53.         c.fun();
  54.         // 向下转型的目的:是为了使用子类中特有的方法
  55.         /*animal d = new animal();
  56.          * animal f = new dog();
  57.          *  cat g = (cat)f;
  58.         cat e = (cat)d;这种类型不允许,小动物就一定是猫么*/
  59.     }
  60. }


abstract class animal
{
	abstract void sing();//叫
}
class cat extends animal
{
	void sing()
	{
		System.out.println("喵喵叫");
	}
	void fun()//猫的特有功能
	{
		System.out.println("捉老鼠");
	}
}
class dog extends animal
{
	void sing()
	{
		System.out.println("汪汪叫");
	}
	void fun()//狗的特有功能
	{
		System.out.println("看家");
	}
}
class pig extends animal
{
	void sing()
	{
		System.out.println("哼哼叫");
	}
	void fun()
	{
		System.out.println("拱地");
	}
}
public class Main
{
	public static void main(String[] args)
	{//以前指挥对象做事
		/*
		 * cat 小猫 = new cat();
		      小猫.sing();
		*/

		animal a = new cat();//自动类型提升,猫对象提升到了动物,类似byte x = 3;int y = x;
		a.sing();

		//PS:猫一旦提升到了动物,但是其特有功能无法访问。
		//专业说法,向上转型。目的:限制对特有功能的访问

		//如果还行用猫的特有功能
		//就可以将该对象,向下转型
		cat c = (cat)a;//将动物a,向下转型为了猫c
		c.fun();

		// 向下转型的目的:是为了使用子类中特有的方法

		/*animal d = new animal();
		 * animal f = new dog();  
		 *  cat g = (cat)f;
		cat e = (cat)d;这种类型不允许,小动物就一定是猫么*/
	}
}

注意:对于转型,自始至终都是子类对象在做着类型的转化:猫对象一会转型为动物,一会转型为猫 PS:转型是有目的性
练习:

 

 

  1. /*
  2. * BLF和BLF2的故事
  3. * BLF2是BLF的儿子
  4. * */
  5. class BLF
  6. {
  7.     void 功能()
  8.     {
  9.         System.out.println(“用C++写程序”);
  10.     }
  11.     void 说英语()
  12.     {
  13.         System.out.println(“hello,world”);
  14.     }
  15. }
  16. class BLF2 extends BLF
  17. {
  18.     void 功能()
  19.     {
  20.         System.out.println(“用java写程序”);
  21.     }
  22.     void 说汉语()
  23.     {
  24.         System.out.println(“你好,世界”);
  25.     }
  26. }
  27. public class Main
  28. {
  29.     public static void main(String[] args)
  30.     {
  31.         BLF x = new BLF2();//一天BLF2冒充BLF
  32.         x.功能();//只能是用java写程序,因为BLF2只会java
  33.         x.说英语();//可以,让BLF2像BLF一样,说英语
  34.         //x.说汉语();//不可以,BLF2已经向上转型为BLF,禁止了BLF2特有功能的使用
  35.         BLF2 Z = (BLF2)x;//变回来
  36.         Z.说汉语();
  37.     }
  38. }
/*
 * BLF和BLF2的故事
 * BLF2是BLF的儿子
 * */
class BLF
{
	void 功能()
	{
		System.out.println("用C++写程序");
	}
	void 说英语()
	{
		System.out.println("hello,world");
	}
}
class BLF2 extends BLF
{
	void 功能()
	{
		System.out.println("用java写程序");
	}
	void 说汉语()
	{
		System.out.println("你好,世界");
	}
}
public class Main
{
	public static void main(String[] args)
	{
		BLF x = new BLF2();//一天BLF2冒充BLF
		x.功能();//只能是用java写程序,因为BLF2只会java
		x.说英语();//可以,让BLF2像BLF一样,说英语
		//x.说汉语();//不可以,BLF2已经向上转型为BLF,禁止了BLF2特有功能的使用
		BLF2 Z = (BLF2)x;//变回来
		Z.说汉语();
	}
}

五、类型判断:

 

  1. instanceof 用法:
  2. import java.lang.reflect.Method;
  3. abstract class animal
  4. {
  5.     abstract void sing();
  6. }
  7. class cat extends animal
  8. {
  9.     void sing()
  10.     {
  11.         System.out.println(“喵喵叫”);
  12.     }
  13.     void fun()
  14.     {
  15.         System.out.println(“抓老鼠”);
  16.     }
  17. }
  18. class dog extends animal
  19. {
  20.     void sing()
  21.     {
  22.         System.out.println(“汪汪叫”);
  23.     }
  24.     void fun()
  25.     {
  26.         System.out.println(“看家”);
  27.     }
  28. }
  29. public class Main
  30. {
  31.     public static void main(String[] args)
  32.     {
  33.         animal BLF = new cat();//猫向上转型为了动物
  34.         method1(BLF);
  35.         animal BLF2 = new dog();//猫向上转型为了动物
  36.         method2(BLF2);
  37.     }
  38.     public static void method1(animal a)
  39.     {
  40.         a.sing();
  41.         //a.fun();我们知道向上转型后,就无法使用子类特有功能
  42.         //所以想要使用就必须再向下转型
  43.         cat c = (cat)a;
  44.         c.fun();//只是可以的,但是假如我们传一只狗呢
  45.     }
  46.     public static void method2(animal a)
  47.     {
  48.         a.sing();
  49.         if(a instanceof cat)//instancdof用于判断a的具体类型
  50.                 //通常是在向下转型前用于健壮性的判断
  51.         {
  52.             cat c = (cat)a;
  53.             c.fun();
  54.         }
  55.         else if(a instanceof dog)//当然一个父类,有n多子类,不可能写n多if
  56.         {
  57.             dog c = (dog)a;
  58.             c.fun();
  59.         }
  60.         else if(a==null){System.out.println(“类型错误”);}
  61.     }
  62. }
instanceof 用法:

import java.lang.reflect.Method;

abstract class animal
{
	abstract void sing(); 
}
class cat extends animal
{
	void sing()
	{
		System.out.println("喵喵叫");
	}
	void fun()
	{
		System.out.println("抓老鼠");
	}
}
class dog extends animal
{
	void sing()
	{
		System.out.println("汪汪叫");
	}
	void fun()
	{
		System.out.println("看家");
	}
}

public class Main
{
	public static void main(String[] args)
	{
		animal BLF = new cat();//猫向上转型为了动物
		method1(BLF);
		animal BLF2 = new dog();//猫向上转型为了动物
		method2(BLF2);
	}
	public static void method1(animal a)
	{
		a.sing();
		//a.fun();我们知道向上转型后,就无法使用子类特有功能
		//所以想要使用就必须再向下转型
		cat c = (cat)a;
		c.fun();//只是可以的,但是假如我们传一只狗呢
	}
	public static void method2(animal a)
	{
		a.sing();
		if(a instanceof cat)//instancdof用于判断a的具体类型
				//通常是在向下转型前用于健壮性的判断
		{
			cat c = (cat)a;
			c.fun();
		}
		else if(a instanceof dog)//当然一个父类,有n多子类,不可能写n多if
		{
			dog c = (dog)a;
			c.fun();
		}
		else if(a==null){System.out.println("类型错误");}
	}
}

instaceof 后面可以是类,也可以是接口,且,它只适用于引用数据类型判断

六、多态的成员的特点:(面试。。。。。。)
1.成员变量 2.成员函数 3.静态函数
1.成员变量
编译时,参考引用型变量所属类中是否有调用成员变量,有,编译通过,没有,编译失败 {  为什么编译失败? 假如动物类中没有sing这个方法 animal c = new cat();//把猫提升为动物 c.sing();//猫现在是动物了,但是动物不会sing,所以编译失败  }
运行时,参考引用型变量所属类中是否有调用成员变量,并运行该所属类中的成员变量 简单说:就是编译和运行都参考等号(“=”)左边,fu f = new zi();
见代码://本问题不会在开发中出现,只会在面试时。。。

  1. class fu
  2. {
  3.     int num = 3;
  4. }
  5. class zi extends fu
  6. {
  7.     int num = 4;
  8. }
  9. public class Main
  10. {
  11.     public static void main(String[] args)
  12.     {
  13.         /* zi z = new zi();
  14.          * System.out.println(z.num);//普通继承是先找子类,子类有的直接覆盖
  15.          * */
  16.         //多态形式
  17.         fu f = new zi();//向上转型为了父类
  18.         System.out.println(f.num);//3
  19.         //想要打印子类的成员变量,向下转型
  20.         zi ff = (zi)f;
  21.         System.out.println(ff.num);//4
  22.     }
  23. }
class fu
{
	int num = 3;
}
class zi extends fu
{
	int num = 4;
}

public class Main
{
	public static void main(String[] args)
	{
		/* zi z = new zi();
		 * System.out.println(z.num);//普通继承是先找子类,子类有的直接覆盖
		 * */
		//多态形式
		fu f = new zi();//向上转型为了父类
		System.out.println(f.num);//3
		//想要打印子类的成员变量,向下转型
		zi ff = (zi)f;
		System.out.println(ff.num);//4
	}
}

2.成员函数(非静态函数,重点)
编译时,参考引用型变量所属类中是否有调用的函数,有,编译通过,没有,编译失败 运行时,参考对象所属类中是否有调用的函数,并运行该所属类中的函数 简单说:编译看左边,运行看右边 (非静态函数,需要用对象调用,所以运行时看右边)

 

  1. class fu
  2. {
  3.     void show()
  4.     {
  5.         System.out.println(“父”);
  6.     }
  7. }
  8. class zi extends fu
  9. {
  10.     void show()
  11.     {
  12.         System.out.println(“子”);
  13.     }
  14. }
  15. public class Main
  16. {
  17.     public static void main(String[] args)
  18.     {
  19.         fu f = new zi();//向上转型将子类型隐藏
  20.         f.show();//打印“子”,如果把子类show注释,打印父
  21.     }
  22. }
class fu
{
	void show()
	{
		System.out.println("父");
	}
}

class zi extends fu
{
	void show()
	{
		System.out.println("子");
	}
}

public class Main
{
	public static void main(String[] args)
	{
		fu f = new zi();//向上转型将子类型隐藏
		f.show();//打印“子”,如果把子类show注释,打印父
	}
}

3.静态函数(可以直接用类名调用,比较特殊)
实际上多态性应该没有静态函数,对象的多态性,而静态函数,可以直接用类名调用,创建对象来调用静态方法,这个对象其实就是垃圾
编译时,参考引用型变量所属类中是否有调用的静态方法,有,编译通过,没有,编译失败 运行时,参考引用型变量所属类中是否有调用的函数,并运行该所属类中的函数
简单说:就是编译和运行都看左边

 

 

  1. class fu
  2. {
  3.     static void my()
  4.     {
  5.         System.out.println(“父sta”);
  6.     }
  7. }
  8. class zi extends fu
  9. {
  10.     static void my()
  11.     {
  12.         System.out.println(“子sta”);
  13.     }
  14. }
  15. public class Main
  16. {
  17.     public static void main(String[] args)
  18.     {
  19.         fu f = new zi();
  20.         f.my();//打印“父sta”,如果删掉父类中的my方法,编译失败
  21.     }
  22. }