1.面向對象思想
1.1
- 現實世界是由對象和對象之間相互作用共同組成的
- 每個對象有自己的特有屬性,也有自己專有的方法。外部對象想要調用這些方法,可以向它請求並傳入參數,等方法執行結束後,返回結果。
- 對象=屬性+方法
- 對象的規範=屬性定義+方法定義
對象調用過程:
1.輸入參數;
2.等待目標方法執行結束;
3.返回結果
1.2
Java中,引入對象和類的概念
- 對象是一個變量(具體的東西)
- 類就是
類型(是規範、是定義)
,從萬千對象中抽取共性
- 類規定了對象應該有的屬性內容和方法
- 對象是類的距體表現,是活生生的
- 例如:土豆絲菜譜是類,一盤土豆絲是對象
1.3
- 從程序發展的角度來理解,OO(Oriented Object:面向對象)是對OP(Oriented Procedure:面向過程)的一種改進
- OP的典型代表是C和Pascal。更強調方法動作,所有的變量是被動參與進來,沒有自主決定權
- OO的方法輸語每個對象的。能否實現是由每個對象說了算的,有主人翁精神
1.4
- OP的例子
public class OPExample {
public static void main(String[] args) {
int a, b, c;
a = 1;
b = 2;
c = add(a, b);
System.out.println("c is " + c);
}
// 函數定義
public static int add(int m, int n) {
return m + n;
}
}
方法是主體,所有的參數是類似於賓語.
- OO的例子
public class OOExample {
private int a;
public void setA(int a) {
this.a = a;
}
public int add(int b) {
return this.a + b;
}
public static void main(String[] args) {
int b = 5;
OOExample obj = new OOExample();
obj.setA(10);
System.out.println(obj.add(b));
}
}
方法從屬於一個對象,而這個對象可以執行自身的某個方法.
obj.add(b):主語obj,謂語add,賓語b
- 計算機的發展和社會發展也是相似之處
- 更強調方法的執行主體
- 增加類型的重用部分(內容和行爲)
1.5
- 變量定義的變遷:更加功能強大
- 基本類型(一種變量)=>>結構體(多種變量捆綁)=>>類(多種變量+方法)
- 類可以繼承;子類可以繼承父類所有內容(不能直接訪問private成員)
- 基本類型無法做到
- 結構體只能做到全包含,不能控制包含粒度
short和int都是整數類型,但是沒有繼承關係,只是表示的整數範圍不同而已。
1.6
- 基本變量例子:
int a; float b;
- 結構體變量例子
// c語言結構體不能包含函數
struct Simple{
int a;
double b;
};//成員默認均爲public
struct Complex{
char c;
struct Simple foo;
//Complex必須包含Simple所有內容
};
Complex包含:int a,float b,char c
- 類/對象例子:
public class Father {
private int money=100;//私有
long mobile=1399999999L;
public void hello(){
System.out.println("hello");
}
}
//--------------------------------------------
public class Son extends Father {
public void hi(){
//子類可以擴展自己的成員方法
System.out.println("hi !!!!!");
}
public static void main(String[] args){
Son s=new Son();
System.out.println(s.mobile);//Son沒有定義mobile,而是通過父類繼承的
// System.out.println(s.money);//error 父類的money是私有的,子類無法直接訪問
s.hello();// Son沒有定義f1,而是通過父類繼承的
s.hi();//Son可以自定義自己的成員方法
}
}
子類必須通過父類的方法才能訪問父類的私有變量。
1.7
- OO最早的始於Simula 67,成形於20實際70年代Smalltalk
- 當前最主要的代表是C++和Java
- 面嚮對象語言主要特點:
- 識認性:辨識/認定爲一種對象
- 類別性:好幾種對象可以歸爲一類
- 多態性:是指在這個類別裏面,這些對象有一定的共同性,也有一定的不同性
- 繼承性:每個子類都會繼承父類的所有東西,然後可以使用它們
1.8總結
- OO總結
- 現實世界是由對象和對象之間相互作用共同組成的
- 對象不僅包含成員變量,還有成員方法
- 對象的內容可以繼承
2.Java類和對象
2.1
- 最簡單的類class A{}//沒有任何屬性和行爲
- 對象 A obj = new A();
- 類是定義,是規範,是“死‘的東西
- 對象是實例,是類的一個實現,是一個具體的東西
- 例如:
- 類等價於一個土豆絲菜譜
- 對象是根據類製作出的對象,等價於一盤土豆絲
2.2
- A obj1 = new A(); A obj2 = new A();
- 以上有 2個對象,它們的類型都是 A,但是這是兩個不同的對象,在內存中有不同的放地址。因此,沒有兩個對象是完全一樣的。
2.3
- A obj = new A();
- obj 可以看作是內存中一個對象 (包括若干個數據)的句柄
- 在C/C++中, obj稱爲指針,在 Java 中稱爲 Reference(參考)
- 對象賦值是Reference 賦值,而基本類型是直接值拷貝
- 參看例子ReferenceTest.java 和ArgumentPassingTest.java ,來查看基本類型賦值和普通對象賦值的不同
// MyNumber
class MyNumber
{
int num = 5;
}
// ReferenceTest
public class ReferenceTest {
public static void main(String[] args) {
int num1 = 5;
int num2 = num1;
System.out.println("num1: " + num1 + ", num2: " + num2);
num2 = 10;
System.out.println("num1: " + num1 + ", num2: " + num2);
MyNumber obj1 = new MyNumber();
MyNumber obj2 = new MyNumber();
System.out.println(obj1.num);
System.out.println(obj2.num);
System.out.println("======接下來輸出新值ֵ=====");
obj2 = obj1;
obj2.num = 10;
System.out.println(obj1.num);
System.out.println(obj2.num);
}
}
// ArgumentPassingTest
public class ArgumentPassingTest {
public static void main(String[] args) {
int a = 1, b = 2;
swap(a,b);
System.out.println("a is " + a + ", b is " + b); //a=1, b=2
MyNumber obj1 = new MyNumber();
MyNumber obj2 = new MyNumber();
obj2.num = 10;
swap(obj1, obj2);
System.out.println("obj1 is " + obj1.num + ", obj2 is " + obj2.num); // obj1 10, obj2 5
}
// int型是直接賦值的
public static void swap(int m, int n)
{
int s = m;
m = n;
n = s;
}
public static void swap(MyNumber obj3, MyNumber obj4)
{
int s = obj3.num;
obj3.num = obj4.num;
obj4.num = s;
}
}
調用swap(a,b);在內存裏出現a和b,以及m和n,都是單獨的數字,m和n的交換不影響a和b
2.4
- 產生一個對象, A obj = new A();
- 99% 的情況是用new關鍵字,還有 1% 是用克隆和反射生成
- new出對象後,內部屬性值默認是? 例子Initialization.java
- short 0 int long 0L
- boolean false
- char ‘\u0000‘(’\u0000‘相當於一個空格)
- byte 0
- float 0.0f
- double 0.0d
public class Initialization {
boolean v1;
byte v2;
char v3;
double v4;
float v5;
int v6;
long v7;
short v8;
public static void main(String[] args) {
Initialization obj = new Initialization();
System.out.println("The initial value of boolean variable is " + obj.v1);
System.out.println("The initial value of byte variable is " + obj.v2);
System.out.println("The initial value of char variable is " + obj.v3); //\u0000 space
System.out.println("The initial value of double variable is " + obj.v4);
System.out.println("The initial value of float variable is " + obj.v5);
System.out.println("The initial value of int variable is " + obj.v6);
System.out.println("The initial value of long variable is " + obj.v7);
System.out.println("The initial value of short variable is " + obj.v8);
int a;
// System.out.println(a); //error, a 沒有初始化
}
}
2.5 總結
- 類是規範,對象根據產生出的實例
- 基本型別賦值是 拷貝賦值,對象賦值是reference賦值
- 類成員變量有初值,函數臨時變量必須初始化
3.構造函數
3.1
- 如何在對象產生時就給成員變量賦值呢
- 答案就在構造函數裏,constructor function
public class A {
int id;
public A(int id2) {
id = id2;
}
}
- A obj = new A(10);會調用構造函數
構造函數沒有返回值
public void A(int id2)不是構造函數,而實普通函數
3.2
Java構造函數的名稱必須和類名一樣,且沒有返回值
- Java有構造函數,但是沒有析構函數
- 構造函數是製造對象的過程,析構函數是清除對象的過程
- 每個變量都是有生命週期的,它只能存儲在離它最近的一
對{}中- 參看LifeCycleTest.java
public class LifeCycleTest {
public static void main(String[] args) {
int a=0; // a 在main函數中都是active
//i只能活在for循環中
for(int i=0; i<5; i++) {
int k = 0;
k++;
}
if(a>0) {
Object obj1 = new Object(); //obj1 只能在if分支中
System.out.println("a is positive");
} else {
Object obj2 = new Object(); //obj2 只能else分支中
System.out.println("a is non-positive");
}
}
}
每一個變量,都只能存活於離它最近的一對大括號當中
- 當變量被創建時,變量將佔據內存;當變量消亡時,系統
將回收內存
3.3
- Java具有內存自動回收機制的,當變量退出其生命週期後,
JVM會自動回收所分配的對象的內存。所以不需要析構函 數來釋放內存
。 - 對象回收效率依賴於
垃圾回收器GC
(Garbage Collector),
其回收算法關係到性能好壞,是JVM的研究熱點。
3.4
- 每個Java類都必須有構造函數。
- 如果沒有顯式定義構造函數,Java編譯器
自動
爲該
類產生一個空的無形參
構造函數。如果已經有了顯
式的有參構造函數,編譯器就不會越俎代庖了。
- 每個子類的構造函數的第一句話,都默認調用父類
的無參數構造函數super(),除非子類的構造函數第
一句話是super,而且super語句必須放在第一條,
不會出現連續兩條super語句。(本條規則在後續繼
承時會再提到)
3.5
- 一個類可以有多個構造函數,只要形參列表不相同
即可。
函數重載(overload),函數名相同,形參不同
- 在new對象的時候,根據實參的不同,自動挑選相應
的構造函數。如果實參形參匹配不上,將會報錯。 - 查看例子ConstructorTest.java
class MyPairNumber
{
int m;
int n;
public MyPairNumber()
{
m = 0;
n = 0;
}
public MyPairNumber(int a)
{
m = a;
n = 0;
}
public MyPairNumber(int a, int b)
{
m = a;
n = b;
}
}
public class ConstructorTest {
public static void main(String[] args) {
MyPairNumber obj1 = new MyPairNumber();
MyPairNumber obj2 = new MyPairNumber(5);
MyPairNumber obj3 = new MyPairNumber(10,20);
System.out.println("obj1 has " + obj1.m + "," + obj1.n);
System.out.println("obj2 has " + obj2.m + "," + obj2.n);
System.out.println("obj3 has " + obj3.m + "," + obj3.n);
// A a = new A(); //error, A類中沒有無參數的構造函數
}
}
多個class可以寫在一個.java文件中,但是最多隻能由一個類時public class,並且public class類的名字必須和.java的文件名相同
如果類由構造函數,編譯器不會自動增加無參的空的構造函數
3.6 總結
- 構造函數是一個對象初始化的過程。
- 一個類必須有構造函數,可以有多個構造函數。在new的
時候根據實參和形參進行匹配。 - Java只有構造函數,沒有析構函數。
4 信息隱藏和this
4.1 信息隱藏原則1
- 面向對象有一個法則:
信息隱藏
- 類的成員屬性,是私有的private;
- 類的方法是公有public的,通過方法修改成員屬性的值。
- 打個比方:朋友再熟悉,也不會到他抽屜直接拿東西,而
是通過他的公開接口來訪問、修改東西。
// InfoHiding
class InfoHiding {
private int id;
public InfoHiding(int id2) {
id = id2;
}
public int getId() {
return id;
}
public void setId(int id2) {
id = id2;
}
}
// InfoHidingTest
public class InfoHidingTest {
public static void main(String[] args) {
InfoHiding obj = new InfoHiding(100);
obj.setId(200);
System.out.println(obj.getId());
}
}
信息隱藏:通過類的方法來間接訪問類的屬性,而不是直接訪問類的屬性
4.2 信息隱藏原則2
- 類成員是私有private的
- get和set方法是公有public的,統稱爲getter和setter
- 外界對類成員的操作只能通過get和set方法
- 可以用Java IDE快速生成
public class Person {
private int height;
private int weight;
private int age;
private String name;
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
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;
}
}
4.3 this(1)
- this負責指向本類中的成員變量
// InfoHiding
class InfoHiding {
private int id;
public InfoHiding(int id2) {
id = id2;
}
public int getId() {
return id;
}
public void setId(int id2) {
id = id2;
}
}
// InfoHiding2
public class InfoHiding2 {
private int id;
public InfoHiding2(int id)
{
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
在InfoHiding2 的構造函數裏,形參的優先級更高
4.4 this(2)
- this負責指向本類中的成員方法
- this.add(5,3); //調用本類的add方法, this可忽略
在不影響歧義的情況下,this可以省略
- this.add(5,3); //調用本類的add方法, this可忽略
- this可以代替本類的構造函數
- this(5); //調用本類的一個形參的構造函數
- 參看ThisTest.java
// ThisTest
public class ThisTest {
public static void main(String[] args) {
MyPairNumber obj = new MyPairNumber(5);
System.out.println(obj.sum());
}
}
// MyPairNumber
public class MyPairNumber {
private int m;
private int n;
public int getM() {
return m;
}
public void setM(int m) {
this.m = m;
}
public int getN() {
return n;
}
public void setN(int n) {
this.n = n;
}
public MyPairNumber() {
this(0, 0);
}
public MyPairNumber(int m) {
this(m, 0);
}
public MyPairNumber(int m, int n) {
this.m = m;
this.n= n;
}
public int sum() {
return this.add(m,n); //return add(m,n); also ok
}
public int add(int a, int b){
return a+b;
}
}
this:指向本類中的成員變量;指向本類中的成員方法;可以當作構造函數使用
4.5 總結
- 信息隱藏原則
- 保護屬性信息
- 公開行爲信息
- this負責指向本類中的成員
- this可以代替本類的構造函數