+ M3 f1 M; }" m$ N9 k `前言7 h( p- z0 c! T$ g v9 p
# Y/ B, s3 ^: A% R, x& B3 ?4 {9 v5 x
社会中就有继承的概念(百度百科):继承是指一个对象直接使用另一对象的属性和方法。也指按照法律或遵照遗嘱接受死者的财产、职务、头衔、地位等。这个解释中的前一句正说明了我们要今天要讲的对象(继承)的大体特性。 3 A6 p! r1 g7 o% ~4 F: Q. n t/ ^. x$ K
9 m- z5 R, T; e. y& P' y: a
2 `4 v2 F7 b7 B) @& r6 N在写Java时用到继承的情况有? * n$ q' M* X8 m! j6 X( W/ }+ Y * y8 C4 V, Y. j当我们准备编写一个类时,发现某个类已有我们所需要的成员变量和方法,假如我们想复用这个类的成员变量和方法,即在所编写类中不用声明成员变量就相当于有了这个成员变量,不用定义方法就相当于有了这个方法,那么我们可以将编写的类声明为这个类的子类即继承。$ F5 g2 M) Z1 V: W. r
" h6 K% }/ v1 L2 W$ V& n
小知识: # [5 @0 g6 k& Q 8 x0 G. M0 b8 v3 W- z3 `4 C源类,基类,超类或者父类都是一个概念% V% U8 q3 P4 k8 E. F, J" @, }) l
1 Z# P( F5 S$ m( j
导出类,继承类,子类也都是同一个概念 ( y2 E9 \& B; O, k* U! \ 3 K- a5 Y$ c) _, `6 h' L3 W- o继承的语法. I! ?; e& ?# t* g! p
6 a; I/ d, h; M$ Q9 g在类声明中,使用关键字extends来声明一个类的子类: ) u9 p) }9 V0 R3 y3 M) j1 ~9 F% c% X, W r. |5 y2 J
class 子类名 extends 父类名 { . ^4 X+ P) D" h- v F6 }. C+ |5 i) x3 B' g& i4 ?
… ! O; s; _1 [1 x ! q9 Z) U& t0 P) C8 o$ l) v% Z7 U}( \* ?2 Q4 u- G3 D
! @% P* J; [! b! K 注意:如类声明语句中没有extends子句,则该类为java.lang包中的Object的子类。这就说明了java中的代码其实都有一个继承的关系,只不过是继承Object这个java中最根本的父类。& a) z4 w- f9 l7 |9 t# y
1 G+ |$ F, i2 I, M( D
继承的特点6 W# Y% }- c ~+ v
4 {8 C5 K; A9 r9 \' E子类拥有父类非private的属性和方法,子类继承的父类方法和成员变量可以当作自己的方法和成员变量一样被子类的实例方法使用。$ b) h- t" S2 j, i* T
子类可以有自己属性和方法,即子类可以在父类的基础上对父类进行扩展。* q$ f6 J+ ?' W, y
子类可以用自己的方式实现父类的方法。(重写或者覆盖) # y" L6 `) {+ c% U( z5 F9 U' u2 g+ C
访问权限和继承之间的关系 8 p3 w9 r4 q9 F- l& Q9 o, ^# H, u " _+ W% J( ?5 e* o5 F$ T" G! }访问限制修饰符限制对象对成员变量操作和方法调用,也限制继承性2 x/ k+ |4 Z# }. s' \
$ m, L+ v5 ]1 ^9 i0 Y( b 3 B" r: U' J( \2 a4 b) F构造器对继承的影响 / l1 g+ J1 m9 f% w% r0 g; R* s4 @" [" j' U. m9 [( l: K: X b; N% ^: v
什么是构造器: ; Z" C7 S2 G G, ?- L( g2 T
6 l* {; [. L" W" r& }# R2 W- v构造器,也称构造方法、构造函数。作用是构造出来一个类的实例,确保对象得到初始化。. S$ l+ q4 E, a6 W$ K4 T# C. n9 _
构造器的格式: 权限修饰符 类名(无参/有参){}。 ( r5 w2 x, s- B5 T% g9 s$ ~根据有无参数,可分为无参构造 和有参构造。 # Z- T0 d. k4 p
构造器的特性: 8 O! F i& O7 C2 O 7 [5 _! S0 c! v- ?/ G8 d与一般方法名不同的是,构造方法名必须和类名保持一致,并且没有返回值。 ! M* V/ I3 z7 k# eJava编译器会自动创建无参构造函数,因此在类中,无参构造即使没有,我们也可省略不写。实例化对象时无需赋值。 - e6 b2 u$ V* o) Z9 `- E倘若类中已存在有参构造函数,则编译器不再提供默认无参构造。实例化对象时需赋值,不然报错。 " t) {3 G. U3 o& Z当类实例化一个对象时会自动调用构造方法。 5 r, u& `( e `- G/ g构造器在Java的继承中会产生什么影响呢? 7 Z, ]2 @- v' h! ?3 V& O' T / W1 d- X7 u( c) q) }2 M我们虽然继承了父类但是父类的构造器是我们子类继承不了的,我们只能去调用父类的构造器。那么在继承并且编写子类的构造方法的时候就要注意两种情况了:1.父类没有重写了构造函数(即构造函数是Java默认给的一个构造函数);2.父类重写了构造函数。 + ]7 Q6 m2 U8 D; [3 C! U5 B# F% ]) d7 W
父类使用默认构造器 5 V% f X; B+ E' v6 R- l: k# l0 r& ^" T
package Extends;# N, u7 n" d: D5 Y4 s
I9 N; z! ~8 @( A: p1 |6 `5 Xpublic class Father {3 j3 y! \1 j) Q9 L& W
Father(){ //默认的看不出区别所以这边设置个无参构造器效果一样的. u, V1 u+ t) O e, Q& A8 z
//当你不定义的时候就是这个构造器 ) n$ Z# l% ?' ^6 Z# \! D1 j/ A System.out.println("This is Father Constrctor");. U+ F; e* Z7 V& a
}% M% N' Y' S# J* s9 l5 u
} 3 F1 b( o1 ^. ^2 k% Y4 dpackage Extends;% _1 I, p' w* S6 ]5 V" J% x6 l
) e1 \& F9 o2 E ^4 v" h
public class Nosuper extends Father{9 ^& n; O, e* o& K) g1 G# S: J* Y
Nosuper(){ //定义子类的构造器8 C! B- l) o1 f
System.out.println("This is Nosuper Constrctor");8 Z }" _% P2 u; i7 B h
} 9 D9 }# J& }- t5 K3 q0 ?% T' A2 {* `& @' d9 D0 e
public static void main(String[] args) { : P# E# W# M2 P% P // TODO Auto-generated method stub4 {2 {8 U; c5 m' y3 n2 M' N/ c2 d2 z
Nosuper no=new Nosuper(); 7 e' k: o6 ^# q; `+ Q- m) i- V# v }4 b b: R! s. T. Y. c( x' P
1 P$ j8 E, Y( z6 ^. G7 I}9 q6 W9 H( d7 `2 M4 j X8 O
OUTPUT:( b( \6 Q* R, K& D* ]: C
This is Father Constrctor 9 n) `" l# d" d, W/ PThis is Nosuper Constrctor 6 d; ~8 l8 o) E父类不使用默认构造器 % l7 i- O0 L0 O& ~1 U2 x. Z( J5 q 7 H+ ^6 }0 N9 S& n% spackage Extends; 5 ~8 D7 Z) ^6 B: _5 r2 G: ]: ~2 N- e4 E# w5 _
public class Father { ' t* z2 H: v+ q0 o$ P9 h" R Father(String name){ f; a7 |6 u0 ~ System.out.println("This is Father Constrctor,name is "+name); & Z" b" \8 g V3 p } ( ?' U7 k+ }$ u$ S2 x} 7 T! ^0 X4 ?6 r$ @( c9 w5 a1 gpackage Extends; , c3 g V# p9 }# J' i. V. s0 H. M# A# H4 j. a4 ^
public class Nosuper extends Father{6 c, ?+ a" I/ S$ v! x: D# s
Nosuper(){ 0 d$ n* [! t( y0 E, e
super("YYH"); //必须先调用父类的构造函数否则会报错7 O( g p5 r% T' ]- F: m) N
System.out.println("This is Nosuper Constrctor");3 @$ ]2 N# J& }0 C+ t& ?' I$ ~
}/ J3 i7 z$ i h1 P
public static void main(String[] args) { Z2 K+ t/ Z$ e$ z9 a
// TODO Auto-generated method stub$ R5 b6 o( ^$ T4 M/ Y' |( N: L
Nosuper no=new Nosuper(); / W( ~, b4 f( w& s& i% R }" {7 ?9 d% |: |% j) j
}7 f% M$ G1 |$ d! m
OUTPUT:) E# j k' f0 F5 W
This is Father Constrctor,name is YYH & E" A [$ `& wThis is Nosuper Constrctor4 W { n# ]5 e/ `5 R& q
总结:对于继承来说,子类会默认调用父类的构造器,但是如果没有默认的父类构造器,子类必须要调用父类的构造器,而且必须是在子类构造器中做的第一件事(第一行代码)。 # }$ s \8 F$ D1 @2 F- u 9 Z# a/ R' f I# {8 g9 @2 U" v# { 6 M4 V0 B& s7 K/ t, z" X- B6 L1 x$ O5 |" K: {
继承中的向上转型/ _1 v! l# x5 V
4 c/ K) r- _7 a7 y0 v" w
当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法,但是它仍然要根据继承链中方法调用的优先级来确认方法,该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。4 Y: z7 g6 l: e* T6 U) `9 |3 x5 v
) U6 A; J. \0 ?* D2 Opackage _4_8; $ u' W7 j/ G& S3 d2 l, X 3 s( _0 ^. `- V4 Q& Kclass A {6 H9 ~* z+ N1 w5 H% b$ B
public String show(D obj) { : m0 v" [4 a0 L: k' u4 g; L return ("A and D"); ' H$ U: C: a2 M- W } : H7 L' U: o8 c5 J! B8 S public String show(A obj) { ' U' ?4 d) B0 B2 f1 [) {! s. e W. d return ("A and A"); 0 w" q B b, Y) q- e p } ' W/ _! l8 s' g# q8 Y3 r# u
8 q* O/ ]$ a# A& _/ W: ?6 c3 M$ t} * l7 P/ V; T' s % F* o2 v9 w) i1 G) ~% c2 l0 F) M& o7 K
class B extends A{ ' \0 f* x9 Y% `3 { //重载% m+ k2 y4 q- Z. y
4 I( I! g) t$ ~# G) ]. k( Z% X1 h8 z- F
public String show(B obj){ 4 f, ~; ^0 q4 K \ return ("B and B");; e7 }. p* B* Q" D1 T* ]
} : B/ P; A: t# @4 B4 t //重写! y7 `7 ^9 j" \" F
public String show(A obj){ 7 c4 v- s& I( J# O+ ~: G- n; f6 L, J return ("B and A"); " |* U+ J8 `$ E. w } / K; I0 K- F' h