類和物件
1. 類與物件的初步認知
C語言是面向程序的,關注的是程序,分析出求解問題的步驟,通過函式呼叫逐步解決問題,
JAVA是基于面向物件的,關注的是物件,將一件事情拆分成不同的物件,靠物件之間的互動完成,
面向程序注重的是程序,在整個程序中所涉及的行為,就是功能,
面向物件注重的是物件,也就是參與程序所涉及到的主體,是通過邏輯將一個個功能實作連接起來,
簡而言之
面向物件就是用代碼(類)來描述客觀世界的事物的一種方式,一個類主要包含一個事物的屬性和行為,
2.類和類的實體化
類就是一類物件的統稱,物件就是這一類具體化的一個實體,
總的來說:類相當于一個模板,而物件是由模板產生的樣本,一個類可以產生無數的物件,
宣告一個類就是創建一個新的資料型別,而類在 Java 中屬于參考型別,Java 使用關鍵字 class 來宣告類,我們來看以下簡單的宣告一個類,
基本語法:
//創建類
class 類名{
field;//成員屬性/變數
method;//成員方法
}
// 實體化一個物件
類名 物件名 = new 類名();
class為定義類的關鍵字,{}中為類的主體,
類中的元素稱為:成員屬性,類中的函式稱為:成員方法,
類的實體化:
用型別別創建物件的程序,稱為類的實體化,
- 類只是一個模型一樣的東西,限定了類有哪些成員,
- 一個類可以實體化出多個物件,實體化出的物件占用實際的物理空間,存盤類成員變數,
- 類實體化出物件就像現實中使用建筑設計圖建造出房子,類就像是設計圖,只設計出需要什么東西,但是并沒有物體的建筑存在,同樣類也只是一個設計,實體化出的物件才能實際存盤資料,占用物理空間,
代碼示例:
class Student {
//成員屬性 實體變數
public int age;
public String name;
public String sex;
//成員方法
public void eat() {
System.out.println("吃飯!");
}
public void sleep() {
System.out.println("睡覺!");
}
public void study(){
System.out.println("上學!");
}
}
public class Demo{
public static void main(String[] args) {
Student student = new Student();//通過new實體化物件
student.eat();//成員方法呼叫需要通過物件的參考呼叫 使用"."運算子
student.sleep();
student.study();
//產生物件 實體化物件 開辟空間
Student student2 = new Student();
Student student3 = new Student();
}
}
運行結果:
吃飯!
睡覺!
上學!
注意:
- new關鍵字用于創建一個物件的實體,
- 使用 . 來訪問物件中的屬性和方法,
- 同一個類可以創建多個實體,
3.類的成員
類的成員可以包含以下:欄位、方法、代碼塊、內部類和介面等,
此處我們重點介紹前三個,
3.1欄位/屬性/成員變數
在類中, 在方法外部定義的變數,這樣的變數我們稱為 “欄位” 或 “屬性” 或 “成員變數”(三種稱呼都可以, 一般不會嚴格區分),
用于描述一個類中包含哪些資料:
class Person {
public String name; // 欄位
public int age;
}
class Test {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
System.out.println(person.age)
}
}
//執行結果
null
0
//空參考
class Test {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name.length()); //獲取字串長度
}
}
//運行結果:拋出空指標例外
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:9)
注意:
- 使用 . 訪問物件的欄位,訪問既包括讀,也包括寫,
- 對于一個物件的欄位如果沒有顯式設定初始值, 那么會被設定一個默認的初值,
- null在java中為"空參考",表示不參考任何物件,類似于C語言中的空指標,如果對null 進行**.** 操作就會引發例外,
默認值規則:
- 對于各種數字型別,默認值為0.
- 對于boolean型別,默認值為false,
- 對于參考型別(String,Array,以及自定義類),默認值都為null,
欄位就地初始化
很多時候我們不希望欄位使用默認值, 而是需要我們顯式設定初值. 可以這樣寫:
class Person {
public String name = "張三";
public int age = 18;
}
class Test {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
System.out.println(person.age);
}
}
// 執行結果
張三
18
3.2方法(method)
就是我曾經總結過的方法,用于描述一個物件的行為,
詳情參考 java中方法的使用 ,這里不做詳細介紹,要注意的一點是如果在類中定義普通成員方法,不用加static關鍵字,
這里的方法是和這個類相關聯的,如果創建了其他實體,那么方法的行為就會發生變化,
要注意的是方法中還有一種特殊的方法稱為構造方法 ,在實體化物件時會自動呼叫,有些時候可能需要進行一些更復雜的初始化邏輯,那么就可以使用構造方法用于物件的初始化,
3.2構造方法(重要)
3.2.1 基本語法
構造方法是一種特殊方法, 使用關鍵字new實體化新物件時會被自動呼叫, 用于完成初始化操作,
new 執行程序:
- 為物件分配記憶體空間,
- 呼叫物件的構造方法,(完成物件的創建)
語法規則:
1.方法名稱必須與類名稱相同
2.構造方法沒有回傳值型別宣告
3.每一個類中一定至少存在一個構造方法(沒有明確定義,則系統自動生成一個無參構造)
calss Person {
public Person() {
//默認建構式
}
}
代碼示例:
class Person{
public int age;
public String name;
Person(){
System.out.println("無參建構式");
}
Person(int age,String name){
System.out.println("帶有2個引數的建構式");
this.age = age;
this.name = name;
}
Person(int age){
System.out.println("單參建構式");
this.age = age;
}
public void show(){
System.out.println("name: "+this.name+" age: "+this.age);
}
}
public class test {
public static void main(String[] args) {
Person p1 = new Person();
p1.show();
Person p2 = new Person(18,"張三");
p2.show();
Person p3 = new Person(20);
p3.show();
}
}
//運行結果:
如果在定義了帶參建構式的情況下, 而又沒有自己定義無參建構式,創建p1會拋出例外
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The constructor Person() is undefined
at practice.test.main(test.java:26)
在都定義的情況下,創建p1、p2、p3結果是:
無參建構式
name: null age: 0
帶有兩個引數的建構式
name: 張三 age: 18
單參建構式
name: null age: 20
注意事項:
- 如果類中沒有提供任何的建構式,那么編譯器會默認生成一個不帶有引數的建構式,
- 若類中定義了構造方法,則默認的無參構造將不再生成,
- 構造方法支持多載,規則和普通方法的多載一致,
3.2.2 this關鍵字
細心的同學已經發現,帶有引數的建構式中出現了this關鍵字,那么,這個this代表的是當前物件的參考(注意不是當前物件),在類中,可以借助this來訪問物件的欄位和方法,
代碼示例:
class Person{
public int age;
public String name;
//默認建構式 構造物件
Person(){
//this呼叫建構式
this(12);//必須放在第一行,不然編譯不通過
System.out.println("無參建構式");
}
//這三個建構式之間的關系為多載,
Person(int age,String name){
System.out.println("帶有兩個引數的建構式");
this.age = age;
this.name = name;
}
Person(int age){
System.out.println("單參建構式");
this.age = age;
}
public void show(){
System.out.println("name: "+this.name+" age: "+this.age);
}
}
public class test {
public static void main(String[] args) {
Person p4 = new Person(); //呼叫不帶引數的建構式
p4.show();
}
}
//運行結果:
單參建構式
無參建構式
name: null age: 12
在類中,this是隱藏的關鍵字,但是提倡寫代碼的時候帶上,我們發現,建構式是用來構造物件的,物件還沒有構造好,我們就使用了this,在這里this不是代表的當前物件,而是當前物件的參考,
4.static關鍵字
4.1修飾屬性
static修飾的成員變數是不屬于物件的,和具體的實體無關,換句話說,同一個類的不同實體共用一個靜態屬性,
代碼示例:
class Person{
public int a;
public static int count;
}
public class test {
public static void main(String[] args) {
Person p1 = new Person();
p1.a++;
Person.n++;
System.out.println(p1.a);
System.out.println(Person.n);
System.out.println("================");
Person p2 = new Person();
p2.a++;
Person.n++;
System.out.println(p2.a);
System.out.println(Person.n);
}
}
//運行結果:
1
1
============
1
2
代碼記憶體決議:
n被static所修飾,所有類共享,且不屬于物件,訪問方式為:類名 . 屬性,

