代碼塊(了解)
(1)用{}括起來的代碼。
(2)分類:
A:局部代碼塊
用于限定變量的生命周期,及早釋放,提高記憶體使用率。
B:構造代碼塊
把多個構造方法中相同的代碼可以放到這裡,每個構造方法執行前,首先執行構造代碼塊。
C:靜态代碼塊
static{}對類的資料進行初始化,僅僅隻執行一次。
(3)靜态代碼塊,構造代碼塊,構造方法的順序問題?
靜态代碼塊 > 構造代碼塊 > 構造方法
class Student {
static {
System.out.println("Student 靜态代碼塊");
}
{
System.out.println("Student 構造代碼塊");
}
public Student() {
System.out.println("Student 構造方法");
}
}
class StudentDemo {
static {
System.out.println("studentDemo靜态代碼塊");
}
public static void main(String[] args) {
System.out.println("我是main方法");
Student s1 = new Student();
Student s2 = new Student();
}
}
運作結果如下:
/*
寫程式的執行結果。
<span style="font-family: Arial, Helvetica, sans-serif;">studentDemo靜态代碼塊</span>
我是main方法
Student 靜态代碼塊
Student 構造代碼塊
Student 構造方法
Student 構造代碼塊
Student 構造方法
*/
繼承(掌握)
(1)把多個類中相同的成員給提取出來定義到一個獨立的類中。然後讓這多個類和該獨立的類産生一個關系,
這多個類就具備了這些内容。這個關系叫繼承。
(2)Java中如何表示繼承呢?格式是什麼呢?
A:用關鍵字extends表示
B:格式:
class 子類名 extends 父類名 {}
(3)繼承的好處:
A:提高了代碼的複用性
B:提高了代碼的維護性
C:讓類與類産生了一個關系,是多态的前提
(4)繼承的弊端:
A:讓類的耦合性增強。這樣某個類的改變,就會影響其他和該類相關的類。
原則:低耦合,高内聚。
耦合:類與類的關系
内聚:自己完成某件事情的能力
B:打破了封裝性
(5)Java中繼承的特點
A:Java中類隻支援單繼承
B:Java中可以多層(重)繼承(繼承體系)
(6)繼承的注意事項:
A:子類不能繼承父類的私有成員
B:子類不能繼承父類的構造方法,但是可以通過super去通路
C:不要為了部分功能而去繼承
(7)什麼時候使用繼承呢?
A:繼承展現的是:is a的關系。
B:采用假設法
(8)Java繼承中的成員關系
A:成員變量
a:子類的成員變量名稱和父類中的成員變量名稱不一樣,直接通路
b:子類的成員變量名稱和父類中的成員變量名稱一樣,這個怎麼通路呢?
子類的方法通路變量的查找順序:就近原則
在子類方法的局部範圍找,有就使用。
在子類的成員範圍找,有就使用。
在父類的成員範圍找,有就使用。
找不到,就報錯。
B:構造方法
a:子類的構造方法預設會去通路 父類的無參構造方法
1:子類中所有的構造方法預設都會通路父類中空參數的構造方法
2:為什麼呢?
因為子類會繼承父類中的資料,可能還會使用父類的資料。
是以,子類初始化之前,一定要先完成父類資料的初始化。父類的初始化是調用方法區中的構造方法進行初始化,不會建立父類對象,對象是要new關鍵字來建立的(
new關鍵字有兩個作用。一是配置設定記憶體,
建立對象。二是調用構造方法,完成對象的初始化工作。完成這兩步之後,才算建立了一個完整的Java對象。
是以new子類的時候,調用父類的構造方法不是建立了一個父類對象,而是隻對它的資料進行初始化,那麼父類這些資料存儲在哪裡呢? 通俗說 子類對象記憶體區域中會劃一部分區域給父類的資料的存儲,即子類對象記憶體中封裝了父類的初始化資料,建立子類對象時, 父類的資料就是子類的對象的一部分,不存在獨立的父類的對象,所有的東西在一起才是一個完整的子類的對象 ) 注意:子類每一個構造方法的第一條語句預設都是:super();
class Son extends Father {
public Son() {
//super();
System.out.println("Son的無參構造方法");
}
public Son(String name) {
//super();
System.out.println("Son的帶參構造方法");
}
}
class ExtendsDemo6 {
public static void main(String[] args) {
//建立對象
Son s = new Son();
System.out.println("------------");
Son s2 = new Son("林青霞");
}
}
運作結果:
Father的無參構造方法
Son的無參構造方法
------------
Father的無參構造方法
Son的帶參構造方法
b:父類中如果沒有無參構造方法,怎麼辦?
子類通過super去明确調用帶參構造(子類用super();調用父類構造方法隻能在構造方法中的第一行調用)
子類通過this調用本身的其他構造,但是一定會有一個去通路了父類的構造
習慣:最好每次都讓父類提供無參構造
class Father {
/*public Father() {
System.out.println("Father的無參構造方法");
}
*/
public Father(String name) {
System.out.println("Father的帶參構造方法");
}
}
class Son extends Father {
public Son() {
super("随便給");
System.out.println("Son的無參構造方法");
//super("随便給");
}
public Son(String name) {
//super("随便給");
this();
System.out.println("Son的帶參構造方法");
}
}
class ExtendsDemo7 {
public static void main(String[] args) {
Son s = new Son();
System.out.println("----------------");
Son ss = new Son("林青霞");
}
}
運作結果:
Father的帶參構造方法
Son的無參構造方法
----------------
Father的帶參構造方法
Son的無參構造方法
Son的帶參構造方法
C:成員方法
a:子類的成員方法和父類中的成員方法名稱不一樣,直接通路
b:子類的成員方法和父類中的成員方法名稱一樣,這個怎麼通路呢?
通過子類對象通路一個方法的查找順序:就近原則
在子類中找,有就使用
在父類中找,有就使用
找不到,就報錯
(9)兩個面試題:
A:Override和Overload的差別?Overload是否可以改變傳回值類型?可以
B:this和super的差別和各自的作用?
this代表本類對應的引用。
super代表父類存儲空間的辨別(可以了解為父類引用,可以操作父類的成員)
怎麼用呢?
A:調用成員變量
this.成員變量 調用本類的成員變量
super.成員變量 調用父類的成員變量
B:調用構造方法
this(..參數.) 調用本類的構造方法
super(..參數.) 調用父類的構造方法
C:調用成員方法
this.成員方法 調用本類的成員方法
super.成員方法 調用父類的成員方法
(10)資料初始化的面試題
A:一個類的初始化過程
/*
看程式寫結果:
A:成員變量 就近原則
B:this和super的問題
this通路本類的成員
super通路父類的成員
C:子類構造方法執行前預設先執行父類的無參構造方法
D:一個類的初始化過程
成員變量進行初始化
預設初始化
顯示初始化
構造方法初始化
結果:
fu
zi
30
20
10
*/
class Fu{
public int num = 10;
public Fu(){
System.out.println("fu");
}
}
class Zi extends Fu{
public int num = 20;
public Zi(){
System.out.println("zi");
}
public void show(){
int num = 30;
System.out.println(num); //30
System.out.println(this.num); //20
System.out.println(super.num); //10
}
}
class ExtendsTest {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
B:子父類的構造執行過程
/*
看程式寫結果:
A:一個類的靜态代碼塊,構造代碼塊,構造方法的執行流程
靜态代碼塊 > 構造代碼塊 > 構造方法
B:靜态的内容是随着類的加載而加載
靜态代碼塊的内容會優先執行
C:子類初始化之前先會進行父類的初始化
結果是:
靜态代碼塊Fu
靜态代碼塊Zi
構造代碼塊Fu
構造方法Fu
構造代碼塊Zi
構造方法Zi
*/
class Fu {
static {
System.out.println("靜态代碼塊Fu");
}
{
System.out.println("構造代碼塊Fu");
}
public Fu() {
System.out.println("構造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("靜态代碼塊Zi");
}
{
System.out.println("構造代碼塊Zi");
}
public Zi() {
System.out.println("構造方法Zi");
}
}
class ExtendsTest2 {
public static void main(String[] args) {
Zi z = new Zi();
}
}
C:分層初始化
/*
看程式寫結果:
A:成員變量的問題
int x = 10; //成員變量是基本類型
Student s = new Student(); //成員變量是引用類型
B:一個類的初始化過程
成員變量的初始化
預設初始化(給預設的值)
顯示初始化(給我們給變量賦的值)
構造方法初始化
C:子父類的初始化(分層初始化)
先進行父類初始化,然後進行子類初始化。
結果:
YXYZ
問題:
雖然子類中構造方法預設有一個super()
初始化的時候,不是按照那個順序進行的。
而是按照分層初始化進行的。
它僅僅表示要先初始化父類資料,再初始化子類資料。
*/
class X {
Y b = new Y();
X() {
System.out.print("X");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y = new Y();
Z() {
//super
System.out.print("Z");
}
public static void main(String[] args) {
new Z();
}
}