class A {
public int i = 1;
public static int j = 11;
public static String m1() { return "类A的静态方法m1."; }
public String m2() { return "类A的实例方法m2."; }
public String m3() { return "类A的实例方法m3."; }
}
class B extends A {
public int i = 2;
public static int j = 22;
public static String m1() { return "类B的静态方法m1."; }
public String m2() { return "类B的实例方法m2."; }
}
public class Output02 {
public static void main(String[] args) {
A x = new B(); //x是A的一个实例,所以无法访问子类定义的新成员和新方法
System.out.println("(1)x.i: " + x.i); //(1)x.i: 1
System.out.println("(2)(B)x.i: " + ((B) x).i); //(2)(B)x.i: 2
System.out.println("(3)x.j: " + x.j); //(3)x.j: 11
System.out.println("(4)(B)x.j: " + ((B) x).j); // (4)(B)x.j: 22
System.out.println("(5)x.m1(): " + x.m1()); //(5) x.m1(): 类A的静态方法m1.
System.out.println("(6)(B)x.m1(): " + ((B) x).m1()); //(6)(B)x.m1(): 类B的静态方法m1.
System.out.println("(7)x.m2(): " + x.m2()); //(7)x.m2(): 类B的实例方法m2.
System.out.println("(8)x.m3(): " + x.m3()); //(8)x.m3(): 类A的实例方法m3
}
}
注:该程序考察的是,java的继承、多态、方法重写、方法覆盖
class A extends B :
A a = new B(); 结果a是一个A类的实例,只能访问A中的方法,那么又和A a = new A();有什么区别呢?
class B extends A
继承过后通常会定义一些父类没有的成员或者方法。
A a = new B();
这样是可以的,上传。
a是一个父类对象的实例,因而不能访问子类定义的新成员或方法。
假如这样定义:
class A{
int i;
void f(){}
}
class B extends A{
int j;
void f(){}//重写
void g(){}
}
然后:
B b = new B();
b就是子类对象的实例,不仅能够访问自己的属性和方法,也能够访问父类的属性和方法。诸如b.i,b.j,b.f(),b.g()都是合
法的。此时 b.f()是访问的B中的f()
A a = new B();
a虽然是用的B的构造函数,但经过upcast,成为父类对象的实例,不能访问子类的属性和方法。a.i,a.f()是合法的,而
a.j,a.g()非 法。此时访问a.f()是访问B中的f()
==========================================================
A a = new B(); 这条语句,实际上有三个过程:
(1) A a;
将a声明为父类对象,只是一个引用,未分配空间
(2) B temp = new B();
通过B类的构造函数建立了一个B类对象的实例,也就是初始化
(3) a = (A)temp;
将子类对象temp转换为父类对象并赋给a,这就是上传(upcast),是安全的。
经过以上3个过程,a就彻底成为了一个A类的实例。
子类往往比父类有更多的属性和方法,上传只是舍弃,是安全的;而下传(downcast)有时会增加,通常是不安全的。
===========================================================
a.f()对应的应该是B类的方法f()
调用构造函数建立实例过后,对应方法的入口已经确定了。
如此以来,a虽被上传为A类,但其中重写的方法f()仍然是B的方法f()。也就是说,每个对象知道自己应该调用哪个方法。
A a1 = new B();
A a2 = new C();
a1,a2两个虽然都是A类对象,但各自的f()不同。
===========================================================
[b]子类调用父类构造方法:super关键字[/b]
在构造子类对象时,JVM会先调用父类的构造方法;
子类构造方法中可以通过super语句调用父类的构造方法;
如果子类构造方法中,没有通过super语句调用父类构造方法,那么JVM会调用父类的默认构造方法,如果不存在默认构造方法,将导致编译错误。
public int i = 1;
public static int j = 11;
public static String m1() { return "类A的静态方法m1."; }
public String m2() { return "类A的实例方法m2."; }
public String m3() { return "类A的实例方法m3."; }
}
class B extends A {
public int i = 2;
public static int j = 22;
public static String m1() { return "类B的静态方法m1."; }
public String m2() { return "类B的实例方法m2."; }
}
public class Output02 {
public static void main(String[] args) {
A x = new B(); //x是A的一个实例,所以无法访问子类定义的新成员和新方法
System.out.println("(1)x.i: " + x.i); //(1)x.i: 1
System.out.println("(2)(B)x.i: " + ((B) x).i); //(2)(B)x.i: 2
System.out.println("(3)x.j: " + x.j); //(3)x.j: 11
System.out.println("(4)(B)x.j: " + ((B) x).j); // (4)(B)x.j: 22
System.out.println("(5)x.m1(): " + x.m1()); //(5) x.m1(): 类A的静态方法m1.
System.out.println("(6)(B)x.m1(): " + ((B) x).m1()); //(6)(B)x.m1(): 类B的静态方法m1.
System.out.println("(7)x.m2(): " + x.m2()); //(7)x.m2(): 类B的实例方法m2.
System.out.println("(8)x.m3(): " + x.m3()); //(8)x.m3(): 类A的实例方法m3
}
}
注:该程序考察的是,java的继承、多态、方法重写、方法覆盖
class A extends B :
A a = new B(); 结果a是一个A类的实例,只能访问A中的方法,那么又和A a = new A();有什么区别呢?
class B extends A
继承过后通常会定义一些父类没有的成员或者方法。
A a = new B();
这样是可以的,上传。
a是一个父类对象的实例,因而不能访问子类定义的新成员或方法。
假如这样定义:
class A{
int i;
void f(){}
}
class B extends A{
int j;
void f(){}//重写
void g(){}
}
然后:
B b = new B();
b就是子类对象的实例,不仅能够访问自己的属性和方法,也能够访问父类的属性和方法。诸如b.i,b.j,b.f(),b.g()都是合
法的。此时 b.f()是访问的B中的f()
A a = new B();
a虽然是用的B的构造函数,但经过upcast,成为父类对象的实例,不能访问子类的属性和方法。a.i,a.f()是合法的,而
a.j,a.g()非 法。此时访问a.f()是访问B中的f()
==========================================================
A a = new B(); 这条语句,实际上有三个过程:
(1) A a;
将a声明为父类对象,只是一个引用,未分配空间
(2) B temp = new B();
通过B类的构造函数建立了一个B类对象的实例,也就是初始化
(3) a = (A)temp;
将子类对象temp转换为父类对象并赋给a,这就是上传(upcast),是安全的。
经过以上3个过程,a就彻底成为了一个A类的实例。
子类往往比父类有更多的属性和方法,上传只是舍弃,是安全的;而下传(downcast)有时会增加,通常是不安全的。
===========================================================
a.f()对应的应该是B类的方法f()
调用构造函数建立实例过后,对应方法的入口已经确定了。
如此以来,a虽被上传为A类,但其中重写的方法f()仍然是B的方法f()。也就是说,每个对象知道自己应该调用哪个方法。
A a1 = new B();
A a2 = new C();
a1,a2两个虽然都是A类对象,但各自的f()不同。
===========================================================
[b]子类调用父类构造方法:super关键字[/b]
在构造子类对象时,JVM会先调用父类的构造方法;
子类构造方法中可以通过super语句调用父类的构造方法;
如果子类构造方法中,没有通过super语句调用父类构造方法,那么JVM会调用父类的默认构造方法,如果不存在默认构造方法,将导致编译错误。