4.2修飾方法
如果在任何方法上應用 static 關鍵字,此方法稱為靜態方法,
靜態方法屬于類,而不屬于類的物件,可以直接呼叫靜態方法,而無需創建類的實體,靜態方法可以訪問靜態資料成員,并可以更改靜態資料成員的值,
代碼示例:
class Person{
public int a;
public static int n;
public static void show() {
n = 1;
//a = 0; error 靜態方法中不能訪問非靜態成員
}
}
public class test {
public static void main(String[] args) {
Person.show(); //無需創建實體物件,直接用類名進行呼叫
System.out.println(Person.n);
}
}
//運行結果:
1
注意事項:
- 靜態方法不能呼叫非靜態方法,反之可以,
- 靜態方法內,不能訪問非靜態成員變數,
- 普通的成員方法不能定義靜態成員變數,但是可以訪問,
- main方法是靜態的,因為如果是普通方法,要依賴于物件的呼叫,而想要呼叫main方法要執行test.main(); ,要執行這一句,必然要先進入main方法中,但是沒有人呼叫,所以說沒辦法執行,所以main方法是靜態方法,

4.3小結
- 靜態成員變數雖然可以通過已實體化的物件來呼叫,但會有警告,正確的呼叫方式是直接使用類名來呼叫,
- 所有被static修飾的方法或者屬性,全部不依賴于物件,
- java 中使用區域變數一定要先初始化,
5.封裝(重要)
在我們寫代碼的時候經常會涉及兩種角色: 類的實作者和類的呼叫者,封裝的本質就是讓類的呼叫者不必太多的了解類的實作者是如何實作類的, 只要知道如何使用類就行了,這樣就降低了類使用者的學習和使用成本, 從而降低了復雜程度,提高開發效率,
5.1 private實作封裝
private/ public 這兩個關鍵字表示 “訪問權限控制” ,
public 修飾的成員變數或者成員方法, 可以直接被類的呼叫者使用,
private 修飾的成員變數或者成員方法, 不能被類的呼叫者使用,
換句話說, 類的使用者根本不需要知道, 也不需要關注一個類都有哪些 private 的成員. 從而讓類呼叫者以更低的成本來使用類,
直接使用public:
public String name = "張三";
public int age = 18;
這樣的代碼導致類的使用者(main方法的代碼)必須要了解該類內部的實作, 才能夠使用這個類,學習成本較高,一旦類的實作者修改了代碼(例如把 name 改成 myName), 那么類的使用者就需要大規模的修改自己的代碼, 維
護成本較高,
范例:
private String name = "張三";
private int age = 18;
使用 private 封裝屬性, 并提供 public 方法供類的呼叫者使用,通常情況下,我們會把欄位設定為private屬性,但是方法是否需要設為public,就需要視情況而定,一般我們希望一個類只提供必要的public方法,而不應該把所有方法都設定為public,
5.2 getter 和setter方法
當我們使用 private 來修飾欄位的時候, 就無法直接使用這個欄位了,
此時如果需要獲取或者修改這個 private 屬性,就需要使用getter 和setter方法,
class Person{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public class test {
public static void main(String[] args) {
Person p = new Person();
p.setAge(18);
p.setName("lisi");
System.out.println(p.getAge());
System.out.println(p.getName());
}
}
//運行結果:
18
lisi
注意事項:
- getName 即為 getter 方法, 表示獲取這個成員的值,
- setName 即為 setter 方法, 表示設定這個成員的值,
- 當set方法的形參名字和類中的成員屬性的名字一樣的時候,如果不使用this, 相當于自賦值, this 表示當前實體的參考,
- 不是所有的欄位都一定要提供 setter / getter 方法, 而是要根據實際情況決定提供哪種方法,
- 我們自己可以寫setter / getter 方法,也可以根據自己的編譯器選項快速生成,
6.代碼塊
欄位的初始化方式有:
- 就地初始化
- 使用構造方法初始化
- 使用代碼塊初始化
前兩種方式前面已經學習過了, 接下來介紹第三種方式,使用代碼塊初始化,
6.1什么是代碼塊
使用 {} 定義的一段代碼.
根據代碼塊定義的位置以及關鍵字,又可分為以下四種:
普通代碼塊
構造塊
靜態塊
同步代碼塊(這里不做解釋,后面學到再談)
6.2普通代碼塊
普通代碼塊:定義在方法中的代碼塊,
public class test{
public static void main(String[] args) {
{ //直接使用{}定義,普通方法塊
int x = 10 ;
System.out.println("x1 = " +x);
}
int x = 100 ;
System.out.println("x2 = " +x);
}
}
// 執行結果
x1 = 10
x2 = 100
這種用法比較少見,
6.3構造代碼塊
構造塊:定義在類中的代碼塊(不加修飾符),也叫:實體代碼塊,構造代碼塊一般用于初始化實體成員變數,
class Person{
private String name;//實體成員變數
private int age;
private String sex;
public Person() {
System.out.println("無參建構式!");
}
//實體代碼塊
{
this.name = "zhangsan";
this.age = 12;
this.sex = "man";
System.out.println("實體代碼塊");
}
public void show(){
System.out.println("name: "+name+" age: "+age+" sex: "+sex);
}
public class test {
public static void main(String[] args) {
Person p1 = new Person();
p1.show();
}
}
// 運行結果
實體代碼塊!
無參建構式!
name: zhangsan age: 12 sex: man
注意: 實體代碼塊優先于建構式執行,
6.4靜態代碼塊
使用static定義的代碼塊,一般用于初始化靜態成員屬性,
class Person{
private String name;//實體成員變數
private int age;
private String sex;
private static int n = 0;//靜態成員變數 由類共享資料 方法區
public Person() {
System.out.println("無參建構式!");
}
//靜態代碼塊
static {
n = 10;//只能訪問靜態資料成員
System.out.println("靜態代碼塊!");
}
public class test {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
}
}
// 運行結果
靜態代碼塊
無參建構式
無參建構式
注意事項:
- 靜態代碼塊不管生成多少個物件,其只會執行一次,且是最先執行的,
- 靜態代碼塊執行完畢后, 實體代碼塊(構造塊)執行,再然后是建構式執行,
7.序列化和匿名物件
7.1 toString方法
我們剛剛注意到,我們在把物件的屬性進行列印的時候,都自己實作了show函式,其實,我們大可不必,接下來我們看一些示例代碼:
public class test {
public static void main(String[] args) {
Person p1 = new Person();
System.out.println(p1);
}
}
運行結果:
Person@7852e922 //這里列印的是一個地址的哈希值 ,原因呼叫的是object的toString方法
那么此時就需要重寫toString這個方法:
class Person {
private String name;
private int age;
public Person(String name,int age) {
this.age = age;
this.name = name;
}
//重寫Object的toString方法
@Override //表示該方法已經被重寫
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class test {
public static void main(String[] args) {
Person p1 = new Person("zhangsan",18);
System.out.println(p1);
}
}
運行結果:
Person{name='zhangsan', age=18}
注意事項:
- toString 方法會在 println 的時候被自動呼叫,
- 將物件轉成字串這樣的操作我們稱為序列化,
- toString是Object 類提供的方法, 我們自己創建的 Person 類默認繼承自 Object類, 可以重寫 toString 方法實作我們自己版本的轉換字串方法,
- @Override 在 Java 中稱為 “注解”, 此處的 @Override 表示下面實作的 toString 方法是重寫了父類的方法,
- 我們自己可以重寫toString 方法,也可以根據自己的編譯器選項快速生成,
7.2匿名物件
匿名只是表示沒有名字的物件,
- 沒有參考的物件稱為匿名物件.
- 匿名物件只能在創建物件時使用.
- 如果一個物件只是用一次, 后面不需要用了, 可以考慮使用匿名物件.
代碼示例:
class Person {
private String name;
private int age;
public Person(String name,int age) {
this.age = age;
this.name = name;
}
public void show() {
System.out.println("name:"+name+" " + "age:"+age);
}
}
public class Main {
public static void main(String[] args) {
new Person("lisi",19).show();//通過匿名物件呼叫方法
}
}
//運行結果:
name:lisi age:19
優點: 只使用一次
缺點:每次使用都要 new 類名(); 來創建一個物件,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/184857.html
標籤:其他
