多态有一种情况是,父类应用指向子类对象:
父亲 fu = new 儿子();
这个时候如果父亲中有变量(包括静态和非静态变量)或者静态方法,都不会被儿子覆盖和重写。他们在内存中占用的是两块地方。
而非静态方法则会被重写。
内存中该对象的内容:
父类的成员变量 ①
父类的静态方法 ①
子类的成员变量 ②
子类的静态方法 ②
父类中未被重写的非静态方法 ③
父类中被子类重写的非静态方法 ③
子类自己新写的方法 ④
当引用是父类型的时候指向 ① ③
当引用是子类型的时候指向 ② ③ ④
引用的类型被强制转换的过程中内存中的数据都是同一组数据。
所以我们常用的方式是private 属性 加 get set方法方式,这样对大部分人来说不会太乱。
参考测试代码如下:
class Fu{
static int fu = 0;
int zi = 0;
public void me(){
System.out.println("Wo Shi Fu");
}
public static void staticMethod(){
System.out.println("Fu de static method");
}
}
class Zi extends Fu{
static int fu = 1;
int zi = 1;
public void me(){
System.out.println("Wo Shi Zi");
}
public static void staticMethod(){
System.out.println("Zi de static method");
}
}
public class Test2 {
public static void main(String[] args) {
Fu x = new Zi();
System.out.println(x.fu);
System.out.println(x.zi);
x.me();
x.staticMethod();
System.out.println("-------------华丽的分割线------------------");
//如果这个时候改变x中的变量
x.fu=99;
x.zi=99;
//强制转换成子对象
Zi y = (Zi)x;
System.out.println("-------------强制转换成子类类型后的内容------------------");
System.out.println(y.fu);
System.out.println(y.zi);
y.me();
y.staticMethod();
System.out.println("-------------华丽的分割线------------------");
y.fu = 88;
y.zi = 88;
System.out.println("-------------强制转换成子类类型后----再次强制转换为父类类型的内容------------------");
Fu a = (Fu)y;
System.out.println(a.fu);
System.out.println(a.zi);
a.me();
a.staticMethod();
System.out.println("-------------强制转换成子类类型后----再次强制转换为父类类型的内容------------------");
Zi b = (Zi)a;
System.out.println(b.fu);
System.out.println(b.zi);
b.me();
b.staticMethod();
}
}
输出:
0
0
Wo Shi Zi
Fu de static method
-------------华丽的分割线------------------
-------------强制转换成子类类型后的内容------------------
1
1
Wo Shi Zi
Zi de static method
-------------华丽的分割线------------------
-------------强制转换成子类类型后----再次强制转换为父类类型的内容------------------
99
99
Wo Shi Zi
Fu de static method
-------------强制转换成子类类型后----再次强制转换为父类类型的内容------------------
88
88
Wo Shi Zi
Zi de static method
以上仅代表个人观点,奉劝大家尽信书不如无书,书也是人写的。
附:
多态关于反射的拓展:
package test.test; import java.lang.reflect.Method; public class Test2 { public static void main(String[] args) throws Exception { test(new hi()); } public static void test(Object obj) throws Exception { System.out.println(obj); Object object = hi.class.newInstance(); Method mtd = hi.class.getDeclaredMethod("print", null); mtd.setAccessible(true); mtd.invoke(object, null); } } class hi{ public String toString() { return "hi"; } private void print() { System.out.println("invokeOk"); } }
输出结果:
hi
invokeOk
调用test方法时,传入参数相当于Object obj = new hi();
这个时候内存中是有print方法的,虽然obj没有指向这个方法。
当用反射调用某个对象的某个方法时的时候,反射技术不会关心这个对象的引用有没有指向指向这个方法,而是关心这个对象所指向的内存中有没有这个方法。