21 繼承及相關之修飾子、關鍵字
依據民法的親屬˙繼承篇,繼承者頂多只能獨得或均分被繼承者的所有財產,甚至還會被課一大筆遺產稅,繼承之後,被繼承者的財產就轉移了,換了個所有者。但Java的類別就不同了,除了得到被繼承類別的所有功能之外,還可自行修改及增添功能,當然也有一些不能達到所有原功能的一些限制,且原類別還存在,還可很博愛的被繼承。這大概也是Java的繼承關鍵字不使用inherits,而使用extends的關係吧!
[21-1父類別與子類別]
繼承是將類別的成員傳承給其他類別,可以多層的一直繼承下去,對被繼承(傳承)的類別稱為父類別(有時也稱為super類別、base類別),繼承(被傳承)的類別稱為子類別。所有類別的根源類別,也就是最頂端的類別為Object,任何沒有extends關鍵字指名繼承的類別,都是繼承自Object類別。
繼承使用extends關鍵字。
<格式>
class 子類別名稱 extends 父類別名稱 { 子類別變更敘述 }
[21-2單純繼承]
子類別繼承時,對父類別成員不作任何變更,是為單純繼承,當然類別名稱也不同,單純繼承比較像人類的繼承。此時「子類別變更敘述」之部分為空白。
<範例>
class Inhfat1 {
int x = 7 ;
char y = 'a' ;
void inhmd( ) {
System.out.println(y + "=" + x) ; } }
class Inhson1 extends Inhfat1{ } // { }內為空白
class Inhmain1 {
public static void main(String[ ] args) {
Inhson1 aaa = new Inhson1( ) ;
Inhson1 bbb = new Inhson1( ) ;
aaa.inhmd ( ) ; //a=7
bbb.x = 10 ;
bbb.inhmd ( ) ; // a=10
aaa.x = 11 ;
aaa.y = 'k' ;
aaa.inhmd ( ) ; } }
執行結果:C:\js>java Inhmain1
a=7
a=10
k=11
[21-3增加父類別成員以外成員之繼承]
除了繼承父類別所有成員之外,子類別並新增欄位、方法等成員。
<範例>
classInhfat2 {
int x = 7 ;
char y = 'a' ;
void inhmd1( ) {
System.out.println(y + "= " + x) ;
}
}
class Inhson2 extends Inhfat2{
int z = 9 ; //新增欄位
void inhmd2( ) { //新增方法
System.out.println("x+z= " +( x+z)) ;
}
}
class Inhmain2 {
public static void main(String[ ] args) {
Inhson2 ccc = new Inhson2( ) ; //建立物件
ccc.x = 11 ;
ccc.y = 'm' ;
ccc.z =18 ;
ccc.inhmd1( ) ;
ccc.inhmd2( ) ;
}
}
執行結果:C:\js>java Inhmain2
m= 11
x+z= 29
[21-4覆寫(override)]
在子類別裡定義一個方法,其名稱、參數、傳回值(同回傳值)型別與父類別完全相同,但是其內容不同,藉以取代父類別之方法。5.0版本另增加傳回值型別不同之覆寫。
<範例>
class Inhfat3 {
int x = 7 ;
char y = 'a' ;
void inhmd( ) {
System.out.println(y + "=" + x) ;
}
}
class Inhson3 extends Inhfat3{
int z = 9 ;
void inhmd( ) {
System.out.println("x+z=" + (x+z)) ;
}
}
class Inhmain3 {
public static void main(String[ ] args) {
inhson3 ddd = new inhson3( ) ;
ddd.z = 11 ;
ddd.x = 14 ;
ddd.y = 'm' ;
ddd. inhmd( ) ;
}
}
執行結果:C:\js>java Inhmain3
x+z=25
[21-5 private修飾子與繼承]
[21-5-1 private成員繼承後無法使用]
父類別private成員,子類別繼承後無法使用,也無法將父類別建立物件使用。
[範例]
class Inhfat4 {
private int x = 7 ;
char y = 'a' ;
void inhmd1( ) {
System.out.println(y + "=" + x) ; } }
class Inhson4 extends Inhfat4{ //繼承
int z = 9 ;
void inhmd2( ) {
System.out.println("x+z=" + (x+z)) ; } }
class inhmain4 {
public static void main(String[ ] args) {
Inhfat4 eee = new Inhfat4( ) ; //父類別建立物件
eee.x = 10 ;
eee.inhmd1( ) ;
Inhson4 fff = new Inhson4( ) ; //子類別建立物件
fff.x = 15 ;
fff.inhmd1( ) ;
fff.inhmd2( ) ; } }
編譯結果:C:\js>javac inhmain4.java
inhmain4.java:10: error: x has private access in Inhfat4
System.out.println("x+z=" + (x+z)) ; } }
^
inhmain4.java:15: error: x has private access in Inhfat4
eee.x = 10 ;
^
inhmain4.java:18: error: x has private access in Inhfat4
fff.x = 15 ;
^
3 errors
[21-5-2透過非private的方法可存取private欄位]
class Inhfat5 {
private int x = 7 ;
char y = 'a' ;
void inhmd( ) {
System.out.println(y + "=" + x) ;
}
}
class Inhson5 extends Inhfat5{
int z = 9 ;
}
class Inhmain5 {
public static void main(String[ ] args) {
Inhfat5 hhh = new Inhfat5( ) ;
hhh.inhmd( ) ;//透過非private的方法可存取private成員x
Inhson5 iii = new Inhson5( ) ;
iii.inhmd( ) ; //透過非private的方法可存取private成員x
}
}
執行結果:C:\js>java Inhmain5
a=7
a=7
[21-6 final修飾子(final class)]
final是用來修飾欄位、方法與類別的修飾子。加上final修飾子的欄位,其值不可以被修改。加上final修飾子的方法,該方法不可以被覆寫。而加上final修飾子的類別,則不可以被繼承。
<final field範例>
加上final修飾子的欄位,其值不可以被修改。
class FinalField1{
public static void main(String[] args){
final int x = 10 ;
x = 29 ; //修改
System.out.println("x=" + x) ;
}
}
編譯結果:C:\js>javac FinalField1.java
FinalField1.java:4: error: cannot assign a value to final variable x
x = 29 ; //修改
^
1 error
<final method範例>
加上final修飾子的方法,該方法不可以被覆寫。
class Finalfat1{
int x = 10 ;
final void finalmd1() {
System.out.println("x=" + x) ;
}
}
class Finalson1 extends Finalfat1 {
void finalmd1() { //方法覆寫
int x = 100 ;
System.out.println("x的值為" + x) ;
}
}
class Finalmain1{
public static void main(String[] args){
Finalson1 mmm = new Finalson1() ;
mmm.x = 300;
mmm.finalmd1() ;
}
}
編譯結果:C:\js>javac Finalmain1.java
Finalmain1.java:9: error: finalmd1() in Finalson1 cannot override finalmd1() in
Finalfat1
void finalmd1() { //方法覆寫
^
overridden method is final
1 error
<final class範例>
加上final修飾子的類別,不可以被繼承。
final class Finalfat2{
void finalmd3(){
int y = 20 ;
System.out.println("y=" +y);
}
}
class Finalson2 extends Finalfat2{ } //不能被繼承
class Finalmain2{
public static void main(String[] args){
Finalson2 fc2 = new Finalson2();
fc2.finalmd3();
}
}
編譯結果:C:\js>javac Finalmain2.java
Finalmain2.java:8: error: cannot inherit from final Finalfat2
class Finalson2 extends Finalfat2{ } //不能被繼承
^
1 error
[21-7 super關鍵字]
以super關鍵字可以引用父類別欄位、方法、建構式。
[格式]
父類別欄位:super.父類別欄位名。
父類別方法:super.父類別方法名。
父類別建構式:super()或super(參數)。
另以this關鍵字可以呼叫本身建構式。
[格式]
本身類別建構式:this()或this(參數)。
[21-7-1super關鍵字用於一般方法及方法內欄位時]
當父類別、子類別有相同之欄位、方法名稱,但其值或內容不同時,在子類別裡使用super關鍵字,可以參考(引用)父類別的欄位或方法。
<範例>
class Superfat1 {
int x = 7 ;
int y = 10 ;
int tot ;
void md1(int i, int j) {
x = x * i ;
y = y * j ;
tot = x + y ; } }
class Superson1 extends Superfat1 {
int x = 14 ;
int y = 20 ;
void md2(int i, int j) {
super.md1(i, j) ; //等同x = x * i ; y = y * j ; tot = x + y ;
System.out.println("總數=" + tot) ; } }
class Supermain1 {
public static void main(String[ ] args) {
Superson1 nnn = new Superson1( ) ;
nnn.md2(3,5) ; } }
執行結果:C:\js>java Supermain1
總數=71
[21-7-2 super關鍵字在建構式的運用]
super()代表執行父類別的建構式。建構式呼叫另一建構式時,必須置於第一個敘述。
<範例>
class SuperClass1{
SuperClass1(){
System.out.println("由super class(SuperClass1)建構式顯示此一訊息");
}
void superMethod1(){
System.out.println("superMethod1");
}
}
class SonClass1 extends SuperClass1{
SonClass1(){
super(); //執行父類別SuperClass1的建構式
System.out.println("由son class(SonClass1)建構式顯示此一訊息");
}
void sonMethod1(){
System.out.println("sonMethod1");
}
}
public class SuperMain11{
public static void main(String[] args){
SonClass1 son1 = new SonClass1();
son1. sonMethod1();
}
}
執行結果:C:\js>java SuperMain11
由super class(SuperClass1)建構式顯示此一訊息
由son class(SonClass1)建構式顯示此一訊息
sonMethod1
[21-7-3 super關鍵字在建構式多載的運用]
<範例>
class SuperClass2{
SuperClass2(){
System.out.println("由super class(SuperClass2)建構式顯示此一訊息");
}
void superMethod2(){
System.out.println("superMethod2");
}
}
class SonClass2 extends SuperClass2{
String str;
SonClass2(String str){
this(); //引用本身建構式
this.str = str;
System.out.println("由son class(" + str + ")建構式顯示此一訊息");
}
SonClass2(){
super();
}
void sonMethod2(){
System.out.println("sonMethod2");
}
}
public class SuperMain22{
public static void main(String[] args){
SonClass2 son2 = new SonClass2("SonClass2");
son2. sonMethod2();
}
}
執行結果:C:\js>java SuperMain22
由super class(SuperClass2)建構式顯示此一訊息
由son class(SonClass2)建構式顯示此一訊息
sonMethod2
[21-8 this關鍵字]
this關鍵字是指所屬類別欄位、建構式。
[格式]
所屬類別欄位:this.所屬類別欄位名。
所屬類別建構式:this ()或this (參數)。
[21-8-1所屬類別內欄位和this關鍵字]
所屬類別內之欄位應前置this關鍵字,但可省略。
[範例]用於一般方法內。
class This1a {
String name ;
int age ;
void thismd1a(String x, int y) {
this.name = x ; //前置this
age = y ; //省略this
System.out.println(this.name + " " + age + "歲") ;
}
}
class Thismain1a {
public static void main(String[ ] args) {
This1a sss = new This1a( ) ;
sss.thismd1a("CKY",27) ;
}
}
執行結果:C:\js>java Thismain1a
CKY 27歲
[範例]用於建構式。
因建構式也是方法的一種,欄位的this使用方式和一般方法完全一樣。
class This1b {
String name ;
int age ;
This1b(String x, int y) {
this.name = x ; //前置this
age = y ; //省略this
System.out.println(this.name + " " + age + "歲") ;
}
}
classThismain1b {
public static void main(String[ ] args) {
This1b ttt = new This1b(" CTC",60) ;
}
}
執行結果: C:\js>java Thismain1b
CTC 60歲
[範例]用於建構式多載。
當一個建構式呼叫另一個建構式時(建構式多載),必須置於該建構式第一個式子。故this()和super()不能共存。
class This1c {
String name ;
int age ;
This1c(String x) {this.name = x + "C" ;}
This1c(String x, int y) {this(x); age = y; }
void thismd1c() {
System.out.println(name + " " + age + "歲") ;
}
}
class Thismain1c {
public static void main(String[ ] args) {
This1c uuu = new This1c("CT",60) ;
}
}
執行結果:C:\js>java Thismain1b
CTC 60歲
[21-8-2欄位和區域變數同名]
欄位和區域變數同名時,前置this以資區別(視覺上的區別)。
<無前置this>
class This2 {
String name ;
int age ;
void thismd2(String name, int age) {
name = name ; //無前置this
age = age ; //無前置this
System.out.println(name + " " + age + "歲") ;
}
}
class Thismain2 {
public static void main(String[ ] args) {
this2 ttt = new this2( ) ;
ttt.thismd2("CKS",32) ;
}
}
執行結果:C:\js>java Thismain2
CKS 32歲
<前置this>
class This3 {
String name ;
int age ;
void thismd3(String name, int age) {
this.name = name ; //前置this,左方為欄位,右方為區域變數(方法的參數)
this.age = age ; //前置this
System.out.println(name + " " + age + "歲") ;
}
}
class Thismain3 {
public static void main(String[ ] args) {
This3 zzz = new This3( ) ;
zzz.thismd3("CKS",32) ;
}
}
執行結果:C:\js>java Thismain3
CKS 32歲
有無前置this,其效果相同,只是易於分辨。
留言列表