大部分內容來自 www.sxt.cn 僅供自己學習,記錄一些筆記。侵刪。
4.1面向過程和麪向對象
-
面向對象具有三大特徵:封裝性、繼承性和多態性,而面向過程沒有繼承性和多態性,並且面向過程的封裝只是封裝功能,而面向對象可以封裝數據和功能。所以面向對象優勢更明顯。
-
一個經典的比喻:面向對象是蓋澆飯、面向過程是蛋炒飯。蓋澆飯的好處就是“菜”“飯”分離,從而提高了製作蓋澆飯的靈活性。飯不滿意就換飯,菜不滿意換菜。用軟件工程的專業術語就是“可維護性”比較好,“飯” 和“菜”的耦合度比較低。
4.2對象的進化史
- 數據無管理時代
- 數組管理和企業部門制
- 對象和企業項目制
- 幾類整合比較
5.總結
1.對象說白了也是一種數據結構(對數據的管理模式),將數據和數據的行爲放到了一起。
2.在內存上,對象就是一個內存塊,存放了相關的數據集合!
3.對象的本質就一種數據的組織方式!
4.3對象和類的概念
類可以看做是一個模版,或者圖紙,系統根據類的定義來造出對象。我們要造一個汽車,怎麼樣造?類就是這個圖紙,規定了汽車的詳細信息,然後根據圖紙將汽車造出來。
類:我們叫做class。 對象:我們叫做Object,instance(實例)。以後我們說某個類的對象,某個類的實例。是一樣的意思。
概括
1.對象是具體的事物;類是對對象的抽象;
2.類可以看成一類對象的模板,對象可以看成該類的一個具體實例。
3.類是用於描述同一類型的對象的一個抽象概念,類中定義了這一類對象所應具有的共同的屬性、方法。
4.3.1第一個類的定義
1.類的定義方式
// 每一個源文件必須有且只有一個public class,並且類名和文件名保持一致!
public class Car {
}
class Tyre { // 一個Java文件可以同時定義多個class
}
class Engine {
}
class Seat {
}
2.簡單學生類的編寫
public class SxtStu {
//屬性(成員變量)
int id;
String sname;
int age;
//方法
void study(){
System.out.println("我正在學習!");
}
//構造方法
SxtStu(){
}
}
3.屬性field
可以理解爲成員變量。
4.方法
方法用於定義該類或該類實例的行爲特徵和功能實現。方法是類和對象行爲特徵的抽象。方法很類似於面向過程中的函數。面向過程中,函數是最基本單位,整個程序由一個個函數調用組成。面向對象中,整個程序的基本單位是類,方法是從屬於類和對象的。
public class Sxtstu {
//屬性field
int id;
String name;
int age;
Computer comp;
void study() {
System.out.println("我在認真學習!使用電腦:"+comp.brand);
}
void play() {
System.out.println("我在玩遊戲!王者榮耀!");
}
//構造方法,用於創建這個類的對象
Sxtstu(){
}
//程序執行的入口,必須要有
public static void main(String[] args) {
Sxtstu stu=new Sxtstu();//創建一個對象
stu.id=1001;
stu.name="TZD";
stu.age=18;
Computer c1=new Computer();
c1.brand="聯想";
stu.comp=c1;
stu.play();
stu.study();
}
}
class Computer {
String brand;
}
4.4面向對象的內存分析
4.5構造方法
要點:
1. 通過new關鍵字調用!!
2. 構造器雖然有返回值,但是不能定義返回值類型(返回值的類型肯定是本類),不能在構造器裏使用return返回某個值。
3. 如果我們沒有定義構造器,則編譯器會自動定義一個無參的構造函數。如果已定義則編譯器不會自動添加!
4. 構造器的方法名必須和類名一致!
package Sxtstu;
class Point {
double x, y;
//構造方法的名稱必須和類名保持一致
public Point(double _x, double _y) {
x = _x;
y = _y;
}
public double getDistance(Point p) {
return Math.sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
}
}
public class TestConstructor {
public static void main(String[] args) {
Point p = new Point(3.0, 4.0);
Point origin = new Point(0.0, 0.0);
System.out.println(p.getDistance(origin));
}
}
4.6構造方法的重載
package Sxtstu;
public class Sxtstu {
int id; // id
String name; // 賬戶名
String pwd; // 密碼
public Sxtstu() {
}
public Sxtstu(int id, String name) {
super();//構造方法的第一句總是super()
this.id = id;//this 表示創建好的對象
this.name = name;
}
public Sxtstu(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public static void main(String[] args) {
Sxtstu u1 = new Sxtstu();
Sxtstu u2 = new Sxtstu(101, "高小七");
Sxtstu u3 = new Sxtstu(100, "高淇", "123456");
}
}
4.7垃圾回收機制
Java引入了垃圾回收機制,令C++程序員最頭疼的內存管理問題迎刃而解。Java程序員可以將更多的精力放到業務邏輯上而不是內存管理工作上,大大的提高了開發效率。
4.7.1 垃圾回收原理和算法
·垃圾回收過程
任何一種垃圾回收算法一般要做兩件基本事情:
1. 發現無用的對象
2. 回收無用對象佔用的內存空間。
垃圾回收機制保證可以將“無用的對象”進行回收。無用的對象指的就是沒有任何變量引用該對象。Java的垃圾回收器通過相關算法發現無用對象,並進行清除和整理。
·垃圾回收相關算法
1. 引用計數法
堆中每個對象都有一個引用計數。被引用一次,計數加1. 被引用變量值變爲null,則計數減1,直到計數爲0,則表示變成無用對象。優點是算法簡單,缺點是“循環引用的無用對象”無法別識別。
s1和s2互相引用對方,導致他們引用計數不爲0,但是實際已經無用,但無法被識別。
public class Student {
String name;
Student friend;
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
s1.friend = s2;
s2.friend = s1;
s1 = null;
s2 = null;
}
}
2. 引用可達法(根搜索算法)
程序把所有的引用關係看作一張圖,從一個節點GC ROOT開始,尋找對應的引用節點,找到這個節點以後,繼續尋找這個節點的引用節點,當所有的引用節點尋找完畢之後,剩餘的節點則被認爲是沒有被引用到的節點,即無用的節點。
4.7.2 通用的分代垃圾回收機制
·Minor GC:
用於清理年輕代區域。Eden區滿了就會觸發一次Minor GC。清理無用對象,將有用對象複製到“Survivor1”、“Survivor2”區中(這兩個區,大小空間也相同,同一時刻Survivor1和Survivor2只有一個在用,一個爲空)
·Major GC:
用於清理老年代區域。
·Full GC:
用於清理年輕代、年老代區域。 成本較高,會對系統性能產生影響。
垃圾回收過程
1、新創建的對象,絕大多數都會存儲在Eden中,
2、當Eden滿了(達到一定比例)不能創建新對象,則觸發垃圾回收(GC),將無用對象清理掉, 然後剩餘對象複製到某個Survivor中,如S1,同時清空Eden區
3、當Eden區再次滿了,會將S1中的不能清空的對象存到另外一個Survivor中,如S2,同時將Eden區中的不能清空的對象,也複製到S1中,保證Eden和S1,均被清空。
4、重複多次(默認15次)Survivor中沒有被清理的對象,則會複製到老年代Old(Tenured)區中,
5、當Old區滿了,則會觸發一個一次完整地垃圾回收(FullGC),之前新生代的垃圾回收稱爲(minorGC)
4.7.3 JVM調優和Full GC
在對JVM調優的過程中,很大一部分工作就是對於Full GC的調節。有如下原因可能導致Full GC:
1.年老代(Tenured)被寫滿
2.持久代(Perm)被寫滿
3.System.gc()被顯式調用(程序建議GC啓動,不是調用GC)
4.上一次GC之後Heap的各域分配策略動態變化
4.7.4 開發中容易造成內存泄露的操作
暫時不學
4.8 this關鍵字
public class User {
int id; //id
String name; //賬戶名
String pwd; //密碼
public User() {
}
public User(int id, String name) {
System.out.println("正在初始化已經創建好的對象:"+this);
this.id = id; //不寫this,無法區分局部變量id和成員變量id
this.name = name;
}
public void login(){
System.out.println(this.name+",要登錄!"); //不寫this效果一樣
}
public static void main(String[] args) {
User u3 = new User(101,"高小七");
System.out.println("打印高小七對象:"+u3);
u3.login();
}
}
public class TestThis {
int a, b, c;
TestThis() {
System.out.println("正要初始化一個Hello對象");
}
TestThis(int a, int b) {
// TestThis(); //這樣是無法調用構造方法的!
this(); // 調用無參的構造方法,並且必須位於第一行!
a = a;// 這裏都是指的局部變量而不是成員變量
// 這樣就區分了成員變量和局部變量. 這種情況佔了this使用情況大多數!
this.a = a;
this.b = b;
}
TestThis(int a, int b, int c) {
this(a, b); // 調用帶參的構造方法,並且必須位於第一行!
this.c = c;
}
void sing() {
}
void eat() {
this.sing(); // 調用本類中的sing();
System.out.println("你媽媽喊你回家喫飯!");
}
public static void main(String[] args) {
TestThis hi = new TestThis(2, 3);
hi.eat();
}
}
4.9 static 關鍵字
在類中,用static聲明的成員變量爲靜態成員變量,也稱爲類變量。 類變量的生命週期和類相同,在整個應用程序執行期間都有效。它有如下特點:
1. 爲該類的公用變量,屬於類,被該類的所有實例共享,在類被載入時被顯式初始化。
2. 對於該類的所有對象來說,static成員變量只有一份。被該類的所有對象共享!!
3. 一般用“類名.類屬性/方法”來調用。(也可以通過對象引用或類名(不需要實例化)訪問靜態成員。)
4. 在static方法中不可直接訪問非static的成員。
核心要點
static修飾的成員變量和方法,從屬於類。
普通變量和方法從屬於對象的。
/**
* 測試static關鍵字的用法
* @author 高淇
*
*/
public class User2 {
int id; // id
String name; // 賬戶名
String pwd; // 密碼
static String company = "北京尚學堂"; // 公司名稱
public User2(int id, String name) {
this.id = id;
this.name = name;
}
public void login() {
printCompany();
System.out.println(company);
System.out.println("登錄:" + name);
}
public static void printCompany() {
// login();//調用非靜態成員,編譯就會報錯
System.out.println(company);
}
public static void main(String[] args) {
User2 u = new User2(101, "高小七");
User2.printCompany();
User2.company = "北京阿里爺爺";
User2.printCompany();
}
}
4.10靜態初始化
構造方法用於對象的初始化!靜態初始化塊,用於類的初始化操作!在靜態初始化塊中不能直接訪問非static成員。
注意事項:
靜態初始化塊執行順序(學完繼承再看這裏):
1. 上溯到Object類,先執行Object的靜態初始化塊,再向下執行子類的靜態初始化塊,直到我們的類的靜態初始化塊爲止。
2. 構造方法執行順序和上面順序一樣!!
public class User3 {
int id; //id
String name; //賬戶名
String pwd; //密碼
static String company; //公司名稱
static {
System.out.println("執行類的初始化工作");
company = "北京尚學堂";
printCompany();
}
public static void printCompany(){
System.out.println(company);
}
public static void main(String[] args) {
User3 u3 = new User3();
}
}
4.11 參數傳值機制
Java中,方法中所有參數都是“值傳遞”,也就是“傳遞的是值的副本”。 也就是說,我們得到的是“原參數的複印件,而不是原件”。因此,複印件改變不會影響原件。
· 基本數據類型參數的傳值
傳遞的是值的副本。 副本改變不會影響原件。
· 引用類型參數的傳值
傳遞的是值的副本。但是引用類型指的是“對象的地址”。因此,副本和原參數都指向了同一個“地址”,改變“副本指向地址對象的值,也意味着原參數指向對象的值也發生了改變”。
/**
* 測試參數傳值機制
* @author 高淇
*
*/
public class User4 {
int id; //id
String name; //賬戶名
String pwd; //密碼
public User4(int id, String name) {
this.id = id;
this.name = name;
}
public void testParameterTransfer01(User4 u){
u.name="高小八";
}
public void testParameterTransfer02(User4 u){
u = new User4(200,"高三");
}
public static void main(String[] args) {
User4 u1 = new User4(100, "高小七");
u1.testParameterTransfer01(u1);
System.out.println(u1.name);
u1.testParameterTransfer02(u1);
System.out.println(u1.name);
}
}
/*輸出結果
高小八
高小八
*/
4.12 包
包機制是Java中管理類的重要手段。 開發中,我們會遇到大量同名的類,通過包我們很容易對解決類重名的問題,也可以實現對類的有效管理。 包對於類,相當於文件夾對於文件的作用。
4.13 package
我們通過package實現對類的管理,package的使用有兩個要點:
1. 通常是類的第一句非註釋性語句。
2. 包名:域名倒着寫即可,再加上模塊名,便於內部管理類。
注意事項:
-
寫項目時都要加包,不要使用默認包。
-
com.gao和com.gao.car,這兩個包沒有包含關係,是兩個完全獨立的包。只是邏輯上看起來後者是前者的一部分。
package cn.sxt;
public class Test {
public static void main(String[] args) {
System.out.println("helloworld");
}
}
4.13.1 JDK中的主要包
4.13.2 導入類import
如果我們要使用其他包的類,需要使用import導入,從而可以在本類中直接通過類名來調用,否則就需要書寫類的完整包名和類名。import後,便於編寫代碼,提高可維護性。
- Java會默認導入java.lang包下所有的類,因此這些類我們可以直接使用。
- 如果導入兩個同名的類,只能用包名+類名來顯示調用相關類:
import java.sql.Date;
import java.util.*;//導入該包下所有的類。會降低編譯速度,但不會降低運行速度。
public class Test{
public static void main(String[] args) {
//這裏指的是java.sql.Date
Date now;
//java.util.Date因爲和java.sql.Date類同名,需要完整路徑
java.util.Date now2 = new java.util.Date();
System.out.println(now2);
//java.util包的非同名類不需要完整路徑
Scanner input = new Scanner(System.in);
}
}
4.13.3 靜態導入
靜態導入(static import)是在JDK1.5新增加的功能,其作用是用於導入指定類的靜態屬性,這樣我們可以直接使用靜態屬性。
package cn.sxt;
//以下兩種靜態導入的方式二選一即可
import static java.lang.Math.*;//導入Math類的所有靜態屬性
import static java.lang.Math.PI;//導入Math類的PI屬性
public class Test2{
public static void main(String [] args){
System.out.println(PI);
System.out.println(random());
}
}
/*
輸出結果
3.141592653589793
0.66487.....
*/
總結
-
面向對象可以幫助我們從宏觀上把握、從整體上分析整個系統。 但是具體到實現部分的微觀操作(就是一個個方法),仍然需要面向過程的思路去處理。
-
類可以看成一類對象的模板,對象可以看成該類的一個具體實例。
-
對於一個類來說,一般有三種常見的成員:屬性field、方法method、構造器constructor。
-
構造器也叫構造方法,用於對象的初始化。構造器是一個創建對象時被自動調用的特殊方法,目的是對象的初始化。構造器的名稱應與類的名稱一致。
-
Java引入了垃圾回收機制,令C++程序員最頭疼的內存管理問題迎刃而解。Java程序員可將更多的精力放到業務邏輯上而不是內存管理工作,大大提高開發效率。
-
this的本質就是“創建好的對象的地址”! this不能用於static方法中。
-
在類中,用static聲明的成員變量爲靜態成員變量,也稱爲類變量。類變量的生命週期和類相同,在整個應用程序執行期間都有效。在static方法中不可直接訪問非static的成員。
-
Java方法中所有參數都是“值傳遞”,也就是“傳遞的是值的副本”。也就是說,我們得到的是“原參數的複印件,而不是原件”。因此,複印件改變不會影響原件。
-
通過package實現對類的管理;如果我們要使用其他包的類,需要使用import導入,從而可以在本類中直接通過類名來調用。