重写/重载
重写指的是根据运行时对象的类型来决定调用哪个方法,而不是根据编译时的类型。所以静态方法不能被覆盖
。
(如果从重写方法会有什么特点来看,我们是不能重写静态方法的。虽然就算你重写静态方法,编译器也不会报错。也就是说,如果你试图重写静态方法,Java 不会阻止你这么做,但你却得不到预期的结果(重写仅对非静态方法有用)。重写指的是根据运行时对象的类型来决定调用哪个方法,而不是根据编译时的类型。让我们猜一猜为什么静态方法是比较特殊的?因为它们是类的方法,所以它们在编译阶段就使用编译出来的类型进行绑定了。使用对象引用来访问静态方法只是 Java 设计者给程序员的自由。我们应该直接使用类名来访问静态方法,而不要使用对象引用来访问。)
向上转型/向下转型
assume 两个类 Base 类 和 Agg 类,Agg 继承与 Base .
and 一个原则:父类引用指向子类对象,子类引用不能指向父类对象(不安全)。
1 向上转型
java
Base f1 = new Agg (); \\父类引用指向子类对象
左边叫 生成一个父类引用Father f1
右边叫 生成一个子类对象new Son()
f1 引用指向了内存堆中Son对象。
把子类对象直接赋给父类的引用叫向上转型,向上转型不用强制转换。向上转型就是父类引用指向子类对象,这里谁指向谁记着不方便,一个简单的记忆方法是 A a = new B(); 可以想象一个箭头 A a => new B(); namely, A 指向 B.
java
class Base{ public String getField(){ String name = "Base"; return name; } } class Agg extends Base{ public String getField(){ String name = "Agg"; return name; } }
java
public class test { public static void main(String[] args) { Base a = new Agg(); System.out.println(""+a.getField()); } }
output: Agg
动态绑定,覆盖了父类的函数
当我们调用a的方法的时候,我们会首先看看a对应的类有没有这个方法, 如果有并且被子类覆盖,这边就会调用子类的方法。
java
class Base{} class Agg extends Base{ public String getField(){ String name = "Agg"; return name; } } public class test { public static void main(String[] args) { Base a = new Agg(); System.out.println(""+ ((Agg)a).getField()); } }
output: Agg.
如果没有,编译器就认为Base没有这个函数,直接调用就会报错 (从这里也能看出向上转型会丢掉子类的一些信息)。
这时候吧a转换成Agg类型的对象,编译器就认为a是一个Agg 类型。可以调用Agg类的函数。
java
class Base{ public String getField(){ String name = "Base"; return name; } } class Agg extends Base{ public String getField(){ String name = "Agg"; return name; } } public class test { public static void main(String[] args) { Agg b = new Agg(); Base a = (Base)b; \\向上转型的另一个写法 System.out.println(""+a.getField()); } }
output: Agg
这道题是向上转型的另一个写法.
java
class Base{ public static String getField(){ String name = "Base"; return name; } } class Agg extends Base{ public static String getField(){ String name = "Agg"; return name; } } public class test { public static void main(String[] args) { Agg a = new Agg(); Base b = new Agg(); System.out.println(""+a.getField()); System.out.println(""+b.getField()); } }
output : Agg Base
静态函数不能覆盖
2 向下转型
java
Son s1 = (Son)f1;
把指向子类对象的父类引用,赋给子类引用叫向下转型,要强制转换。
java
Father f2 = new Father(); Son s1 = (Son)f2; //编译出错,子类引用不能指向父类对象
如
java
class Base{ public String getField(){ String name = "Base"; return name; } } class Agg extends Base{ public String getField(){ String name = "Agg"; return name; } } public class test { public static void main(String[] args) { Base a = new Base(); Agg b = (Agg)a; \\ 不会编译通过,这样向下转型不可以,不安全。 System.out.println(""+b.getField()); } }
向下转型:当比较对象的时候,向下转型是很有用的。
那应该如何安全的向下转型?
先向上 - 再向下
java
Base b = new Agg(); \\先向上 Agg a= (Agg)b; \\再向下
再贴一个向下转型实际应用场景的代码,比较对象:
java
public class Person { private String name; private int age; public boolean equals(Object anObject) { if (anObject == null) return false; /* The object being passed in is checked to see it's class type which is then compared to the class type of the current class. If they are not equal then it returns false */ else if (getClass( ) != anObject.getClass()) return false; else { /* this is a downcast since the Object class is always at the very top of the inheritance tree and all classes derive either directly or indirectly from Object: */ Person aPerson = (Person) anObject; return ( name.equals(aPerson.name) && (age == aPerson.age)); } } }