转的 关于java的多态,有的书上是这样讲的,它讲java的多态分成静态的多态,和动态的多态,而所谓静态的多态就是只函数的重载,动态的多态就是方法的覆写。 如下面: class Test { void print() { System.out.println("hello world"); } void print(int x) { System.out.println("hello world"+i); } public static void main(String []args) { Test ts=new Test(); ts.print(); ts.print(10); } } /* 上面的程序就是在一个类中成员方法的重载例子。也就是一个静态的多态性。系统会在你编译的时候根据你调用的方法的参数列表来动态的决定调用那一个函数。 */ 动态的多态: class Test { void print() { System.out.println("hello Test"); } public static void main(String []args) { A a=new A(); a.print(); } } class A extends Test { void print() { System.out.println("hello A"); } } /* 这时由于子类覆写了父类的方法,所以调用的是子类覆写后的方法。 这是动态的多态。 */ 2、是把一个子类的实例赋值给一个父类的问题,请看下面的程序: class A { void print(){} public static void main(String []args) { A [] a=new A[3]; a[0]=new B(); a[1]=new C(); a[2]=new D(); for(int i=0;i<a.length;i++) { a[i].print(); } } } class B extends A { void print() { System.out.println("hello B"); } } class C extends A { void print() { System.out.println("hello C"); } } class D extends A { void print() { System.out.println("hello D"); } } /* 上面的程序执行的结果: hello B hello C hello D 可以看出,程序不会调用父类的print()方法,再说父类print()方法根本什么也不做。这就是JVM (java虚拟机),能在程序运行时,动态的识别变量的类型。就像上面一样。这主要是考java的运行时的类型识别机制实现的,当然我认为这其实也可以看成是java多态的一种表现。 */ 在java中子类是父类的实例,这就像是说 鱼是动物。但不能说动物就一定是鱼,这也是符合了人们对现实世界的认识规律。另外java为我们提供了一个关键字,在孙鑫的教程里面也讲到了吧。它是instanceof 你可以用这来判断一个对象是否是一个类的实例。还是上面的A ,B,C ,D类的例子: 在mian函数中写上下面的代码:(把原来的代码删掉) B b=new B(); if(b instanceof A) System.out.println("b instanceof A"); //输出:b instanceof A 说明b是A类的实例。 再看下面的例子。 A a=new B(); if(a instanceof B) System.out.println("a instanceof B"); //输出:a instanceof B 但此时不能这样,B b=a; 虽然a是B的实例但是这里不能这样赋值,要像下面: B b=(B)a; //进行类型的强制转换 关于这部分你还是自己体会吧。
7.3. 多态(polymorphism) 多态:一个对象变量可以指向多种实际类型的现象。 7.3.1. 方法的覆盖(overridding) 当子类从父类继承一个无参方法,而又定义了一个同样的无参方法,则子类新写的方法覆盖父类的方法,称为覆盖。(注意返回值类型也必须相同,否则编译出错。) 如果方法参数表不同,则成重载。 特点: 1.对于方法的访问限制修饰词,子类方法要比父类的访问权限更高。 父类为public,那么子类为private则出现错误。 2.子类抛出的异常应该是父类抛出的异常或其子类 7.3.2. 多态的分类 多态分两种: 1编译时多态:编译时动态重载; 2运行时多态:指一个对象可以具有多个类型,方法的覆盖 这样对于对象而言分为: 理解运行时多态: Car c = new Bus(); Car编译时类型 编译时检查变量类型是否存在,是否有调用的方法 Bus运行时类型 实际运行是访问heep中的对象,调用实际的方法。 运行时多态是由运行时类型决定的 编译时多态是由编译时类型决定的 猫,小鸟,狗 都是动物,都可以安上动物的标签。 Interface Animal{} Class Car implements Animal{} Class Bird implements Animal{} Class Dog implements Animal{} 方法中 Animal a = new Car(); Animal b = new Bird(); Animal c = new Dog();*方法重载看的是参数的编译时类型public class Animal{ public static void main(String[] args){ } } (1) 是覆盖吗?不能多态了 abstract class MyClass{ priavate void m(); } class Sub extends MyClass(){ public void m(); } (2) 错误的修饰符组合 abstract class MyClass{ priavate abstract void m(); } class Sub extends MyClass(){ public void m(); } (3) 5.0 新 非覆盖 abstract class MyClass{ private final void m(); } class Sub extends MyClass(){ public void m(); } 运行时多态的三原则 1.对象不变;(改变的是主观认识) 2.对于对象的调用只能限于编译时类型的方法,如调用运行时类型方法报错。 在上面的例子中:Animal a=new Dog();对象a的编译时类型为Animal,运行时类型为dog。 注意:编译时类型一定要为运行时类型的父类或者同类型。 对于语句:Dog d=(Dog)a。将d强制声明为a类型,此时d为Dog(),此时d就可以调用运行时类型。注意:a和d指向同一对象。 3.动态类型判定实际调用的方法。即它调用覆盖后的方法。
重载(overload)和重写(override)的区别: 重载,从字面上看,建议读成(zhong 第四声)载,意思就是说,一辆客车本来只能坐20个人,而实际上坐了30人,我们说它超重了,也就是重载了。引深到程序设计语言中,就是说同一个名字的方法有多个实现,通过参数列表的不同来区别。比如 f(), f(int a), f(String str), f(int a, int b)就是重载。 重写,读成(chong 第二声)写,就是子类重新实现父类已经实现过的方法。 要理解多态,首先必须了解“类”和“对象”的区别: 类是广泛的概念,指一个群体,类别。 对象(又叫实例)是具体的东西。 比如说“人”是一个类,而“克林顿”就是“人”类的一个对象。 多态,简单点说,就是一个对象同时拥有多种类型。 看看一个模型: class 动物class 哺乳动物 extends 动物 class 鸟类 extends 动物 class 人 extends 哺乳动物 class 麻雀 extends 鸟类 class 百灵鸟 extends 鸟类1、如果我现在养了一只百灵鸟,那么我有一个“百灵鸟”的对象(也叫实例)。我可以说,我有一个“鸟”(父类)的对象,也可以我有一个“动物”的实例。 所以,子类向父类、爷爷类造型是自动的: 动物 obj = new 百灵鸟();2、如果我养了一只“鸟”,那么可能我养的是“麻雀”,也可能是“百灵鸟”。因此,父类向子类造型存在其可能性,但也可能会失败,在程序中应该进行类型检查: 鸟 obj = ...... // 从程序其它地方得到一个“鸟”的对象。 if(obj instanceof 百灵鸟){ 百灵鸟 obj1 = (百灵鸟)obj; }所以,相对而言,父类是比较“泛”的类型,而子类是更加“精确”的类型。3、后面的就不想总结了,楼主在图上画一棵类的继承树,然后想一想“人”可不可以造型成“鸟”。并且按着这个思路下去,再多添加一些子类,看看哪种情况可以造型,哪种情况不能造型。多态的好处,总结一下就是:可以使程序员关心他想要的类型,而忽略其它类型。 比如一个考勤模型: class 员工 class 会计 extends 员工 class 出纳 extends 员工 class 清洁工 extends 员工 class 工程师 extends 员工在考勤时,系统应该记录“员工”的上下班时间,在这里他关心的类型是泛类型“员工”,而不是精确类型(子类)。因此,上下班的方法应该定义在“员工”类,子类继承这个方法。java中的多态还涉及到接口问题。 因为为了简单,java取销了多继承,也就是一个类最多只能继承一个父类。因此问题就来了:当一种类型需要同时具有两个以上的类型,而这两个类型没有什么逻辑关系时怎么办。 比如说一个模型: class 动物 class 人 extends 动物 class 男人 extends 人 class 女人 extends 人 而我们需要另外一些类型:医生、老师、司机等。 现在需要一种类型,他同时是人,还必须是医生和司机。而java中如果继承了“人”,则不能再继承“医生”和“司机”。 所以,java中新增加了“接口”,旦一个类实现了某个接口,则这个类的对象也具有了接口的类型。 interface 医生 interface 老师 interface 司机class MyClass extends 男人 implements 医生, 司机那么可以: 医生 obj = new MyClass(); 另外,异常抛出来的其实也是继承自 Exception 类对象。在一个类的方法声抛出异常之后,子类如果重写这个方法时,能够声明抛出的异常将会是有限制的: class Father{ public void f() throws Exception_1{ // ...... } } class Sun extends Father { public void f() throws Exception_1_1, Exception_1_2{ } }Exception_1 和 Exception_1_1, Exception_1_2 之间必然会有一定的关系。这里我就不多说了,楼主顺着上面的思路,自己总结一下。
如下面:
class Test
{
void print()
{
System.out.println("hello world");
}
void print(int x)
{
System.out.println("hello world"+i);
}
public static void main(String []args)
{
Test ts=new Test();
ts.print();
ts.print(10);
}
}
/*
上面的程序就是在一个类中成员方法的重载例子。也就是一个静态的多态性。系统会在你编译的时候根据你调用的方法的参数列表来动态的决定调用那一个函数。
*/ 动态的多态: class Test
{
void print()
{
System.out.println("hello Test");
}
public static void main(String []args)
{
A a=new A();
a.print();
}
} class A extends Test
{
void print()
{
System.out.println("hello A");
}
} /*
这时由于子类覆写了父类的方法,所以调用的是子类覆写后的方法。
这是动态的多态。
*/ 2、是把一个子类的实例赋值给一个父类的问题,请看下面的程序:
class A
{
void print(){}
public static void main(String []args)
{
A [] a=new A[3];
a[0]=new B();
a[1]=new C();
a[2]=new D();
for(int i=0;i<a.length;i++)
{
a[i].print();
}
}
} class B extends A
{
void print()
{
System.out.println("hello B");
}
} class C extends A
{
void print()
{
System.out.println("hello C");
}
} class D extends A
{
void print()
{
System.out.println("hello D");
}
} /*
上面的程序执行的结果:
hello B
hello C
hello D 可以看出,程序不会调用父类的print()方法,再说父类print()方法根本什么也不做。这就是JVM (java虚拟机),能在程序运行时,动态的识别变量的类型。就像上面一样。这主要是考java的运行时的类型识别机制实现的,当然我认为这其实也可以看成是java多态的一种表现。
*/ 在java中子类是父类的实例,这就像是说 鱼是动物。但不能说动物就一定是鱼,这也是符合了人们对现实世界的认识规律。另外java为我们提供了一个关键字,在孙鑫的教程里面也讲到了吧。它是instanceof
你可以用这来判断一个对象是否是一个类的实例。还是上面的A ,B,C ,D类的例子:
在mian函数中写上下面的代码:(把原来的代码删掉)
B b=new B();
if(b instanceof A)
System.out.println("b instanceof A");
//输出:b instanceof A 说明b是A类的实例。 再看下面的例子。
A a=new B();
if(a instanceof B)
System.out.println("a instanceof B"); //输出:a instanceof B
但此时不能这样,B b=a;
虽然a是B的实例但是这里不能这样赋值,要像下面:
B b=(B)a;
//进行类型的强制转换 关于这部分你还是自己体会吧。
多态:一个对象变量可以指向多种实际类型的现象。
7.3.1. 方法的覆盖(overridding)
当子类从父类继承一个无参方法,而又定义了一个同样的无参方法,则子类新写的方法覆盖父类的方法,称为覆盖。(注意返回值类型也必须相同,否则编译出错。)
如果方法参数表不同,则成重载。
特点:
1.对于方法的访问限制修饰词,子类方法要比父类的访问权限更高。
父类为public,那么子类为private则出现错误。
2.子类抛出的异常应该是父类抛出的异常或其子类
7.3.2. 多态的分类
多态分两种:
1编译时多态:编译时动态重载;
2运行时多态:指一个对象可以具有多个类型,方法的覆盖
这样对于对象而言分为:
理解运行时多态:
Car c = new Bus();
Car编译时类型 编译时检查变量类型是否存在,是否有调用的方法
Bus运行时类型 实际运行是访问heep中的对象,调用实际的方法。
运行时多态是由运行时类型决定的
编译时多态是由编译时类型决定的
猫,小鸟,狗 都是动物,都可以安上动物的标签。
Interface Animal{}
Class Car implements Animal{}
Class Bird implements Animal{}
Class Dog implements Animal{}
方法中
Animal a = new Car();
Animal b = new Bird();
Animal c = new Dog();*方法重载看的是参数的编译时类型public class Animal{
public static void main(String[] args){ }
}
(1) 是覆盖吗?不能多态了
abstract class MyClass{
priavate void m();
}
class Sub extends MyClass(){
public void m();
}
(2) 错误的修饰符组合
abstract class MyClass{
priavate abstract void m();
}
class Sub extends MyClass(){
public void m();
}
(3) 5.0 新 非覆盖
abstract class MyClass{
private final void m();
}
class Sub extends MyClass(){
public void m();
}
运行时多态的三原则
1.对象不变;(改变的是主观认识)
2.对于对象的调用只能限于编译时类型的方法,如调用运行时类型方法报错。
在上面的例子中:Animal a=new Dog();对象a的编译时类型为Animal,运行时类型为dog。
注意:编译时类型一定要为运行时类型的父类或者同类型。
对于语句:Dog d=(Dog)a。将d强制声明为a类型,此时d为Dog(),此时d就可以调用运行时类型。注意:a和d指向同一对象。
3.动态类型判定实际调用的方法。即它调用覆盖后的方法。
重载,从字面上看,建议读成(zhong 第四声)载,意思就是说,一辆客车本来只能坐20个人,而实际上坐了30人,我们说它超重了,也就是重载了。引深到程序设计语言中,就是说同一个名字的方法有多个实现,通过参数列表的不同来区别。比如
f(), f(int a), f(String str), f(int a, int b)就是重载。
重写,读成(chong 第二声)写,就是子类重新实现父类已经实现过的方法。
要理解多态,首先必须了解“类”和“对象”的区别:
类是广泛的概念,指一个群体,类别。
对象(又叫实例)是具体的东西。
比如说“人”是一个类,而“克林顿”就是“人”类的一个对象。
多态,简单点说,就是一个对象同时拥有多种类型。
看看一个模型:
class 动物class 哺乳动物 extends 动物
class 鸟类 extends 动物 class 人 extends 哺乳动物
class 麻雀 extends 鸟类
class 百灵鸟 extends 鸟类1、如果我现在养了一只百灵鸟,那么我有一个“百灵鸟”的对象(也叫实例)。我可以说,我有一个“鸟”(父类)的对象,也可以我有一个“动物”的实例。
所以,子类向父类、爷爷类造型是自动的:
动物 obj = new 百灵鸟();2、如果我养了一只“鸟”,那么可能我养的是“麻雀”,也可能是“百灵鸟”。因此,父类向子类造型存在其可能性,但也可能会失败,在程序中应该进行类型检查:
鸟 obj = ...... // 从程序其它地方得到一个“鸟”的对象。
if(obj instanceof 百灵鸟){
百灵鸟 obj1 = (百灵鸟)obj;
}所以,相对而言,父类是比较“泛”的类型,而子类是更加“精确”的类型。3、后面的就不想总结了,楼主在图上画一棵类的继承树,然后想一想“人”可不可以造型成“鸟”。并且按着这个思路下去,再多添加一些子类,看看哪种情况可以造型,哪种情况不能造型。多态的好处,总结一下就是:可以使程序员关心他想要的类型,而忽略其它类型。
比如一个考勤模型:
class 员工
class 会计 extends 员工
class 出纳 extends 员工
class 清洁工 extends 员工
class 工程师 extends 员工在考勤时,系统应该记录“员工”的上下班时间,在这里他关心的类型是泛类型“员工”,而不是精确类型(子类)。因此,上下班的方法应该定义在“员工”类,子类继承这个方法。java中的多态还涉及到接口问题。
因为为了简单,java取销了多继承,也就是一个类最多只能继承一个父类。因此问题就来了:当一种类型需要同时具有两个以上的类型,而这两个类型没有什么逻辑关系时怎么办。
比如说一个模型:
class 动物
class 人 extends 动物
class 男人 extends 人
class 女人 extends 人
而我们需要另外一些类型:医生、老师、司机等。
现在需要一种类型,他同时是人,还必须是医生和司机。而java中如果继承了“人”,则不能再继承“医生”和“司机”。
所以,java中新增加了“接口”,旦一个类实现了某个接口,则这个类的对象也具有了接口的类型。
interface 医生
interface 老师
interface 司机class MyClass extends 男人 implements 医生, 司机那么可以:
医生 obj = new MyClass();
另外,异常抛出来的其实也是继承自 Exception 类对象。在一个类的方法声抛出异常之后,子类如果重写这个方法时,能够声明抛出的异常将会是有限制的:
class Father{
public void f() throws Exception_1{
// ......
}
}
class Sun extends Father {
public void f() throws Exception_1_1, Exception_1_2{
}
}Exception_1 和 Exception_1_1, Exception_1_2 之间必然会有一定的关系。这里我就不多说了,楼主顺着上面的思路,自己总结一下。