# 面向對象編程
## 面向過程和面向對象編程
例如 C 語言、VB 語言都是面向過程的編程語言。通過一個函數(方法)解決一件事情,「就事論事」。事情處理完成后,是不會留下任何「遺產」的。
一件事情:
例如 「南通青鳥 IT 教育 96 班同學在 3 教室上陸老師的 Java 課」。
用面向對象的思維邏輯去分析,抽象實體:
* 班級
* 學生
* 教室
* 老師
* 課程
* 學校
通過類封裝實體的屬性和動作(方法)。
## 類和對象
**類:** 是一種自定義的數據類型。有時把這種數據類型也叫做「類類型」或者「引用數據類型」。「引用」就是內存地址的意思。
**對象:**通過類創建的變量,或者叫類的實體。
> 類是一群對象的特征母版,對象是類的具體實例。
>
> 類是一群對象的抽象。
### 類的定義
> 類所具備的最基本要素:(靜態)屬性、(動態)方法。
語法:
```java
[修飾符] class 類名 {
// 成員變量
[修飾符] 數據類型 成員變量1;
[修飾符] 數據類型 成員變量2;
...
// 方法
[修飾符] 返回值 方法名1([參數列表]) {
方法體語句;
}
[修飾符] 返回值 方法名2([參數列表]) {
方法體語句;
}
...
// 構造器:創建對象用的方法
[修飾符] 類名([參數列表1]) {
方法語句;
}
[修飾符] 類名([參數列表2]) {
方法語句;
}
}
```
類的三大部件:成員變量、方法、構造器。
實例:
```java
public class Student1 {
// 構造器
Student1(String name, int age, String code) {
this.name = name;
this.age = age;
this.code = code;
}
// 成員變量
String name;
int age;
String code;
// 方法
String intro() {
return "我叫"+this.name+",我的學號是"+this.code+",我今年"+this.age+"歲了。";
}
void listen() {
System.out.println(this.name + "在上課。");
}
}
```
使用類構建對象
```java
public static void main(String[] args) {
// 構建一個對象:調用類的構造器
Student1 hehao = new Student1("何浩", 20, "C25");
// 用對象:給屬性賦值
hehao.birthday = new Date(); // 賦值
System.out.println(hehao.code); // 獲取屬性值
// 用對象:調用對象的方法
System.out.println(hehao.intro());
hehao.listen();
}
```
> 類名的定義要符合 Java 的標識符命名規范,類名首字母大寫,如果多個單詞,使用駝峰命名法則(每個獨立單詞首字母大寫),**在 Java 中,只要看到首字母大寫,你就是一個類。**
>
> 類中三大部件的定義是沒有嚴格的順序的,但是,我們一般遵循,構造器、成員編程、方法這樣的定義順序。
**構造器**
語法:
```
[修飾符] 類名([參數列表]) {}
```
* 構造器是一個特殊的方法,方法名就是類名,沒有返回值(和 void 是有區別的),構造器是類創建對象的唯一途徑。如果一個類沒有顯式的定義一個構造器,那么**編譯器會給這個類默認的定義一個沒有參數的構造器**。
* 如果顯式的定義了一個構造器,那么編譯器就不會給類定義默認的空參數構造器。
**成員變量**
語法:
```
[修飾符] 數據類型 成員變量名 [= 默認值];
```
* 修飾符:可以省略,也可以是 public protected private static final,其中 public protected private 只允許出現一次。
* 數據類型:可以是任意的數據類型(包含基本數據類型、類類型、數組類型)
* 默認值:如果是類類型的,沒有定義默認值,那么成員變量的值為 null,如果是基本數據,沒有定義默認值,那么成員變量的值是有意義的,比如 int 就是 0,boolean 就是 false。
**方法**
語法:
```
[修飾符] 方法的返回值數據類型 方法名(形參列表) {
方法體語句;
}
```
* 修飾符:可以省略,也可以是 public protected private static final abstract,其中 public protected private 只允許出現
* 返回值:可以是數據類型(不要忘了自定義的數據類型),也可以是 void,如果定義了返回值,那么就必須在 return 后面跟隨該類型的值或者對象。
* 方法名:一般首字母小寫,也適用駝峰命名法則,一般是動詞在前,名詞在后,不易過長
* 形參列表:定義方法可以接受的參數,由 0-N 個 「數據類型 參數名」通過 「,」 組合的。一旦方法指定了形參,那么在調用的時候就必須一一對應的傳入實參。
**static 關鍵字**
用于修飾成員變量和方法,用 static 修飾的成員變量后者方法是屬于 **類** 的,而不屬于該類的實例(對象)。通常把 static 修飾的成員變量稱為「類變量、靜態變量」,方法稱為「類方法、靜態方法」
> 靜態的成員是不能訪問非靜態成員的;
>
> 靜態成員之間是可以互相訪問的。
```java
static String teacher = "陸老師";
// 方法
static String fun2() {
System.out.println(this.name); // 錯誤代碼
System.out.println(teacher);
return "";
}
```
**使用一個對象的過程**
* 定義類
* 構建和使用對象
語法:
```
類類型 對象名 = new 構造器方法();
```
實例:
```java
Student1 hehao = new Student1("何浩", 20, "C25");
```
在內存中的執行過程:
1、在棧內存中,會存儲對象名,在沒有執行構造器創建對象并賦值時,此時對象名對應的值為 null;
2、通過 new 關鍵字調用類的構造器在堆內存中分配了一塊對象區域;
3、通過賦值運算符 = ,將堆內存中的對象地址賦給棧內存中的變量名;
4、例如再次給對象的屬性賦值:通過棧內存定位到對象在堆內存中的地址,找到相應的成員變量,進行賦值操作。
> 引用,還可以稱為「地址」、「指針」,特指類類型,因為只有類類型才會在堆內存中分配對象空間,并將地址(指針)在棧內存中用于對象變量名的引用。
**this 關鍵字**
Java 中使用 this 關鍵字,指向調用該方法的對象。根據 this 所在的位置,大致分為兩種:
* 出現在構造器中:引用該構造器正在初始化的對象;
* 普通方法中:調用該方法的對象。
this 用于在類定義中,獲取當前對象的屬性,或者調用當前對象的方法。
> 在類定義中,可以省略 this 關鍵字去調用屬性或者方法,但是在類被編譯的時候,編譯器還是會加上 this 關鍵字。所以強烈建議在類定義時如果要調用該類中的普通成員變量后者方法,還是要把 this 加上去。
>
> 用 static 修飾的方法中是不能使用 this 關鍵字的。
```java
Student1(String name, int age, String code) {
this.name = name;
this.age = age;
this.code = code;
}
String intro() {
return "我叫" + this.name + ",我的學號是" + this.code + ",我今年" + this.age + "歲了。";
}
void listen() {
System.out.println("自我介紹:" + this.intro() + " " + this.name + "在上課。");
return;
}
static String fun2() {
return this.intro(); // 錯誤代碼
}
```
### 方法的詳解
**所屬性:**
要么屬于類(用 static 修飾的方法)、要么屬于對象。
```java
public class Demo6 {
public static void main(String[] xxx) {
// 獲取用戶輸入的信息
int age = Integer.valueOf(xxx[0]);
String sex = xxx[1];
// 構建封裝對象
Student1 stu = new Student1();
stu.age = age;
stu.sex = sex;
// 執行業務邏輯
System.out.println(stu.fun1() ? "合法" : "非法");
}
}
class Student1 {
int age;
String sex;
// 用于判斷年齡和性別是否是合法結婚年齡的方法
boolean fun1() {
if (this.sex.equals("男")) {
if (this.age >= 25) {
return true;
} else {
return false;
}
} else {
if (this.age >= 23) {
return true;
} else {
return false;
}
}
}
}
```
> 程序的設計:
>
> * 用戶的輸入
> * 輸入內容進行封裝
> * **調用業務邏輯方法**
> * 輸出結果
**方法關心的要素**
* 方法屬于誰
* 方法的參數
* 方法的返回值
方法定義的語法
```
[修飾符] 返回值類型 方法名(形參列表) {
方法體
}
```
**方法中參數傳遞的機制**
參數的傳遞都是「值傳遞」,在調用方法的時候,參數會被創造出一個副本,原本的值是不會改變的。
基本數據類型,也稱為「值類型」。
```java
package com;
public class Demo11 {
void fun1(int i, int j) {
i = i + 5;
j = j + 5;
System.out.println("fun1-i:" + i);
System.out.println("fun1-j:" + j);
}
void fun1(P p) {
p.i = p.i + 5;
p.j = p.j + 5;
System.out.println("fun1-p-i:" + p.i);
System.out.println("fun1-p-j:" + p.j);
}
public static void main(String[] args) {
Demo11 demo11 = new Demo11();
int i = 10;
int j = 20;
demo11.fun1(i, j);
System.out.println("main-i:" + i);
System.out.println("main-j:" + j);
System.out.println("====================");
P p = new P();
p.i = 10;
p.j = 20;
demo11.fun1(p);
System.out.println("main-p-i:" + p.i);
System.out.println("main-p-j:" + p.j);
}
}
class P {
int i;
int j;
}
```
輸出:
```java
fun1-i:15
fun1-j:25
main-i:10
main-j:20
====================
fun1-p-i:15
fun1-p-j:25
main-p-i:15
main-p-j:25
```
> 總結一下:如果方法中傳入的是基本數據類型,那么原變量的值是不會發生改變的,如果方法中傳入的是引用數據類型(即類類型),那么傳入方法中,如果對對象的相關屬性進行了修改,那么原對象的相關屬性也會發生改變。
### 變量
根據變量定義所在位置的不同,可以定義:
- 成員變量:在類中定義的變量,用 static 修飾的為類變量,非 static 修飾的為實例變量。
訪問變量的語法:
```java
類.成員變量
實例(對象).成員變量
```
實例:
~~~
public class Demo1 {
int x; // 實例變量
static double PI = 3.14;
public static void main(String[] args) {
Demo1 d1 = new Demo1(); // d1 成為實例或者對象
d1.x = 10;
System.out.println(d1.PI); // 不建議這樣使用
System.out.println(Demo1.PI); // PI為類變量
}
}
~~~
> 關于默認值的問題:對于基本數據類型的實例變量,在對象被初始化的時候都是會有默認值的,數值類型為 0 ,布爾類型為 false,字符類型 '\u0000';引用數據類型默認值為 null。
- 局部變量
局部變量按照定義的位置分為:
- 在方法內部定義的變量;
- 在代碼塊中定義的變量,比如有循環體內部、判斷體內部;
- 形式參數:在方法定義的參數列表中定義的變量;
> 關于局部變量生命周期的理解:從定義變量的位置開始,到定義位置所在花括號的結束位置結束。
> 要注意一般在 for 循環中我們的初始化條件里面定義的變量,其生命周期在循環體內。
~~~
public static void main(String[] args) {
System.out.println(i); // 有錯誤的
int i = 0;
if (i < 10) {
int j = i / 2;
System.out.println(j);
}
System.out.println(j); // 有錯誤的
for (int k = 0; k <= 10; k++) {
System.out.println(k);
}
System.out.println(k); // 有錯誤的
}
~~~
**成員變量和局部變量的區別**
- 成員變量中是可以加入修飾符的,如 private、public、protected、static、final,在局部變量中是不可以加入修飾符的。
- 成員變量中的類變量是類被加載的時候初始化的,程序關閉時銷毀。
- 成員變量中的實例變量是對象被創建出來的時候初始化的,在對象沒有引用的時候被銷毀。
**變量的使用規則**
- 如果需要一個變量來描述一個類或對象的固有信息,比如人的年齡、性別、姓名這類,會把這些變量定義為成員變量中的實例變量;
- 如果一個變量只在方法體內或者代碼塊中有效,就沒有必要定義為成員變量。
> 變量的命名:一般局部變量或者實例變量,使用駝峰的命名方式,但是首字母小寫,如果是類變量,特別是常量,使用全部大寫,兩個單詞之間用 `_` 分隔
- 前言
- 計算機概論
- 數據庫
- 數據庫介紹
- MySQL的安裝
- SQL
- 表基本操作
- 修改數據語句
- 數據檢索操作
- 多表數據操作
- 表結構設計
- 綜合應用
- JAVA
- JAVA 介紹
- JAVA 運行原理
- JDK 配置
- 類和對象
- 數據類型
- 變量
- 直接量
- 運算符
- 流程控制
- 數組結構
- 面向對象
- 隱藏和封裝
- 深入構造器
- 類的繼承
- 多態
- 包裝類
- final 修飾符
- 抽象類
- 接口
- 集合框架
- 常用類學習
- 異常處理
- 設計模式-單例模式
- JDBC
- JSP&Servlet
- Web應用
- Tomcat
- JSP
- Scriptlet
- Page 指令
- 包含指令
- 跳轉指令
- 用戶注冊實例
- JSP練習
- 內置對象
- Servlet
- 過濾器
- Web分層思想
- EL表達式
- JSTL
- 分頁實現
- AJAX&JSON
- 開發步驟
- 路徑問題
- Log4j
- 電子書城
- 案例分析
- 核心代碼
- Java 高級
- 文件操作
- 泛型
- 類加載機制和反射
- 注解 Annotation
- Mybatis框架
- 框架介紹
- Mybatis簡單實現
- 表基本操作
- 優化配置文件
- 表字段名與實體類屬性名不同的解決方案
- 一對一關聯
- 一對多關聯
- 教學管理
- 學員名錄
- 周測統計
- 2017-10-27
- 2017-11-03
- 2017-11-10
- 2017-11-17
- 課堂作業
- 班會紀要
- 2017-10-24
- 缺勤記錄
- 班級備忘錄
- 違紀統計
- 編程素養
- Day001
- Day002
- Day003
- Day004
- Day005
- Day006
- Day007
- Day008
- Day009
- Day010
- Day011
- Day012
- Day013
- Day014
- Day015
- Day016
- Day017
- Day018
- Day019