1,什么是多态?
2,向上转型和多态
public class GeometricFraph { public static void main(String[] args) { perimeter(new Square()); perimeter(new Circular()); } /** * 多态的形式调用方法 * @param geometric */ public static void perimeter(Geometric geometric){ //根据实际的实例调用对应的方法 geometric.perimeter(); } public static void perimeter(Square square){ System.out.println("Square"); //根据实际的实例调用对应的方法 square.perimeter(); } } /** * 几何类 */ class Geometric{ /** * 获得周长 */ public void perimeter(){ System.out.println("外围总长"); } } /** * 四方形 */ class Square extends Geometric{ /** * 四边形获得周长的方式 */ @Override public void perimeter(){ System.out.println("四边总长"); } /** * 四方形的宽度 * 扩展方法 */ public void width(){ System.out.println("宽度"); } } /** * 圆形 */ class Circular extends Geometric{ /** * 圆形获得周长的方式 */ @Override public void perimeter(){ System.out.println("圆圈总长"); } /** * 圆形的直径 * 扩展方法 */ public void diameter(){ System.out.println("直径"); } }
结果:
Square
四边总长
Geometric
圆圈总长
如上两个perimeter方法参数分别是Geometric基类和Square导出类(子类),调用perimeter方法时如果传入的是Square实例,调则用的是perimeter(Square square)方法。实际上如果没有perimeter(Square square) 方,则默认会进入perimeter(Geometric geometric)方法,就比如传入的new Circular()调用的是perimeter(Geometric geometric)方法,而且geometric参数准确调用了Circular的perimeter方法。
3,方法调用绑定
3.1 前期绑定
3.2 动态绑定
public static void main(String[] args) { getClassInfo(new Circular()); } public static void getClassInfo(Geometric geometric) { Class clazz = geometric.getClass(); System.out.println("Geometric参数实际的类" + clazz.getName()); System.out.println(Arrays.deepToString(clazz.getDeclaredMethods())); } 结果: Geometric参数实际的类:com.javaApi.override.Circular [public void com.javaApi.override.Circular.perimeter(), public void com.javaApi.override.Circular.diameter()]
从上打印的结果可以看出java运行时通过参数获取其class信息并识别具体实例,以及拥有的可调用的方法集合信息。RTTI通过类型完成动态绑定工作,关于RTTI和类信息以后会有笔记详解讲。
4,缺陷:"覆盖"私有方法(private方法)
/** * 几何类 */ class Geometric { /** * 对角线 */ private void diagonal(){ System.out.println("几何总长"); } } /** * 圆形 */ class Circular extends Geometric { /** * 对角线 */ public void diagonal(){ System.out.println("几何总长"); } }
注意,父类和子类都有diagonal方法,但它们俩没有任何关系,而且此方法也不支持多态,如果有访问权限(private只能本类调用访问权限),Geometric参数只会调用自身的diagonal方法。
4,缺陷:域和静态方法
class Geometric { public String name="几何"; public void getName(){ System.out.println("name:"+name); } } class Circular extends Geometric { public String name="圆形"; @Override public void getName(){ System.out.println("name:"+name+",super.name:"+super.name); } } public static void main(String[] args) { getName(new Circular()); } public static void getName(Geometric geometric) { geometric.getName(); } 结果: name:圆形,super.name:几何
4.1静态方法不支持多态
5,构造方法和多态
class Geometric { public String name="几何"; public void getName(){ System.out.println("name:"+name); } /** * 父类构造器 */ public Geometric(){ //调用getName()方法,且getName方法支持多态 getName(); } } class Circular extends Geometric { public String name="圆形"; @Override public void getName(){ System.out.println("name:"+name+",super.name:"+super.name); } } public static void main(String[] args) { getName(new Circular()); } public static void getName(Geometric geometric) { geometric.getName(); } 结果: name:null,super.name:几何 name:圆形,super.name:几何
通过结果分析,为什么第一次name为null,第二次又有值了呢?就上像提到的构造器调用顺序,new Circular()时会先调用父类的构造器并在父类构造器中调用了getName方法,而此时子类name值还没有初始化所以其默认值是null,而getName方法支持多态,所以在父类构造器中调用的是子类的getName方法,所以这就是结果name为null的原因。
6,协变返回类型
public static Geometric getGeometric() { return new Circular(); }
7,向下转型
//类型判断,co是否是Circular类型 if (co instanceof Circular){
Circular cc= (Circular)co;//向下转型 cc.getName();
}