全部章節 >>>>
本章目錄
2.1 成員變量
在類體中定義的變量爲成員變量,作用範圍是整個類,只要在這個類中都可以訪問到它。
成員變量包括實例屬性了類屬性。
類屬性從類被加載開始存在,直到系統完全銷燬該類,類屬性的作用域與該類的生命週期相同。
實例屬性則從類的實例被創建起開始存在,直到系統銷燬該實例,實例屬性的作用域與其對應的實例的生命週期相同。
2.1.1 成員變量與局部變量的區別
在類中的位置不同:
成員變量:在類中方法外面。
局部變量:在方法或者代碼塊中,或者方法的聲明上(即在參數列表中)。
在內存中的位置不同:
成員變量:在堆中(方法區中的靜態區)。
局部變量:在棧中。
生命週期不同:
成員變量:隨着對象的創建而存在,隨着對象的消失而消失。
局部變量:隨着方法的調用或者代碼塊的執行而存在,隨着方法的調用完畢或者代碼塊的執行完畢而消失。
初始值:
成員變量:有默認初始值。
局部變量:沒有默認初始值,使用之前需要賦值,否則編譯器會報錯。
2.1.2 成員變量的使用
示例:測試英雄對象中成員屬性的賦值和引用
public class Hero {
String name;//英雄名字
int age;//英雄年齡
public static void main(String[] args){
//創建英雄對象hero1
Hero hero1 = new Hero();
hero1.name="德魯伊"; //爲hero1的實例屬性name賦值
hero1.age=45;
//創建英雄對象hero2
Hero hero2 = new Hero();
System.out.println("英雄hero1的名字:"+hero1.name
+"\t"+"年齡:"+hero1.age);
System.out.println("英雄hero2的名字:"+hero2.name
+"\t"+"年齡:"+hero2.age);
}
}
實例屬性內存分配示意圖
2.1.3 實踐練習
2.2 this關鍵字
1、this關鍵字代表自身
2、this關鍵字主要用途
- 用this代表自身類的對象(直接使用this、使用this引用成員變量、使用this調用成員方法)。
- 用this在自身的構造方法內部調用其他的構造方法。
2.2.1 使用this關鍵字引用成員變量和成員方法
示例:測試在方法中使用this關鍵字引用成員變量和成員方法
public class Hero {
public void jump(){
System.out.println("---英雄遇到了障礙需要跳過去---");
}
public void run(){
System.out.println("---執行run方法英雄正在奔跑---");
Hero hero = new Hero();//創建Hero對象
System.out.println("her對象已經被創建內存地址
爲:"+hero.hashCode()+",它將實行jump方法");
hero.jump();//調用run()方法
}
}
public class TestHero {
public static void main(String[] args){
Hero hero = new Hero();//創建Hero對象
System.out.println("hero對象已經被創建內存地址
爲:"+hero.hashCode()+",它將實行run方法");
hero.run();//調用run()方法
}
}
2.2.2 解決實例變量與局部變量同名的問題
示例:實例變量與句變量同名(實例變量前沒有this)
public class Hero {
String name;
public void setName(String name){
name=name; //此處易混淆,可讀性差
}
public static void main(String[] args){
Hero hero=new Hero();
hero.setName("風暴精靈");
System.out.println("hero的名字爲:"+hero.name);
}
}
分析:當方法中的局部變量與實例變量同名時,在方法中如果不使用this前綴調用實例變量,則在方法中默認調用方法中的局部變量(形參也是局部變量)。
示例:實例變量與句變量同名(實例變量前有this)
public class Hero {
String name;
public void setName(String name){
this.name=name;
}
public static void main(String[] args){
Hero hero=new Hero();
hero.setName("風暴精靈");
System.out.println("hero的名字爲:"+hero.name);
}
}
2.2.3 實踐練習
2.3 隱藏和封裝
現實生活中的封裝
隱藏內部實現細節,封裝系統(部件、組件)功能
2.3.1 封裝
封裝是面向對象的三大特性之一。
封裝將對象的狀態信息隱藏在對象內部,不允許外部程序直接訪問對象內部信息,而是通過該類所提供的方法實現對內部信息的操作和訪問。
封裝是面向對像編程語言對客觀世界的模擬,客觀世界中的屬性均被隱藏在對象內部,外界無法直接操作和修改。
一個良好的封裝可以實現以下目的:
隱藏類的實現細節。
讓使用者只能通過事先預定的方法訪問數據,從而可以在該方法中加入控制邏輯,限制對屬性的不合理訪問。
可進行數據檢查,從而有利於保證對象信息的完整性。
便於修改,提高代碼的可維護性。
實現良好封裝的途徑:
隱藏對象的屬性和實現細節,不允許外部直接訪問。
暴露出方法,讓方法控制對這些屬性進行安全的訪問和操作。
封裝實際上有兩個方面的含義:隱藏該隱藏的,暴露該暴露的。
Java封裝的實質:使用訪問控制符private隱藏屬性,以及public暴露方法。
示例:利用封裝隱藏英雄屬性以及暴露屬性賦值和更新的方法
public class Hero {
//使用private修飾屬性,隱藏這些屬性
private String name;
private int age;
//public方法公開對name屬性賦值
public void setName(String name) {
//執行合理校驗,要求用戶名必須在2~6之間
if(name.length()>6||name.length()<2){
System.out.println("您輸入的名字不符合要求");
return;
}else{
this.name = name;
}
}
//public方法公開對name屬性取值
public String getName() {
return name;
}
......
}
2.3.2 Java訪問控制符
Java通過修飾符來控制類、屬性和方法的訪問權限和其他功能,通常放在語句的最前端。
Java支持四種不同的訪問權限。
訪問控制級別圖:
Java訪問控制級別表:
訪問修飾符 |
同一個類中 |
同一個包中 |
子類中 |
所有類中 |
private |
√ |
— |
— |
— |
default |
√ |
√ |
— |
— |
protected |
√ |
√ |
√ |
— |
public |
√ |
√ |
√ |
√ |
示例:private訪問控制符修飾的屬性在同一個類中可以訪問
public class Person{
private String name="李彥宏";
public static void main(String args[]){
Person person = new Person();
//同一類中可以訪問所有屬性
System.out.println("姓名是:"+person.name);
}
}
示例:default訪問控制符修飾的屬性在同一個包中可以訪問
package com.vo;
public class Person{
//默認修飾符爲default
String name="李彥宏";
}
public class Test{
public static void main(String args[]){
Person person = new Person();
//訪問default修飾的屬性
System.out.println(person.name);
}
}
示例:default訪問控制符修飾的屬性在同一個包中可以訪問
package com.vo;
public class Person{
//默認修飾符爲default
String name="李彥宏";
}
public class Test{
public static void main(String args[]){
Person person = new Person();
//訪問default修飾的屬性
System.out.println(person.name);
}
}
示例:public訪問控制符修飾的屬性能夠被不同包中的類訪問
package com.vo;
public class Person{
//public爲公有訪問修飾符
public String name="李彥宏";
}
package com.test;
public class Test{
public static void main(String args[]){
Person person = new Person();
//被public修飾的屬性在任何位置均可訪問
System.out.println(person.name);
}
}
2.3.3 實踐練習
2.4 static關鍵字
- Java類的運行包括類加載和實例化兩個階段。
- 當一個類被加載至 JVM 中,靜態成員會被初始化。
- 靜態成員不屬於某個對象,僅屬於靜態成員所在的類。
被 static 修飾的成員即爲靜態成員。
靜態代碼塊
靜態屬性
靜態方法
2.4.1 靜態成員變量
靜態成員變量屬於其所在類,被類中的所有實例共享。
靜態成員變量可通過類直接訪問,也可通過類的實例訪問。
示例:模擬個人銀行賬戶取款10次
public class Bank {
//靜態成員變量,賬戶餘額
private static int count = 50000 ;
public static void main(String[] args) {
//實例化10個Bank對象
for(int i=0; i<10; i++){
Bank bank=new Bank();
//每次取款1000元,類的實例調用靜態成員屬性
bank.count = bank.count - 1000;
//Bank.count=Bank.count-1000; //通過類名之間訪問靜態成員
System.out.println("當前銀行總錢數="+Bank.count);
}
}。
}
所有的靜態成員變量都可以通過類名直接訪問。
2.4.2 靜態方法
- 被static修飾的方法稱爲靜態方法。
- 靜態方法也可通過類名直接訪問,也可通過對象名訪問。
- 靜態方法中不能訪問非靜態的成員,如實例屬性、實例方法。
- 靜態方法通常作爲工具方法,因爲靜態方法不會因爲實例的不同,而影響方法最終的執行效果。
示例:定義一個計算平方的靜態方法
public class MathUtils {
//計算平方
public static double square(double num){
return num*num;
}
public static void main(String[] args){
double num=9.6;
double result=MathUtils.square(num);
System.out.println(num+"的平方="+result);
}
}
爲什麼靜態方法不能訪問非靜態成員?
Java程序運行時首先由JVM加載類。
類加載時會爲靜態的成員開闢內存空間,而實例成員在類的實例化 階段才被創建,所以當類加載時靜態的成員已經被創建,而此時並不存在實例成員,因此不能在靜態方法中訪問非靜態成員。
但是實例方法可以訪問靜態成員。
2.4.3 靜態代碼塊
- 如果需要在類加載時執行某一操作,則可以使用靜態代碼塊。
- 靜態代碼不存在任何方法體中,它在Java虛擬機加載類時執行。
- 如果類中包含多個靜態代碼塊,則Java虛擬機將按照它們在類中出現的順序依次執行。
- 靜態代碼塊只會被執行一次。
爲什麼需要靜態代碼塊?什麼場合需要用到靜態代碼塊?
靜態方法在類加載後,雖然在內存中已經分配了內存空間,但只有顯式地調用靜態方法時,該方法纔會被執行。如果需要在類加載時執行某一操作,則可以使用靜態代碼塊
示例:靜態代碼塊程序演示
public class StaticBlock {
//第一個靜態代碼塊
static{
System.out.println("---第一個靜態代碼塊---");
}
//第二個靜態代碼塊
static{
System.out.println("---第二個靜態代碼塊---");
}
//第三個靜態代碼塊
static{
System.out.println("---第三個靜態代碼塊---");
}
public static void main(String[] args){
System.out.println("---main方法被執行了---");
}
}
雖然main()方法是程序的入口方法,但該方法是在類加載完成後,由JVM虛擬機調用該方法。
而靜態代碼塊是在類加載時就執行。
加載完靜態代碼塊後,才執行main()方法。
2.4.4 實踐練習
總結:
- 變量可以分爲成員變量和局部變量,成員變量是在類範圍定義的變量,局部變量是在方法中定義的變量。
- 成員變量分爲類屬性和實例屬性兩種,定義屬性時沒有static修飾符修飾的就是實例屬性。類屬性的作用域與該類的生命週期相同,例屬性的作用域與其對應的實例的生命週期相同。
- this關鍵字代表自身。
- 封裝將對象的狀態信息隱藏在對象內部,不允許外部程序直接訪問對象內部信息,而是通過該類所提供的方法實現對內部信息的操作和訪問。
- Java訪問控制符可見性範圍由小到大爲:private->default->protected->public。
- 靜態成員變量屬於其所在類,被類中的所有實例共享,靜態成員變量可通過類直接訪問,也可通過類的實例訪問。靜態方法不能訪問非靜態的成員。