成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何在Java中創建優雅的對象來提升程序性能

開發 后端
Java 對象的創建方式是其語法明確規定,用戶不可能從外部改變的。本文仍然要使用上面的方式來創建對象,所以本文只能說是構建對象,而非創建對象也。

[[348621]]

 其實這個問題很多人都進行過解答,也有很多小伙伴在Java四大名著之一的《Effective Java》中的第1~5小節了解過,不過我還是想結合自己的理解對這個問題進行總結和歸納,談談為什么會最終選擇構建器來實現我們的目的。

在 Java 中有多種方式可以創建對象,總結起來主要有下面的 4 種方式:

正常創建:通過 new 操作符

反射創建:調用 Class 或 java.lang.reflect.Constructor 的 newInstance()方法

克隆創建:調用現有對象的 clone()方法

發序列化:調用 java.io.ObjectInputStream 的 getObject()方法反序列化

Java 對象的創建方式是其語法明確規定,用戶不可能從外部改變的。本文仍然要使用上面的方式來創建對象,所以本文只能說是構建對象,而非創建對象也。

假設有這樣一個場景,現在要構建一個大型的對象,這個對象包含許多個參數的對象,有些參數有些是必填的,有些則是選填的。那么如何構建優雅、安全地構建這個對象呢?

01 單一構造函數

通常,我們第一反應能想到的就是單一構造函數方式。直接 new 的方式構建,通過構造函數來傳遞參數,見下面的代碼:

  1. /*** 
  2. * 單一構造函數 
  3. */ 
  4. public class Person { 
  5. // 姓名(必填) 
  6. private String name
  7. // 年齡(必填) 
  8. private int age; 
  9. // 身高(選填) 
  10. private int height; 
  11. // 畢業學校(選填) 
  12. private String school; 
  13. // 愛好(選填) 
  14. private String hobby; 
  15. public Person(String nameint age, int height, String school, String hobby) { 
  16. this.name = name
  17. this.age = age; 
  18. this.height = height; 
  19. this.school = school; 
  20. this.hobby = hobby; 
  21. } } 

上面的構建方式有下面的缺點:

有些參數是可以選填的(如 height, school),在構建 Person 的時候必須要傳入可能并不需要的參數。

現在上面才 5 個參數,構造函數就已經非常長了。如果是 20 個參數,構造函數都可以直接上天了!

構建的這樣的對象非常容易出錯。

客戶端必須要對照 Javadoc 或者參數名來講實參傳入對應的位置。如果參數都是 String 類型的,一旦傳錯參數,編譯是不會報錯的,但是運行結果卻是錯誤的。

02 多構造函數

