) Y* D. {5 ^) _% J父类使用默认构造器 , I6 Y# Q- k2 x& X9 z+ Z # J0 S& N: b6 v: b' `% L: v父类不使用默认构造器) w. L8 h0 O0 G: f. H- V0 u
* b- s: h5 \5 k: K8 O继承中的向上转型7 y5 U P. S1 n$ I$ l" u: k
+ M+ Z& @, T" \. |
继承慎用 ' z, a" p; G6 b9 o @ # d/ S7 A; w$ ?后言 - W: o" {0 [3 D7 ^* u( o1 ^9 w- ?4 z 2 q, G$ K! ^% `# a9 ~$ Q3 c9 S& x7 Q% P1 E/ f1 Z% _
4 s5 D6 w8 W2 `) K. |; }前言 ( b ?0 I" p. Q" d4 w8 B8 p; A) |% I" e$ P% a
社会中就有继承的概念(百度百科):继承是指一个对象直接使用另一对象的属性和方法。也指按照法律或遵照遗嘱接受死者的财产、职务、头衔、地位等。这个解释中的前一句正说明了我们要今天要讲的对象(继承)的大体特性。 : ]2 B. y1 L4 [( n2 i 5 D! p2 O4 F7 I c, {+ w2 e( y& p
+ S8 ]2 _. V! X1 L; [1 K
在写Java时用到继承的情况有?( U7 `, N' m1 V
# U. O% o K; N当我们准备编写一个类时,发现某个类已有我们所需要的成员变量和方法,假如我们想复用这个类的成员变量和方法,即在所编写类中不用声明成员变量就相当于有了这个成员变量,不用定义方法就相当于有了这个方法,那么我们可以将编写的类声明为这个类的子类即继承。9 I, N4 E" h& k4 r+ E
6 M" T+ O6 c w小知识: & w: p; } O* B } 3 i4 X( G: t' w( `: F7 Y u: @源类,基类,超类或者父类都是一个概念 8 D i- [1 x* C3 y # z, o$ g% E0 V5 r导出类,继承类,子类也都是同一个概念 ! z! X% K( r: h 1 {; Y( k* D# t- B- ]继承的语法 # g% ~) t, j- i' J( l( s" h: j4 Z) u$ \# m: N
在类声明中,使用关键字extends来声明一个类的子类: {# D: a# f% b/ c) {
9 m5 G$ x% q+ ` l$ Q
class 子类名 extends 父类名 { 9 _8 k! d7 U* N 5 u+ `" W0 |& x) i9 u … + l+ ?" U$ A! i. C' U0 ]- Z$ f1 v+ f& m( v5 N8 E
} : n3 k" \: E O" t" h9 g3 }3 X % v7 _7 G) q( Z- n! A4 `0 b 注意:如类声明语句中没有extends子句,则该类为java.lang包中的Object的子类。这就说明了java中的代码其实都有一个继承的关系,只不过是继承Object这个java中最根本的父类。 , I' `) h! {! j1 N7 Z) Q+ \ : I/ g% v- N& ~4 [+ f继承的特点% o6 x9 U( X f
& B/ Q0 ?' [ z% Y8 e
子类拥有父类非private的属性和方法,子类继承的父类方法和成员变量可以当作自己的方法和成员变量一样被子类的实例方法使用。/ r) e% V0 f3 _- A$ i' v% n
子类可以有自己属性和方法,即子类可以在父类的基础上对父类进行扩展。( [: }; q$ O# u$ P* @, r
子类可以用自己的方式实现父类的方法。(重写或者覆盖) - J4 s5 L) r/ F, A% n访问权限和继承之间的关系# ~8 j% J6 i8 F! g
! X& S! l9 B% G ?1 _# g
访问限制修饰符限制对象对成员变量操作和方法调用,也限制继承性* B0 z, @5 d8 x$ @
6 V9 g# `; h+ x+ u. r当子类和父类在同一个包:父类private成员变量和方法不会被子类继承 ' O- Q5 W1 j; J3 c$ S' A当子类和父类不在同一个包:父类private和friend(默认)成员变量和方法不会被子类继承 % s- ^* z# R7 _' Q) e3 b' c; Z5 Y- [, K9 `
0 {: |8 ]& E- L: X7 l6 _
构造器对继承的影响 / r3 Q. @9 I/ ~; W; |7 p 6 s# l. J, M, A. S! U. |+ T9 v什么是构造器: % W0 K% M* d2 c# g$ o/ O; [
" ]& s7 N& R8 A0 o% D5 C3 X" E Y我们虽然继承了父类但是父类的构造器是我们子类继承不了的,我们只能去调用父类的构造器。那么在继承并且编写子类的构造方法的时候就要注意两种情况了:1.父类没有重写了构造函数(即构造函数是Java默认给的一个构造函数);2.父类重写了构造函数。 1 |) H( q1 H9 G2 A& p: J2 E" ?0 ~/ ~' r8 d8 b; ]* }; i
父类使用默认构造器 ! \5 j6 _% ?% M0 A ' d0 m4 D4 n7 }2 kpackage Extends; ) V" C, D$ P8 J" W2 q ; Q+ C/ N) y7 B6 Epublic class Father {$ e+ d$ r( j5 E" r0 @: R
Father(){ //默认的看不出区别所以这边设置个无参构造器效果一样的 E6 J2 B% F4 |: X
//当你不定义的时候就是这个构造器 - D2 }) b$ Q: e1 S5 f& n System.out.println("This is Father Constrctor"); 2 {) f2 e5 c' m# T9 Z" V" M$ t4 z }1 @/ [4 {7 w F% \1 t+ [
} 3 i' O: p! ]( {3 g+ \1 N9 z Wpackage Extends;- j' s! u) W7 T9 Y' S
, y' F1 |# n5 P4 w" t) i9 D
public class Nosuper extends Father{ $ h0 s1 t! A# I$ E Nosuper(){ //定义子类的构造器 . t8 X: |6 Y- O9 h$ ]- k$ G System.out.println("This is Nosuper Constrctor"); ! X5 Z7 _ J* L9 S0 O: x( w% W } ' y: E! ]( G1 \* G. |/ e$ i7 f4 t! q; O2 h/ m6 |
public static void main(String[] args) {* C8 `8 @0 O0 c" p9 Q+ u6 ^, B
// TODO Auto-generated method stub + @2 b% T3 l% H& J# F' G Nosuper no=new Nosuper(); 3 s2 S4 r6 [! S* F) X6 y8 N5 ], Y) q } / h2 [9 M' o1 N& J$ Z9 g( V " i- @9 L' w9 J/ i7 V5 \! ~- R} \0 ^" K, D& C$ N) t( J3 b
OUTPUT:+ @/ @( F' t$ U& o# Y
This is Father Constrctor , n6 E; r# S4 {- O/ Z4 WThis is Nosuper Constrctor. J4 ?. f, s* c: C4 \8 T6 a: c# _
父类不使用默认构造器 8 G$ x7 U! M: @) \! e; R & \5 e2 X- e5 K9 jpackage Extends;+ z9 }8 U" ]% A! D& z# x8 a
+ m' k& K% \* m0 @( Cpublic class Father { ! c+ Q7 T9 l' C! f- b6 J, ]$ X Father(String name){7 c7 f5 j& L3 o7 K1 q+ U9 G3 @
System.out.println("This is Father Constrctor,name is "+name);3 }/ U Y) B" {( ]- P1 f7 W
} ) E; q" [4 K% y4 e6 a}3 _7 k5 x7 u% ^) G9 n# B4 W- H0 B) F
package Extends; - B: d9 a: p7 R- B3 Q' u4 p* y U3 _& r- f ~% C, R( J
public class Nosuper extends Father{; I* U! X4 j9 ?" N7 Y2 R, F% @5 ~
Nosuper(){ / M% R4 m8 g. C1 R8 d! T1 c$ k
super("YYH"); //必须先调用父类的构造函数否则会报错 1 K/ S9 G3 G( g% [. z2 g- d5 ~ System.out.println("This is Nosuper Constrctor");/ n1 B, _% R+ U4 i$ ?
}5 B1 @( {1 ~" o! s
public static void main(String[] args) {6 [! Q! o! O4 o! t# U1 Z: D
// TODO Auto-generated method stub % ~9 J( L, I( Y6 h \1 a Nosuper no=new Nosuper(); , P% x6 @: @' h9 V- j }" y6 m. I# D+ m# S4 J9 K
} $ b5 L: `& r4 \* e! d7 h; WOUTPUT:$ n$ _# d# {9 _' Y0 \
This is Father Constrctor,name is YYH) q! E& O2 Q2 l( z4 p! J
This is Nosuper Constrctor ' i ?; Y( K0 x6 J- ^总结:对于继承来说,子类会默认调用父类的构造器,但是如果没有默认的父类构造器,子类必须要调用父类的构造器,而且必须是在子类构造器中做的第一件事(第一行代码)。. u) j/ W2 z2 y, c. u9 E
8 p8 p( `1 N4 U4 T6 U: C
+ l% @0 O- `. D1 W' H1 A7 w
/ w6 F& E' G: ^, h: M( s继承中的向上转型 . r+ _+ X* v# ?0 r; V: s: m) `, Z$ K2 \, K
当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法,但是它仍然要根据继承链中方法调用的优先级来确认方法,该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。$ p) z, [' D+ d4 z) r
9 }: l' F, t) Mpackage _4_8;6 ^+ l- D ?* T( v1 B/ ^
H+ e2 t7 G! s* q+ p4 A
class A { 2 L3 ]; Z5 v! U h2 J public String show(D obj) {2 F: T X4 D( n* F
return ("A and D");7 t9 N8 {# A0 |' ~ G
} % j6 A/ b2 b3 h0 V: W/ q8 { public String show(A obj) { 9 l0 L6 y/ u: ?0 f: p8 f$ v return ("A and A");7 U! _. _3 X. |' W% v; {: n6 i7 A
} 7 d+ P/ \- `# |/ J3 T * H! H" c7 g) k6 l4 t! p} / o3 W( R8 B4 z( }) j$ T9 Q / \! u1 }: T7 y. a* v. F8 P# @- g; F/ i! }5 I" d
class B extends A{/ i% c! g y; R! {
//重载 / L; m6 }/ o+ M& E 4 z1 q. Z: `9 t* ^ public String show(B obj){6 @9 f2 Z: T& l5 l' v! [) _5 J& r
return ("B and B");; G" K3 i- U+ H$ F+ S
}, p. k: r( G0 m5 y; ]' L. o2 |
//重写 ; A9 g. ]& w, u6 ~ public String show(A obj){ - v& h9 K) R- y return ("B and A"); 5 X! ] i( N( N1 U( {6 K4 R- ^ } & n; I2 x+ w9 T y% x$ x
/ @5 e: _* o8 J8 A! B9 o}5 G% H2 e) i6 ]2 p
# @. d" R2 _! C) f- q- {2 f( } \/ m h! ?% _9 x/ b/ I
class C extends B{}- x: E% h/ g u, ?% U- q! @
class D extends B{} * }7 b3 U8 n3 S I" k }4 z1 cpublic class t {, P3 n; `" P) t4 X" c; Z# {/ h, l, T
public static void main(String[] args) { - m3 F1 s* G$ o. d3 G9 S8 c A a1 = new A(); - g/ r) q) D/ ?( a$ p2 m' O A a2 = new B(); //1.只能调用子类中重写父类的方法,不可以 * N: X# F) p( R# L) r4 Q+ H //调用重载的方法$ j5 ?) |7 B, }4 s( P6 W: q! \ C( a
B b = new B();: \# P4 D+ U8 T2 K( @- `0 c
C c = new C(); $ c7 O4 {; f8 T, h$ g D d = new D(); X5 [3 b) i. Y% y
System.out.println("1--" + a1.show(b)); ! A( `# ^+ V0 K/ [ System.out.println("2--" + a1.show(c));6 P N. E, ] t1 M
System.out.println("3--" + a1.show(d)); $ U6 w# u n6 I4 F3 `) @, E System.out.println("--------");) ^/ o7 Q, p7 g& Y
System.out.println("4--" + a2.show(b)); / |" f( W; H, d% Y) o0 E5 a* n System.out.println("5--" + a2.show(c)); # X/ i$ m4 U' p; |, B ? System.out.println("6--" + a2.show(d)); ) q* \4 J3 S6 @0 { | O System.out.println("6--" + a2.show(a1)); 0 i' S- l' H3 Y! e7 b System.out.println("*");# G8 ?! d& s {+ a1 O7 l& L
System.out.println("7--" + b.show(b));* Y. {6 ~& s6 Y* F8 m8 M( ^! K
System.out.println("8--" + b.show(c)); ( ]- C3 A/ N m) }) Y2 f System.out.println("9--" + b.show(d)); 9 Q" i. z& c' _9 q$ y0 ^# n }) o; `) C' O( N7 S
}# ]2 v d3 C1 ~+ h
OUTPUT:7 f. }5 v' d, o: d. ?
1--A and A 8 G" H& s& L/ [2--A and A7 w) x! b% S6 V* x | P. y
3--A and D 7 l8 b6 S) }& j2 u G% H-------- 2 ?4 r0 G3 o* W. X! Z' B- S8 ]4--B and A h+ }' w! a5 x! R
5--B and A6 G; W2 x' Q) r) j; H! @
6--A and D/ l% m4 J' I e/ p( D2 c
6--B and A0 @& B, |9 n3 P; ?, ] ~$ i
*' ?: d2 [' R: U
7--B and B A% F8 q9 x0 c+ u/ c. W' V
8--B and B2 R! L) K( M0 |3 S- |
9--A and D3 N4 O7 P1 a# y
仔细理解一下其中的代码不难理解其中向上转型在继承中的作用。按照this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)这个顺序一步一步的执行就会得到结果。6 q" [5 F8 r; R, m& Z