對于第 1 個問題,我們可以通過構造函數重載來解決。見下面的代碼:

  1. /*** 
  2. * 多構造函數 
  3. */ 
  4. public class Person { 
  5. // 姓名(必填) 
  6. private String name
  7. // 年齡(必填) 
  8. private int age; 
  9. // 身高(選填) 
  10. private int height; 
  11. // 畢業學校(選填) 
  12. private String school; 
  13. // 愛好(選填) 
  14. private String hobby; 
  15. public Person(String nameint age) { 
  16. this.name = name
  17. this.age = age; 
  18. public Person(String nameint age, int height) { 
  19. this.name = name
  20. this.age = age; 
  21. this.height = height; 
  22. public Person(String nameint age, int height, String school) { 
  23. this.name = name
  24. this.age = age; 
  25. this.height = height; 
  26. this.school = school; 
  27. public Person(String nameint age, String hobby, String school) { 
  28. this.name = name
  29. this.age = age; 
  30. this.hobby = hobby; 
  31. this.school = school; 
  32. } } 

上面的方式確實能在一定程度上降低構造函數的長度,但是卻有下面的缺陷:

 

導致類過長。這種方式會使得 Person 類的構造函數成階乘級增長。按理來說,應該要寫的構造函數數是可選成員變量的組合數(實際并沒有這么多,原因見第 2 點)。如果讓我調用這樣的類,絕對會在心里默念 xx!!

有些參數組合無法重構。因為 Java 中重載是有限制的,相同方法簽名的方法不能構成重載,編譯時無法通過。譬如包含(name, age, school)和(name, age, hobby)的構造函數是不能重載的,因為 shcool 和 hobby 同為 String 類型。Java 只認變量的類型,管你變量是什么含義呢。

03 JavaBean方式

上面的方法不行,莫急!還有法寶——JavaBean。一個對象的構建通過多個方法來完成。直接見下面的代碼:

  1. public class Person { 
  2. // 姓名(必填) 
  3. private String name
  4. // 年齡(必填) 
  5. private int age; 
  6. // 身高(選填) 
  7. private int height; 
  8. // 畢業學校(選填) 
  9. private String school; 
  10. // 愛好(選填) 
  11. private String hobby; 
  12. public Person(String nameint age) { 
  13. this.name = name
  14. this.age = age; 
  15. public void setHeight(int height) { 
  16. this.height = height; 
  17. public void setSchool(String school) { 
  18. this.school = school; 
  19. public void setHobby(String hobby) { 
  20. this.hobby = hobby; 
  21. } } 
  22. 客戶端使用這個對象的代碼如下: 
  23. public class Client { 
  24. public static void main(String[] args) { 
  25. Person person = new Person("james", 12); 
  26. person.setHeight(170); 
  27. person.setHobby("reading"); 
  28. person.setSchool("xxx university"); 
  29. } } 

這樣看起來完美的解決了 Person 對象構建的問題,使用起來非常優雅便捷。確實,在單一線程的環境中這確實是一個非常好的構建對象的方法,但是如果是在多線程環境中仍有其致命缺陷。在多線程環境中,這個對象不能安全地被構建,因為它不是不可變對象。一旦Person 對象被構建,我們隨時可通過 setXXX()方法改變對象的內部狀態。假設有一個線程正在執行與 Person 對象相關的業務方法,另外一個線程改變了其內部狀態,這樣得到莫名其妙的結果。由于線程運行的無規律性,使得這問題有可能不能重現,這個時候真的就只能哭了。

04 Builder方式

為了完美地解決這個問題,下面引出本文中的主角(等等等等!)。我們使用構建器(Builder)來優雅、安全地構建 Person 對象。廢話不說,直接代碼:

  1. /** 
  2. * 待構建的對象。該對象的特點: 
  3. * <ol> 
  4. * <li>需要用戶手動的傳入多個參數,并且有多個參數是可選的、順序隨意</li> 
  5. * <li>該對象是不可變的(所謂不可變,就是指對象一旦創建完成,其內部狀態不可變, 
  6. 更通俗的說是其成員變量不可改變)。* 不可變對象本質上是線程安全的。</li> 
  7. * <li>對象所屬的類不是為了繼承而設計的。</li> 
  8. * </ol> 
  9. * 滿足上面特點的對象的構建可是使用下面的 Build 方式構建。這樣構建對象有下面的好 
  10. 處: 
  11. * <ol> 
  12. * <li>不需要寫多個構造函數,使得對象的創建更加便捷</li> 
  13. * <li>創建對象的過程是線程安全的</li> 
  14. * </ol> 
  15. * @author xiaoyu 
  16. * @date 2020-10-25 
  17. */ 
  18. public class Person { 
  19. // 姓名(必填),final 修飾 name 一旦被初始化就不能再改變,保證了對象的不可變 
  20. 性。 
  21. private final String name
  22. // 年齡(必填) 
  23. private final int age; 
  24. // 身高(選填) 
  25. private final int height; 
  26. // 畢業學校(選填) 
  27. private final String school; 
  28. // 愛好(選填) 
  29. private final String hobby; 
  30. /** 
  31. * 這個私有構造函數的作用: 
  32. * <ol> 
  33. * <li>成員變量的初始化。final 類型的變量必須進行初始化,否則無法編譯成功</li> 
  34. * <li>私有構造函數能夠保證該對象無法從外部創建,并且 Person 類無法被繼承</li> 
  35. * </ol> 
  36. */ 
  37. private Person(String nameint age, int height, String school, String hobby) { 
  38. this.name = name
  39. this.age = age; 
  40. this.height = height; 
  41. this.school = school; 
  42. this.hobby = hobby; 
  43. /** 
  44. * 要執行的動作 
  45. */ 
  46. public void doSomething() { 
  47. // TODO do what you want!! 
  48. /** 
  49. * 構建器。為什么 Builder 是內部靜態類? 
  50. * <ol> 
  51. * <li>必須是 Person 的內部類。否則,由于 Person 的構造函數私有,不能通過 new 的 
  52. 方式創建 Person 對象</li> 
  53. * <li>必須是靜態類。由于 Person 對象無法從外部創建,如果不是靜態類,則外部無 
  54. 法引用 Builder 對象。</li> 
  55. * </ol> 
  56. * <b>注意</b>:Builder 內部成員變量要與 Person 的成員變量保持一致。 
  57. * @author xiaoyu 
  58. */ 
  59. public static class Builder { 
  60. // 姓名(必填)。注意:這里不能是 final 的 
  61. private String name
  62. // 年齡(必填) 
  63. private int age; 
  64. // 身高(選填) 
  65. private int height; 
  66. // 畢業學校(選填) 
  67. private String school; 
  68. // 愛好(選填) 
  69. private String hobby; 
  70. public Builder(String nameint age) { 
  71. this.name = name
  72. this.age = age; 
  73. public Builder setHeight(int height) { 
  74. this.height = height; 
  75. return this; 
  76. public Builder setSchool(String school) { 
  77. this.school = school; 
  78. return this; 
  79. public Builder setHobby(String hobby) { 
  80. this.hobby = hobby; 
  81. return this; 
  82. /** 
  83. * 構建對象 
  84. * @return 返回待構建的對象本身 
  85. */ 
  86. public Person build() { 
  87. return new Person(name, age, height, school, hobby); 
  88. } } } 

客戶端構建對象的方式見下面的代碼:

  1. /** 
  2. * 使用 Person 對象的客戶端 
  3. * @author xiaoyu 
  4. * @date 2020-10-25 
  5. */ 
  6. public class Client { 
  7. public static void main(String[] args) { 
  8. /* 
  9. * 通過鏈式調用的方式創建 Person 對象,非常優雅! 
  10. */ 
  11. Person person = new Person.Builder("james", 12) 
  12. .setHeight(170) 
  13. .setHobby("reading"
  14. .build(); 
  15. person.doSomething(); 
  16. } } 

如果不想看代碼,可看下面對于上面代碼的總結:

 

通過 private Person(..)使得 Person 類不可被繼承

通過將 Person 類的成員變量設置為 final 類型,使得其不可變

通過 Person 內部的 static Builder 類來構建 Person 對象

通過將 Builder 類內部的 setXXX()方法返回 Builder 類型本身,實現鏈式調用構建 Person 對 象

 

總結

至此,我們就相對完美地解決這一類型的對象創建問題!下面來總結一下本文的重點。待創建的對象特點:

需要用戶手動的傳入多個參數,并且有多個參數是可選的、順序任意

對象不可變

對象所屬的類不是為了繼承而設計的。即類不能被繼承

 

依次使用的對象構建方法:

單一構造函數

多構造函數

JavaBean 方式

Builder 方式

最終,通過比較得出 Builder 方法最為合適的解決。

責任編輯:姜華 來源: 淺羽的IT小屋
相關推薦

2019-02-01 09:50:00

提升Python程序性能

2020-12-03 08:00:00

SQL數據庫MySQL

2018-07-06 16:26:11

編程語言Python程序性能

2024-05-16 11:04:06

C#異步編程編程

2011-09-20 10:41:45

Web

2022-10-08 13:13:14

Python程序性能

2024-12-05 15:33:50

Python列表元組

2024-12-09 09:50:00

JVM逃逸逃逸分析

2023-04-13 07:33:31

Java 8編程工具

2012-01-06 13:48:59

flash

2025-02-10 03:00:00

2023-09-27 23:24:50

C++鏈表

2009-07-24 16:40:14

ASP.NET軟件開發

2012-05-19 22:24:34

MVVM

2018-11-20 10:50:00

Java性能優化編程技巧

2023-11-14 08:36:15

Celery工具

2024-05-17 13:01:31

C#編程開發

2023-05-12 13:21:12

JMHJava程序

2010-08-10 13:58:00

Flex性能測試

2010-06-11 10:19:22

systemd
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品自拍视频在线观看 | 精品国产一区二区三区久久久蜜月 | 午夜爽爽爽男女免费观看影院 | 久久亚洲国产 | 国产精品久久久久无码av | 国产欧美一区二区三区在线播放 | 国内精品伊人久久久久网站 | 久久精品99国产精品日本 | 国产精品久久久久久久久久久免费看 | 九一视频在线观看 | 国产高清精品一区二区三区 | 久久久久国产精品 | 国产91av视频在线观看 | a免费视频 | 免费一区二区三区 | 99精品欧美一区二区三区 | 亚洲欧美一区二区三区国产精品 | 欧美性生交大片免费 | 精品视频在线播放 | 在线视频 亚洲 | 日一区二区三区 | 欧美一区在线看 | 在线看免费| 精品免费国产视频 | 中文字幕在线视频一区二区三区 | 超碰97人人人人人蜜桃 | 欧美亚洲国产精品 | 国产免费看 | 亚洲毛片一区二区 | 五月综合激情在线 | 欧美性一区二区三区 | xxxxx黄色片 欧美一区免费 | 中文一区二区 | 精品自拍视频在线观看 | 久久99国产精品 | 韩国精品在线 | 亚洲人成一区二区三区性色 | 亚洲一区在线日韩在线深爱 | 精品久久久久久久久久 | 午夜在线 | 久久国产高清 |