java中通用的方法和準則
1.不要讓常量和變量中出現(xiàn)易混淆的字母
比如: long i = 1l;
別人很難一下子看清楚是11還是1l,,所以應(yīng)該這樣寫1L,。
命名規(guī)范:
1.包名全部小寫
2.類名首字母大寫
3.方法名稱,,首字母小寫,后面單詞首字母大寫
4.常量要用大寫,,并且用下劃線隔開
5.變量要用小寫
2.莫讓常量蛻變成變量
interface Const {
public static final int RANDOM_NUM = new Random().nextInt(10);
}
for (int j = 0; j < 5; j++) {
Log.i("clp", "num =" + Const.RANDOM_NUM);
}
上面的代碼,,每次運行值都會不一樣。
RE:只有在值固定的時候,,才考慮用final,。否則輕易不要用。 static有時候在臨時保存數(shù)據(jù)的時候會用到,。
3.三元操作符的類型務(wù)必一致
int i = 80;
String s1 = String.valueOf(i < 100 ? 90 : 100);
String s2 = String.valueOf(i < 100 ? 90 : 100.0);
Log.i("clp", "s1=" + s1);
Log.i("clp", "s2=" + s2);
I/clp: s1=90
I/clp: s2=90.0
規(guī)則:
1.如果2個類型不能相互轉(zhuǎn)換,,就返回Object類型
2.如果是明確類型的表達式(比如變量),,則int類型轉(zhuǎn)為long,,long類型轉(zhuǎn)為float
…還有其他規(guī)則
4.避免帶有邊長參數(shù)的方法重載
public int getCount(int type, int i, int j) {
return i + j;
}
public int getCount(int type, int... value) {
int count = 0;
for (int i : value) {
count *= i;
}
return count;
}
Log.i("clp", "count=" + getCount(1, 3, 4));
上面的代碼,,很容易搞混,可能不分析具體原因,,不知道會調(diào)用那個,。
RE:其實會調(diào)用int參數(shù)的那個,因為編譯器從最簡單的開始,。
I/clp: count=7
5.不要讓null或者空值影響到邊長方法
public void methodA(String name, Integer... value) {
}
public void methodA(String name, String... value) {
}
methodA("a", 1, 2);
methodA("b", "e", "e");
methodA("c");//編譯器報錯
methodA("c", null);//編譯器報錯
上面解決的辦法是傳入空的String,。
RE:我感覺最好的辦法是,避免這種寫法,,遇到這種情況,,不要去重載。
基本類型
27.謹慎包裝類型的大小比較
Integer i = new Integer(2);
Integer j = new Integer(2);
//比較封裝對象的大小,,只能使用i.compareTo(j),。
//i==j,i>j,j<j都返回false。 i==j是返回對象的引用地址,。i>j,j<j是值的比較,。
28.優(yōu)先使用整形池
int input = 127;//128 555
Integer ii = new Integer(input);
Integer jj = new Integer(input);
Log.i("clp", "new 產(chǎn)生的對象:" + (ii == jj));//都為false
ii = input;
jj = input;
Log.i("clp", "基本類型產(chǎn)生的對象" + (ii == jj));//127為true,128 555為false
ii = Integer.valueOf(input);
jj = Integer.valueOf(input);
Log.i("clp", "valueOf 產(chǎn)生的對象" + (ii == jj));//127為true,,128 555為false
1.new產(chǎn)生的對象比較,,肯定為false
2.自動裝箱和Integer.valueOf一樣(裝箱時通過valueOf實現(xiàn))
3.valueOf的實現(xiàn)方式,在-128和127之間,,使用的是緩沖,。超過的話,直接new
public static Integer valueOf(int i) {
final int offset = 128;
if (i > -128 && i < 127) {
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
29.優(yōu)先使用基本類型
int i = 14;
f(i);
f(Integer.valueOf(i));
public static void f(long i) {
Log.i("clp", "基本類型的方法被調(diào)用");
}
public static void f(Long i) {
Log.i("clp", "包裝的方法被調(diào)用");
}
輸出結(jié)果:
Log.i(“clp”, “基本類型的方法被調(diào)用”);
Log.i(“clp”, “基本類型的方法被調(diào)用”);
解析:1.自動裝箱只有在賦值時才有關(guān)系,,重載可以編譯通過
2.f(i)不會報錯,,因為編輯器會自動把i加寬,變?yōu)閘ong
3.f(Integer.valueOf(i))不會報錯:基本類型,,可以先加寬在包裝,。但是不能直接包裝。所以1.先轉(zhuǎn)變?yōu)镮nteger對象,,然后調(diào)用方法的時候發(fā)現(xiàn)沒有,,自動轉(zhuǎn)換為int基本類型 3.發(fā)現(xiàn)沒有,自動加寬變?yōu)閘ong
4.如果把f(long i)方法給注釋掉,,代碼是編譯不通過的
30.不要隨便設(shè)置隨機種子
Random random = new Random(1000);
for (int i = 0; i < 4; i++) {
CldLog.i("clp", "第" + i + "次的隨機數(shù)為:" + random.nextInt());
}
RE:按照上面的代碼寫,,每次運行都會得到想通的隨機數(shù)。通過Random random = new Random(),,則不能固定范圍
04-15 11:35:44.565 15244-15244/cld.navi.mainframe I/clp: 第0次的隨機數(shù)為:-1244746321 @initControls:CldModeA.Java(72)
04-15 11:35:44.565 15244-15244/cld.navi.mainframe I/clp: 第1次的隨機數(shù)為:1060493871 @initControls:CldModeA.java(72)
04-15 11:35:44.565 15244-15244/cld.navi.mainframe I/clp: 第2次的隨機數(shù)為:-1826063944 @initControls:CldModeA.java(72)
04-15 11:35:44.565 15244-15244/cld.navi.mainframe I/clp: 第3次的隨機數(shù)為:1976922248 @initControls:CldModeA.java(72)
正確寫法如下:
Random random = new Random();
for (int i = 0; i < 4; i++) {
CldLog.i("clp", "第" + i + "次的隨機數(shù)為:" + random.nextInt(20));
}
類,、對象及方法
31.接口中不要存在實現(xiàn)代碼
RE:這個都知道
32.靜態(tài)變量一定要先聲明后賦值
static {
i = 100;
}
public static int i = 1;
//輸出結(jié)果,,i等于1
public static int i = 1;
static {
i = 100;
}
//輸出結(jié)果,i等于100
1.靜態(tài)變量是類加載的時候分配到存儲區(qū)的
2.靜態(tài)變量在類初始化的時候首先被加載,,分配地址空間,,還沒賦值
3.按照靜態(tài)類和靜態(tài)塊的先后順序賦值,所以誰的位置在后面,,誰有最終的決定權(quán)
33.不要復(fù)寫靜態(tài)方法
public class Base {
public static void doBaseStatic() {
Log.i("clp", "doBaseStatic");
}
public void doBase() {
Log.i("clp", "doBase No Static");
}
}
public class Sub extends Base {
public static void doBaseStatic() {
Log.i("clp", "do Sub Static");
}
public void doBase() {
Log.i("clp", "do Sub No Static");
}
}
Base mBase = new Sub();
mBase.doBase();//do Sub No Static
Base.doBaseStatic();//doBaseStatic
mBase.doBaseStatic();//doBaseStatic
//Android Studio用上面的寫法會提示
Sub.doBaseStatic();//do Sub Static
1.mBase.doBaseStatic()實際上調(diào)用的是父類的方法,。因為靜態(tài)方法不依賴實例對象,是通過類名訪問的
34.構(gòu)造函數(shù)盡量簡化
public abstract class Server {
public static int DEFAULT_PORT = 4000;
public Server() {
Log.i("clp", "Server");
int port = getPort();
Log.i("clp", "port=" + port);
// Log.i();
}
protected abstract int getPort();
}
public class ServerIml extends Server {
public int port = 100;
public ServerIml(int port) {
Log.i("clp", "ServerIml");
this.port = port;
}
@Override
protected int getPort() {
// return port;//值為0
return DEFAULT_PORT;//返回值4000
}
}
ServerIml serverIml = new ServerIml(80);
這個跟構(gòu)造方法的執(zhí)行順序有關(guān),。
04-15 14:35:54.027 7381-7381/com.example.demo I/clp: Server
04-15 14:35:54.027 7381-7381/com.example.demo I/clp: port=4000
04-15 14:35:54.027 7381-7381/com.example.demo I/clp: ServerIml
執(zhí)行順序如下:
1.子類的構(gòu)造函數(shù)接收int類型的參數(shù)(沒有賦值)
2.父類初始化常量,,也就是DEFAULT_PORT,并賦值為4000
3.執(zhí)行父類無參的構(gòu)造方法
4.調(diào)用int port = getPort();獲取端口號 ,,調(diào)用子類端口號的實現(xiàn)方法,。此時DEFAULT_PORT已經(jīng)有值,但是port子類的
構(gòu)造函數(shù)還沒有執(zhí)行,,所以沒有賦值,,返回0
5.父類初始化完畢,開始初始化子類
6.子類被賦值為100
7.執(zhí)行子類的構(gòu)造函數(shù),,重新賦值為80
35.避免在構(gòu)造函數(shù)中初始化其他類
public class Son extends Father {
public void doSomeThing() {
Log.i("clp", "doSomeThing");
}
}
public class Father {
Father() {
new Other();
}
}
public class Other {
Other() {
new Son();
}
}
Son son = new Son();
son.doSomeThing();
上面的代碼,,直接回導(dǎo)致程序死掉。陷入死循環(huán),。
36.使用構(gòu)造代碼塊精煉程序
代碼塊:
1.使用static{}的靜態(tài)代碼塊,。類創(chuàng)建的時候加載
2.方法后面{}的普通代碼塊,必須通過調(diào)用方法名稱使用
3.synchronize修飾的同步代碼塊
4.構(gòu)造代碼塊,,在類中沒有任何修飾,,直接使用{}
public class CldGouzaoUtil {
{
Log.i("clp", "構(gòu)造代碼塊");
}
public CldGouzaoUtil() {
Log.i("clp", "構(gòu)造方法");
}
}
04-15 14:59:55.597 22529-22529/com.example.demo I/clp: 構(gòu)造代碼塊
04-15 14:59:55.597 22529-22529/com.example.demo I/clp: 構(gòu)造方法
構(gòu)造代碼塊,不同于static代碼塊,,它是依賴于構(gòu)造方法執(zhí)行,。所以用途主要為
1.初始化實例變量
2.初始化實例環(huán)境
RE:2個都是在構(gòu)造方法執(zhí)行前執(zhí)行一些初始化、檢測的操作,。
37.構(gòu)造代碼塊會想你所想
public class CldGouzaoUtil {
protected static int numOfNew = 0;
{
numOfNew++;
}
public CldGouzaoUtil() {
}
public CldGouzaoUtil(String mDes) {
this();
}
public static int getNumOfNew() {
return numOfNew;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
new CldGouzaoUtil();
new CldGouzaoUtil("haha");
new CldGouzaoUtil("haha");
Log.i("clp", "初始化的次數(shù)為:" + CldGouzaoUtil.getNumOfNew());
04-15 15:31:37.737 19985-19985/com.example.demo I/clp: 初始化的次數(shù)為:3
new CldGouzaoUtil(“haha”)這種構(gòu)造函數(shù)調(diào)用this的,,構(gòu)造代碼塊也只會執(zhí)行一次。而且只要不殺死程序,,次數(shù)會一直保留,。
38.使用靜態(tài)內(nèi)部類提高封裝性
//使用靜態(tài)內(nèi)部類加強類的封裝性和提高代碼的可讀性
public class CldInnerStatic {
//提高封裝性-比如這個代表home是外部類的子行為
//提高代碼的可讀性
//形似內(nèi)部,神似外部---可以脫離外部存在
String name;
public Home home;
private static int outer = 100;
public CldInnerStatic(String name) {
this.name = name;
}
public void setHome(Home home) {
this.home = home;
}
//不持有外部類的引用
//靜態(tài)內(nèi)部類不依賴外部類
public static class Home {//靜態(tài)內(nèi)部類
public String addr;//地址
public int tel;//家庭電話
public Home(String addr, int tel) {
this.addr = addr;
this.tel = tel;
// name = "哈哈";//報錯-不能訪問外部類的變量
outer = 80;//靜態(tài)內(nèi)部類可以訪問外部類static的變量
}
}
public class Company {
// public static int comAddr = "";//報錯-普通內(nèi)部類不能聲明static的方法和變量
//報錯
// public static void setComName() {//普通內(nèi)部類不能聲明static的方法和變量
//
// }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
CldInnerStatic innerStatic = new CldInnerStatic("張三");
innerStatic.setHome(new CldInnerStatic.Home("上海", 02166666666));
39.使用匿名內(nèi)部類的構(gòu)造函數(shù)
List<String> mList = new ArrayList<>();
List<String> mList2 = new ArrayList<>() {
};
List<String> mList3 = new ArrayList<>() {
{//代碼塊
}
};
第二種和第三種都是相當于匿名內(nèi)部類List mlist2 = new Sub();
40.匿名類的構(gòu)造函數(shù)很特殊
public class CldCalculator {
{//在這里,,計算出來的值就為0,,在使用的地方就是正確的
setOperator();
Log.i("clp", "setOperator");
}
private int i, j, result;
public CldCalculator() {
}
public CldCalculator(int i, int j) {
Log.i("clp", "CldCalculator");
this.i = i;
this.j = j;
}
protected void setOperator() {
result = i + j;
}
public int getResult() {
return result;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
public class SubCal extends CldCalculator {
{//在這里,計算出來的值就為0,在使用的地方就是正確的
setOperator();
Log.i("clp", "setOperator");
}
public SubCal(int i, int j) {
}
}
CldCalculator calculator = new CldCalculator(1, 2) {
// {
// setOperator();//這里使用,,值是正確的
// Log.i("clp", "setOperator");
// }
};
Log.i("clp", "result=" + calculator.getResult());
CldCalculator calculator1 = new SubCal(1, 2);
Log.i("clp", "calculator1=" + calculator.getResult());//結(jié)果為0
兩個結(jié)果不一樣,,因為匿名內(nèi)部類的特殊處理機制。一般的類都是默認調(diào)用父類的無參構(gòu)造,。但是匿名類沒有名字,,直接由
構(gòu)造代碼塊代替,直接調(diào)用了父類的同參構(gòu)造方法,。然后再調(diào)用自己的構(gòu)造代碼塊,。
41.讓多繼承成為現(xiàn)實
使用內(nèi)部類,巧妙的實現(xiàn)多繼承
public interface Father {
int Strong();//強壯指數(shù)
}
public interface Mother {
int kind();//溫柔指數(shù)
}
public class FatherIml implements Father {
@Override
public int Strong() {
return 8;
}
}
public class MotherIml implements Mother {
@Override
public int kind() {
return 8;
}
}
public class Son extends FatherIml implements Mother {
@Override
public int Strong() {
return super.Strong() + 2;//比付清還要強壯
}
@Override
public int kind() {
return new MotherIml() {
@Override
public int kind() {
return super.kind() - 2;//溫柔比母親少了2個點
}
}.kind();
}
}
Son son = new Son();
Log.i("clp", "strong =" + son.Strong() + ";kind=" + son.kind());
//結(jié)果:04-15 17:32:13.267 14610-14610/? I/clp: strong =10;kind=6
42.讓工具類不可實例化
工具類的正確構(gòu)建方式:1.不能實例化 2.不能繼承
public final class CldUtil {
private CldUtil() {
throw new Error("不要實例化我");
}
}
43.避免對象的淺拷貝
public class Person implements Cloneable {
//名稱
private String name;
//父親
private Person father;
public Person(String name) {
this.name = name;
}
public Person(String name, Person father) {
this.name = name;
this.father = father;
}
public void setName(String name) {
this.name = name;
}
public void setFather(Person father) {
this.father = father;
}
public String getName() {
return name;
}
public Person getFather() {
return father;
}
@Override
public Person clone() {//對象的拷貝
Person p = null;
try {
p = (Person) super.clone();
p.setFather(new Person(p.getFather().getName()));//如果沒有這句話,,就是淺拷貝,加了這句話,,就是深拷貝
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
Person father = new Person("父親");
Person p1 = new Person("大兒子", father);
Person p2 = p1.clone();
p2.setName("小兒子");
// p2.setFather(new Person("干爹"));
p2.getFather().setName("干爹");
Log.i("clp", "fist name=" + p1.getName() + ";father =" + p1.getFather().getName());
Log.i("clp", "sec name=" + p2.getName() + ";father =" + p2.getFather().getName());
使用淺拷貝
04-15 17:55:30.827 2810-2810/com.example.demo I/clp: fist name=大兒子;father =干爹
04-15 17:55:30.827 2810-2810/com.example.demo I/clp: sec name=小兒子;father =干爹
使用p2.setFather(new Person(“干爹”));或者深拷貝
04-15 17:58:27.197 2810-2810/com.example.demo I/clp: fist name=大兒子;father =父親
04-15 17:58:27.197 2810-2810/com.example.demo I/clp: sec name=小兒子;father =干爹
44.推薦使用序列化實現(xiàn)對象的拷貝
public class Person implements Serializable {
private static final long serialVersionUID = 201704161112L;
//名稱
public String name;
//父親
public Person person;
public Person(String name) {
this.name = name;
}
public Person(String name, Person person) {
this.name = name;
this.person = person;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
//使用字節(jié)流實現(xiàn)對象的拷貝
public static <T extends Serializable> T clone(T obj) {
//final和static的序列化問題會被引入到對象的拷貝中???
//transient變量也會影響到拷貝的結(jié)果???
T cloneObj = null;
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);//如果不實現(xiàn)序列化,,則會拋出序列化異常
objectOutputStream.close();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
cloneObj = (T) objectInputStream.readObject();
objectInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
01-04 19:27:44.620 17104-17104/old.pkg.com.myapplicati I/clp: 名稱:小兒子;父親為:父親
01-04 19:27:44.620 17104-17104/old.pkg.com.myapplicati I/clp: 名稱:大兒子;父親為:干爹
45.復(fù)寫equals方法時不要識別不出自己
public class Person {
//名稱
public String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Person) {
Person person = (Person) obj;
//equalsIgnoreCase為忽略大小寫
return name.equalsIgnoreCase(person.getName());
// return name.equalsIgnoreCase(person.getName().trim());
// 01-04 19:41:01.360 30991-30991/old.pkg.com.myapplicati I/clp: p1 is equals =false
//
// return name.equalsIgnoreCase(person.getName());
// 01-04 19:41:48.420 32459-32459/old.pkg.com.myapplicati I/clp: p1 is equals =true
}
return super.equals(obj);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
Person p1 = new Person("張三 ");
Log.i("clp", "p1 is equals =" + p1.equals(p1));
使用:
return name.equalsIgnoreCase(person.getName().trim());
01-04 19:41:01.360 30991-30991/old.pkg.com.myapplicati I/clp: p1 is equals =false
return name.equalsIgnoreCase(person.getName());
01-04 19:41:48.420 32459-32459/old.pkg.com.myapplicati I/clp: p1 is equals =true
46.equals應(yīng)該考慮null值情景
接上面的例子,如果按照下面的方式判斷,,就會報錯
Person p1 = new Person("張三 ");
Person p2 = new Person(null);
Log.i("clp", "p1 p2 is equals =" + p2.equals(p1));
所以,,應(yīng)該按照下面的寫:
@Override
public boolean equals(Object obj) {
if (obj instanceof Person) {
Person person = (Person) obj;
if (person.getName() == null || name == null) {
return false;
}
//equalsIgnoreCase為忽略大小寫
return name.equalsIgnoreCase(person.getName());
// return name.equalsIgnoreCase(person.getName().trim());
// 01-04 19:41:01.360 30991-30991/old.pkg.com.myapplicati I/clp: p1 is equals =false
//
// return name.equalsIgnoreCase(person.getName());
// 01-04 19:41:48.420 32459-32459/old.pkg.com.myapplicati I/clp: p1 is equals =true
}
return super.equals(obj);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
47.在equals中使用getClass進行類型判斷
接上面例子,如果有一個子類,,代碼如下:
public class ManPerson extends Person {
public int id;
public ManPerson(String name, int id) {
this.name = name;
this.id = id;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ManPerson) {
ManPerson person = (ManPerson) obj;
return super.equals(obj) && person.id == id;
}
return super.equals(obj);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
然后進行判斷:
Person p1 = new Person("張三");
ManPerson manPerson = new ManPerson("張三", 100);
Log.i("clp", "p1 manPerson is equals =" + p1.equals(manPerson));
結(jié)果是true,。
這是因為p1為父類,所以使用了父類的equals方法進行判斷,。關(guān)鍵就是equals方法中使用了instanceof,。故修改如下:
@Override
public boolean equals(Object obj) {
if (obj.getClass() != null && obj.getClass() == this.getClass()) {
Person person = (Person) obj;
if (person.getName() == null || name == null) {
return false;
}
//equalsIgnoreCase為忽略大小寫
return name.equalsIgnoreCase(person.getName());
// return name.equalsIgnoreCase(person.getName().trim());
// 01-04 19:41:01.360 30991-30991/old.pkg.com.myapplicati I/clp: p1 is equals =false
//
// return name.equalsIgnoreCase(person.getName());
// 01-04 19:41:48.420 32459-32459/old.pkg.com.myapplicati I/clp: p1 is equals =true
}
return super.equals(obj);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
48.覆寫equals方法必須覆寫hashCode方法
Map<Person, Object> map = new HashMap<Person, Object>() {
{
put(new Person("張三"), new Object());
}
};
Log.i("clp", "map has key=" + map.containsKey(new Person("張三")));
上面方法,如果不覆寫hashCode,,會返回false,。
因為map是根據(jù)hashCode值決定數(shù)組的下標(HashMap底層是通過數(shù)組保存的)。如果不覆寫,,每一個對象都有一個hasCode,,自然會找不到
所以Person類中添加如下方法:
@Override
public int hashCode() {
return name.hashCode();
}
49.推薦覆寫toString()
原因是本身,此此方法返回的是對象引用的地址值,。
01-04 21:29:51.320 27893-27893/old.pkg.com.myapplicati I/clp: person =newpkg.pkg.com.myapplication2.algorithm.Person@bd2e9
Person person = new Person("張三");
Log.i("clp", "person =" + person.toString());
01-04 21:29:12.490 26591-26591/old.pkg.com.myapplicati I/clp: person =name =張三
50.使用package-info類為包服務(wù)
作用:
1.聲明友好類和包內(nèi)訪問常量
2.為在包上標注注解提供便利
3.提供包的整體注釋說明
51.不要主動進行垃圾回收
因為System.gc會停止所有的相應(yīng),,去進行檢測內(nèi)存中是否有可回收的對象??赡軙容^耗時,,10S或者20S也說不準。
字符串
52.推薦使用String直接量賦值
String s1 = "張三";
String s2 = " 張三 ";
String s3 = new String("張三");
String s4 = s3.intern();
Log.i("clp", " s1 s2 is equals=" + (s1 == s2));
Log.i("clp", " s1 s3 is equals=" + (s1 == s3));
Log.i("clp", " s1 s4 is equals=" + (s1 == s4));
01-04 21:51:49.220 19875-19875/old.pkg.com.myapplicati I/clp: s1 s2 is equals=false
01-04 21:51:49.220 19875-19875/old.pkg.com.myapplicati I/clp: s1 s3 is equals=false
01-04 21:51:49.220 19875-19875/old.pkg.com.myapplicati I/clp: s1 s4 is equals=true
Java為了避免產(chǎn)生大量的對象,,內(nèi)部有一個字符串池,。創(chuàng)建字符串時,會先判斷池子中是否有這個字符串,,有就直接返回,,
如果沒有,,就創(chuàng)建一個,丟到池子當中,,并返回,。
使用new 創(chuàng)建,肯定是新建了一個對象,。
intern方法會檢查當前的對象,,在池子中是否有字面值相等的引用對象,如果有就返回池子中的對象,,沒有就放置到池子中,,并返回。
會不會有線程安全問題?
String是一個不可變對象,。
1.不可能有子類
2.String中提供的方法中的返回值,,都會新建一個對象,不會對原對象進行修改,。
要不要考慮垃圾回收?
字符串池,,是保存子JVM的常量池當中,不會進行垃圾回收,。
53.注意參數(shù)中傳遞的參數(shù)要求
//刪除字符串
public static String remove(String orgin, String sub) {
return orgin.replaceAll(sub, "");
}
Log.i("clp", "result =" + CldStringUtil.remove("好是好", "好"));
Log.i("clp", "result =" + CldStringUtil.remove("$是$", "$"));
結(jié)果:
01-04 22:08:33.220 6359-6359/old.pkg.com.myapplicati I/clp: result =是
01-04 22:08:33.220 6359-6359/old.pkg.com.myapplicati I/clp: result =是
replaceAll要求第一個參數(shù)是正則表達式,。$這個符號在正則表達式中是字符串的結(jié)束位置。
修改如下:
//刪除字符串
public static String remove(String orgin, String sub) {
while (orgin.contains(sub)) {
orgin = orgin.replace(sub, "");
}
return orgin;
}
54.正確使用String,、StringBuffer,、StringBuilder
1.String一旦創(chuàng)建,不可變
2.StringBuffer是線程安全的,,StringBuilder是線程不安全的,。
所以StringBuffer的性能要比StringBuilder低。
3.性能方法,,因為String每次都會新建,,所以會遠慢于StringBuffer和StringBuilder
55.注意字符串的位置
String s1 = 1 + 2 + "abc";
String s2 = "abc" + 1 + 2;
Log.i("clp", "s1=" + s1);
Log.i("clp", "s2=" + s2);
01-05 06:40:30.540 28819-28819/old.pkg.com.myapplicati I/clp: s1=3abc
01-05 06:40:30.540 28819-28819/old.pkg.com.myapplicati I/clp: s2=abc12
1.從左到右依次拼接
2.只要遇到String,則所有數(shù)據(jù)都轉(zhuǎn)換為String類進行拼接
3.如果是原始數(shù)據(jù),,則直接進行拼接,,如果是對象,則調(diào)用toString()
4.在+表達式中,,String具有最高的優(yōu)先級
56.自由選擇字符串拼接方法
String s = "";
long time = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
s += "a";
}
long timeend = System.currentTimeMillis() - time;
Log.i("clp", "time1 =" + timeend);
String a = "";
long time2 = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
s = s.concat("a");
}
long timeend2 = System.currentTimeMillis() - time2;
Log.i("clp", "time1 =" + timeend2);
StringBuilder b = new StringBuilder();
long time3 = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
b.append("a");
}
long timeend3 = System.currentTimeMillis() - time3;
Log.i("clp", "time1 =" + timeend3);
StringBuffer c = new StringBuffer();
long time4 = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
c.append("a");
}
long timeend4 = System.currentTimeMillis() - time4;
Log.i("clp", "time1 =" + timeend4);
01-05 06:53:02.410 3080-3080/old.pkg.com.myapplicati I/clp: time1 =1160
01-05 06:53:04.070 3080-3080/old.pkg.com.myapplicati I/clp: time1 =1668
01-05 06:53:04.080 3080-3080/old.pkg.com.myapplicati I/clp: time1 =5
01-05 06:53:04.090 3080-3080/old.pkg.com.myapplicati I/clp: time1 =8
書上說concat執(zhí)行時間比直接添加少一倍,。但是在我手機上測試為啥還要高???
57.推薦在復(fù)雜字符串操作中使用正則表達式
//使用正則表達式計算單詞的數(shù)量
public static int getCount(String word) {
//正在表達式
Pattern pattern = Pattern.compile("\\b\\w+\\b");
Matcher matcher = pattern.matcher(word);
int count = 0;
while (matcher.find()) {
count++;
}
return count;
}
String s = "How are you !Good!";
Log.i("clp", "count=" + CldStringUtil.getCount(s));
01-05 07:10:17.220 8910-8910/old.pkg.com.myapplicati I/clp: count=4
58.強烈建議使用UTF編碼
文件格式為UTF-8
try {
String s = "張三";
byte[] b = s.getBytes("GBK");
Log.i("clp", "string is =" + new String(b));
Log.i("clp", "string is =" + new String(b, "GBK"));
} catch (Exception e) {
}
輸出結(jié)果:
01-05 07:20:10.370 11249-11249/old.pkg.com.myapplicati I/clp: string is =????
01-05 07:20:10.370 11249-11249/old.pkg.com.myapplicati I/clp: string is =張三
59.對字符串排序持一種寬容的態(tài)度
1.使用Arrays.sort肯定不行,它是根據(jù)UNICODE代碼表來排序的,。
2.使用Collator,,但是只能包含常用的7000多個漢字。
String[] sortName = {"張三", "李四", "王五"};
Comparator c = Collator.getInstance(Locale.CHINA);
Arrays.sort(sortName, c);
for (String str : sortName) {
Log.i("clp", "name =" + str);
}
原因:java使用UNICODE編碼。
GB2312->GB18030->UNICODE
數(shù)組和集合
60.性能考慮,,數(shù)組是首選
//基本類型是在棧內(nèi)操作的,。而對象是在堆內(nèi)操作的。
//棧的特點是:速度快,、容量小 堆的特點是:速度慢,,容量大。
public static int getCountArray(int[] list) {
int sum = 0;
long time = System.currentTimeMillis();
for (int i = 0; i < list.length; i++) {
sum += list[i];
}
long timeend = System.currentTimeMillis() - time;
Log.i("clp", "array time is =" + timeend);
return sum;
}
public static int getCountList(List<Integer> list) {
int sum = 0;
long time = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {
sum += list.get(i);//做了一次拆箱操作,。Integer通過intValue方法自動轉(zhuǎn)換為了int基本類型
}
long timeend = System.currentTimeMillis() - time;
Log.i("clp", "data time is =" + timeend);
return sum;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
int[] data = new int[100000];
for (int i = 0; i < data.length; i++) {
data[i] = 2;
}
CldArrayUtil.getCountArray(data);
List<Integer> list = new ArrayList<Integer>();
for (int j = 0; j < 100000; j++) {
list.add(2);
}
CldArrayUtil.getCountList(list);
01-05 08:13:19.740 21326-21326/old.pkg.com.myapplicati I/clp: array time is =4
01-05 08:13:19.880 21326-21326/old.pkg.com.myapplicati I/clp: data time is =35
數(shù)組的效率是集合的10倍,。這個說法是對的。
61.若有必要,,使用變長數(shù)組
public static int[] expandArray(int[] data, int length) {//指定新的數(shù)組長度
if (length < 0) {
length = 0;
}
return Arrays.copyOf(data, length);
}
int[] data = new int[20];
for (int i = 0; i < data.length; i++) {
data[i] = 2;
}
data = CldArrayUtil.expandArray(data, 50);
Log.i("clp", "length =" + data.length);
Log.i("clp", "data[2]=" + data[2]);
01-05 08:26:57.310 23679-23679/old.pkg.com.myapplicati I/clp: length =50
01-05 08:26:57.310 23679-23679/old.pkg.com.myapplicati I/clp: data[2]=2
62.警惕數(shù)組的淺拷貝
Arrays.copyOf為數(shù)組的淺拷貝,,如果是基本類型,直接拷貝值,。如果是對象,,拷貝的是引用地址。
所以如果改變拷貝后的對象的值,,拷貝前的值也會發(fā)生變化。
解決方式:重新生成對象,。
63.在明確的場景下,,為集合指定初始容量
1.例如ArrayList,如果不指定,,初始容量為10.每次如果長度不夠,,就自動擴容到1.5倍。
所以,,如果要指定一個長度為50的List,,最好直接指定容量
List<String> mlist = new ArrayList<>(50);
for (int i = 0; i < 60; i++) {//列表長度為50,添加60個元素
mlist.add("2");
}
Log.i("clp", "list size =" + mlist.size());
01-05 19:23:08.320 4367-4367/old.pkg.com.myapplicati I/clp: list size =60
Vector,、HashMap,、Stack類似。
64.多種最值算法,,適時選擇
int[] data = new int[100000];
for (int i = 0; i < data.length; i++) {
data[i] = new Random().nextInt(10000);
}
//使用數(shù)組排序
int max = data[0];
long time = System.currentTimeMillis();
for (int i : data) {
max = max > data[i] ? max : data[i];
}
long timeEnd = System.currentTimeMillis() - time;
Log.i("clp", "timeEnd=" + timeEnd);
Log.i("clp", "max data = " + max);
01-05 19:35:47.690 8007-8007/old.pkg.com.myapplicati I/clp: timeEnd=6
01-05 19:35:47.690 8007-8007/old.pkg.com.myapplicati I/clp: max data = 9999
int[] data = new int[100000];
for (int i = 0; i < data.length; i++) {
data[i] = new Random().nextInt(10000);
}
//使用Arrays排序
int max = data[0];
long time = System.currentTimeMillis();
Arrays.sort(data.clone());
long timeEnd = System.currentTimeMillis() - time;
Log.i("clp", "timeEnd=" + timeEnd);
Log.i("clp", "max data = " + data[data.length - 1]);
01-05 19:37:36.810 9440-9440/old.pkg.com.myapplicati I/clp: timeEnd=172
01-05 19:37:36.810 9440-9440/old.pkg.com.myapplicati I/clp: max data = 9281
排序10萬個數(shù)據(jù),,才有細微的差別。所以,,小數(shù)據(jù)性能影響不大,。用Arrays.sort排序代碼可讀性高一點。
求第二大元素,正常通過數(shù)據(jù)循環(huán)查找可以搞定,,下面使用TreeSet實現(xiàn)(過濾掉相同數(shù)據(jù)).
long time = System.currentTimeMillis();
List<Integer> mList = Arrays.asList(data);
TreeSet<Integer> ts = new TreeSet<Integer>(mList);
int max = ts.lower(ts.last());
long timeEnd = System.currentTimeMillis() - time;
Log.i("clp", "timeEnd=" + timeEnd);
Log.i("clp", "sec max data = " + max);
01-05 19:42:18.750 10551-10551/old.pkg.com.myapplicati I/clp: timeEnd=1092
01-05 19:42:18.750 10551-10551/old.pkg.com.myapplicati I/clp: sec max data = 9998
65.避開基本類型數(shù)組轉(zhuǎn)換列表陷進
int[] data = new int[100000];
for (int i = 0; i < data.length; i++) {
data[i] = new Random().nextInt(10000);
}
List mList = Arrays.asList(data);
Log.i("clp", "list size =" + mList.size());
01-05 19:50:27.710 13585-13585/old.pkg.com.myapplicati I/clp: list size =1
asList需要輸入一個泛型化的邊長參數(shù),,基本類型是不能泛型化的,但是數(shù)組可以。所以上面就把數(shù)組泛型化為只有一個數(shù)組的,。
mList.get(0)數(shù)據(jù)如下:
其他7個基本類型也有這個問題,,所以如果要用,請使用包裝類型,。
66.asList方法產(chǎn)生的List對象不可更改
Integer[] data = new Integer[5];
for (int i = 0; i < 5; i++) {
data[i] = new Random().nextInt(10);
}
List<Integer> mList = Arrays.asList(data);
mList.add(2);
java.lang.RuntimeException: Unable to start activity ComponentInfo
{old.pkg.com.myapplicati/newpkg.pkg.com.myapplication2.MainActivity}: java.lang.UnsupportedOperationException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2279)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2329)
at android.app.ActivityThread.access$1100(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1242)
因為通過asList產(chǎn)生的List不同于正常使用的List,,不能使用add remove方法。
只有size toArray get set contains五個方法可以用,。
List mList = Arrays.asList(1, 2, 3);這種方式生成數(shù)組有巨大的隱患,。
67.不同的列表選擇不同的遍歷方法
new Thread(new Runnable() {
@Override
public void run() {
List<Integer> mList = new ArrayList<>();
for (int i = 0; i < 80 * 100; i++) {
mList.add(new Random().nextInt(200));
}
long start = System.currentTimeMillis();
int average = CldArrayUtil.average(mList);
Log.i("clp", "time =" + (System.currentTimeMillis() - start) + "ms");
Log.i("clp", "average=" + average);
List<Integer> mList2 = new LinkedList<>();
for (int i = 0; i < 80 * 100; i++) {
mList2.add(new Random().nextInt(200));
}
long start2 = System.currentTimeMillis();
int average2 = CldArrayUtil.average(mList2);
Log.i("clp", "time2 =" + (System.currentTimeMillis() - start2) + "ms");
Log.i("clp", "average2=" + average2);
}
}).start();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
使用fori循環(huán)
//求平局數(shù)
public static int average(List<Integer> list) {
int sum = 0;
for (int i = 0; i < list.size(); i++) {
sum += list.get(i);
}
return sum / list.size();
}
01-05 21:07:22.310 2140-2188/old.pkg.com.myapplicati I/clp: time =8ms
01-05 21:07:22.310 2140-2188/old.pkg.com.myapplicati I/clp: average=98
01-05 21:07:23.280 2140-2188/old.pkg.com.myapplicati I/clp: time2 =929ms
01-05 21:07:23.280 2140-2188/old.pkg.com.myapplicati I/clp: average2=98
8000個就是快1S,80萬個就是100S!!!!
//求平局數(shù)
public static int average(List<Integer> list) {
int sum = 0;
// for (int i = 0; i < list.size(); i++) {
// sum += list.get(i);
// }
for (Integer i : list) {
sum += i;
}
return sum / list.size();
}
01-05 21:09:06.990 3137-3185/old.pkg.com.myapplicati I/clp: time =5ms
01-05 21:09:06.990 3137-3185/old.pkg.com.myapplicati I/clp: average=99
01-05 21:09:07.030 3137-3185/old.pkg.com.myapplicati I/clp: time2 =9ms
01-05 21:09:07.030 3137-3185/old.pkg.com.myapplicati I/clp: average2=98
在手機上測試,使用foreach方法,,消耗的時間差不多???
ArrayList實現(xiàn)了隨機讀取(RandomAcess),,而LinkedList實現(xiàn)了迭代器。
書上建議通過判斷是否有RandomAcess
//求平局數(shù)
public static int average(List<Integer> list) {
int sum = 0;
if (list instanceof RandomAccess) {//針對ArrayList可以隨機讀取的
for (int i = 0; i < list.size(); i++) {
sum += list.get(i);
}
} else {//針對LinkedList這種
for (Integer i : list) {
sum += i;
}
}
return sum / list.size();
}
01-05 21:11:53.070 4250-4304/old.pkg.com.myapplicati I/clp: time =4ms
01-05 21:11:53.070 4250-4304/old.pkg.com.myapplicati I/clp: average=98
01-05 21:11:53.130 4250-4304/old.pkg.com.myapplicati I/clp: time2 =12ms
01-05 21:11:53.130 4250-4304/old.pkg.com.myapplicati I/clp: average2=98
68.頻繁插入和刪除時用LinkedList
ArrayList和LinkedList性能比較
添加:
new Thread(new Runnable() {
@Override
public void run() {
List<String> mArrayList = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
mArrayList.add("a");
}
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
mArrayList.add(2, "a");
}
Log.i("clp", "array list time =" + (System.currentTimeMillis() - start) + "ms");
List<String> mLinkedList = new LinkedList<String>();
for (int i = 0; i < 10; i++) {
mLinkedList.add("a");
}
long start2 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
mLinkedList.add(2, "a");
}
Log.i("clp", "linked list time =" + (System.currentTimeMillis() - start2) + "ms");
}
}).start();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
01-05 21:34:13.060 10127-10170/old.pkg.com.myapplicati I/clp: array list time =15847ms
01-05 21:34:13.170 10127-10170/old.pkg.com.myapplicati I/clp: linked list time =116ms
10萬個數(shù)據(jù)的話,,相差100倍,。
刪除:
new Thread(new Runnable() {
@Override
public void run() {
List<String> mArrayList = new ArrayList<String>();
for (int i = 0; i < 10 * 10000; i++) {
mArrayList.add("a");
}
long start = System.currentTimeMillis();
while (mArrayList.size() > 0){
mArrayList.remove(0);
}
Log.i("clp", "array list time =" + (System.currentTimeMillis() - start) + "ms");
List<String> mLinkedList = new LinkedList<String>();
for (int i = 0; i < 10 * 10000; i++) {
mLinkedList.add("a");
}
long start2 = System.currentTimeMillis();
while (mLinkedList.size() > 0) {
mLinkedList.remove(0);
}
Log.i("clp", "linked list time =" + (System.currentTimeMillis() - start2) + "ms");
}
}).start();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
01-05 21:37:58.600 11330-11372/old.pkg.com.myapplicati I/clp: array list time =15108ms
01-05 21:37:58.700 11330-11372/old.pkg.com.myapplicati I/clp: linked list time =13ms
刪除,性能相差1000倍,。
修改:
new Thread(new Runnable() {
@Override
public void run() {
List<String> mArrayList = new ArrayList<String>();
for (int i = 0; i < 10 * 10000; i++) {
mArrayList.add("a");
}
long start = System.currentTimeMillis();
for (int i = 0; i < 10 * 10000; i++) {
mArrayList.set(10000, "b");
}
Log.i("clp", "array list time =" + (System.currentTimeMillis() - start) + "ms");
List<String> mLinkedList = new LinkedList<String>();
for (int i = 0; i < 10 * 10000; i++) {
mLinkedList.add("a");
}
long start2 = System.currentTimeMillis();
for (int i = 0; i < 10 * 10000; i++) {
mLinkedList.set(10000, "b");
}
Log.i("clp", "linked list time =" + (System.currentTimeMillis() - start2) + "ms");
}
}).start();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
01-05 21:40:26.700 12467-12523/old.pkg.com.myapplicati I/clp: array list time =28ms
01-05 21:40:55.580 12467-12523/old.pkg.com.myapplicati I/clp: linked list time =28672ms
總結(jié):頻繁的刪除和插入,,使用LinkedList。 如果頻繁的獲取和修改,。使用ArrayList
69.列表相等只需關(guān)系元素數(shù)據(jù)
判斷集合是否相等時,,只需要判斷元素是否相等即可。
ArrayList<String> mList = new ArrayList<String>();
mList.add("a");
Vector<String> mVList = new Vector<String>();
mVList.add("a");
Log.i("clp", "is equals =" + mList.equals(mVList));
01-06 06:56:50.610 25692-25692/old.pkg.com.myapplicati I/clp: is equals =true
equals是在AbstractList中實現(xiàn)的,,代碼如下:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator e2 = ((List) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
70.子列表只是原列表的一個視圖
List<String> mlist = new ArrayList<String>();
mlist.add("A");
mlist.add("B");
ArrayList<String> mBList = new ArrayList<>(mlist);
List<String> mCList = mlist.subList(0, mlist.size());
mCList.add("C");
Log.i("clp", "mlist mBlist is equals =" + mlist.equals(mBList));
Log.i("clp", "mlist mCList is equals =" + mlist.equals(mCList));
01-06 07:18:39.990 29976-29976/old.pkg.com.myapplicati I/clp: mlist mBlist is equals =false
01-06 07:18:39.990 29976-29976/old.pkg.com.myapplicati I/clp: mlist mCList is equals =true
subList是在原數(shù)組上進行操作,。
71.推薦使用subList處理局部列表
List<String> mList = new ArrayList<String>();
for (int i = 0; i < 100; i++) {
mList.add("a");
}
//刪除第20~30之間的元素
mList.subList(20, 30).clear();
Log.i("clp", "mList size =" + mList.size());
01-06 07:28:51.470 32234-32234/old.pkg.com.myapplicati I/clp: mList size =90
72.生成子列表之后不要再操作原列表
List<String> mList = new ArrayList<String>();
for (int i = 0; i < 100; i++) {
mList.add("a");
}
List<String> mSubList = mList.subList(20, 30);
mList.add("d");
Log.i("clp", "mlist size =" + mList.size());
Log.i("clp", "mSubList size =" + mSubList.size());
java.lang.RuntimeException: Unable to start activity ComponentInfo
{old.pkg.com.myapplicati/newpkg.pkg.com.myapplication2.MainActivity}:
java.util.ConcurrentModificationException
操作子列表也有可能導(dǎo)致報錯,如下:
List<String> mList = new ArrayList<String>();
for (int i = 0; i < 100; i++) {
mList.add("a");
}
List<String> mSubList = mList.subList(20, 30);
List<String> mSubList2 = mList.subList(10, 30);
mSubList.add("d");
// mSubList2.add("e");
Log.i("clp", "mlist size =" + mList.size());
Log.i("clp", "mSubList size =" + mSubList.size());
Log.i("clp", "mSubList2 size =" + mSubList2.size());
73.使用Comparator進行排序
public class Person implements Comparable<Person> {
public int id;
public String name;
public Person(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public int compareTo(Person person) {
if (person == null) {
return -1;
}
return Integer.valueOf(id).compareTo(Integer.valueOf(person.id));
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
List<Person> mList = new ArrayList<Person>();
mList.add(new Person(2, "張二"));
mList.add(new Person(1, "張一"));
mList.add(new Person(4, "張四"));
mList.add(new Person(3, "張三"));
Collections.sort(mList);
for (int i = 0; i < mList.size(); i++) {
Log.i("clp", "index =" + i + ";name =" + mList.get(i).name);
}
使用Comparator可以拓展排序,。
List<Person> mList = new ArrayList<Person>();
mList.add(new Person(2, 440300, "張二"));
mList.add(new Person(1, 440322, "張一"));
mList.add(new Person(4, 440310, "張四"));
mList.add(new Person(3, 440200, "張三"));
mList.add(new Person(6, 440200, "張六"));
mList.add(new Person(5, 440200, "張五"));
Collections.sort(mList, new PerComparator());
for (int i = 0; i < mList.size(); i++) {
Log.i("clp", "index =" + i + ";cityId=" + mList.get(i).cityId + ";name =" + mList.get(i).name);
}
//先按照cityId進行排序,,如果相等,就按照id排序
public class PerComparator implements Comparator<Person> {
@Override
public int compare(Person person, Person t1) {
if (person.cityId > t1.cityId) {//1的畫,,是排后面
return 1;
} else if (person.cityId == t1.cityId) {//如果城市相等,,按照id排序
if (person.id > t1.id) {
return 1;
} else if (person.id == t1.id) {
return 0;
} else {
return -1;
}
} else {
return -1;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
如果想實現(xiàn)倒序,直接使用:
Collections.sort(mList, Collections.reverseOrder(new PerComparator()));
Collections.reverse(mList);---對排序之后的,,進行倒序
Comparable實現(xiàn)默認排序,。Comparator可以實現(xiàn)拓展排序。
74.不推薦使用binarySearch對列表進行檢索
1.indexOf是通過for循環(huán)進行排序查找第一個符合條件的
2.binarySearch是通過二分查找,,但是前提也是必須先排序
所以,,如果已經(jīng)排序的,使用binarySearch性能會高很多,。
75.集合中的元素必須做到compartTo和equals同步
public class Person implements Comparable<Person> {
public int id;
public String name;
public Person(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public int compareTo(Person person) {
if (person == null) {
return -1;
}
return person.name.compareTo(this.name);
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o == this) {
return true;
}
if (this.getClass() != o.getClass()) {
return false;
}
Person p = (Person) o;
return Integer.valueOf(id).compareTo(Integer.valueOf(p.id)) == 0;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
List<Person> mList = new ArrayList<Person>();
mList.add(new Person(1, "張二"));
mList.add(new Person(1, "張一"));
Person p = new Person(1, "張一");
int index1 = mList.indexOf(p);
int index2 = Collections.binarySearch(mList, p);
Log.i("clp", "index1=" + index1);
Log.i("clp", "index2=" + index2);
04-18 11:51:12.192 12423-12423/com.example.demo I/clp: index1=0
04-18 11:51:12.192 12423-12423/com.example.demo I/clp: index2=1
indexOf是通過對象中的equals來判斷是否相等,,
binarySearch是通過compartTo來判斷是否相等,。所以2個方法應(yīng)該同步。
76.集合運算中使用更優(yōu)雅的方式
List<String> mList1 = new ArrayList<String>();
mList1.add("a");
mList1.add("b");
List<String> mList2 = new ArrayList<String>();
mList2.add("a");
mList2.add("c");
//并集
// mList1.addAll(mList2);
// Log.i("clp", "并集 size=" + mList1.size());
// //04-18 12:07:46.552 12423-12423/com.example.demo I/clp: 并集 size=4
//交集
// mList1.retainAll(mList2);
// Log.i("clp", "交集 size=" + mList1.size());
//04-18 12:08:55.022 12423-12423/com.example.demo I/clp: 交集 size=1
//差集
// mList1.removeAll(mList2);
// Log.i("clp", "差集 size=" + mList1.size());
//04-18 12:09:44.782 12423-12423/com.example.demo I/clp: 差集 size=1
//無重復(fù)的并集
mList2.removeAll(mList1);
mList1.addAll(mList2);
Log.i("clp", "無重復(fù)的并集 size=" + mList1.size());
// 04-18 12:10:34.862 12423-12423/com.example.demo I/clp: 無重復(fù)的并集 size=3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
無重復(fù)的并集,,不能使用HashSet,,因為會把本來重復(fù)的元素合并掉。
77.使用shuffle打亂列表
int count = 10;
List<String> mList = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
mList.add(i + "");
}
// for (int i = 0; i < 10; i++) {
// int random = new Random().nextInt(10);
// Collections.swap(mList, i, random);
// }
Collections.shuffle(mList);//打亂順序
for (int i = 0; i < 10; i++) {
Log.i("clp", "value" + mList.get(i));
}
78.減少HashMap中元素的數(shù)量
1.比ArrayList多了Entry對象,,如果有40萬個數(shù)據(jù),,就是多了40萬個對象
2.擴容機制不一樣,HashMap是2倍擴容,,ArrayList是1.5倍
3.HashMap有一個加載因子,,意思是到達容量的0.75就開始擴容了
所以大量數(shù)據(jù)的時候,HashMap比ArrayList先內(nèi)存溢出,。
79.集合中的哈希碼盡量不要重復(fù)
HashMap是通過哈希值,,實現(xiàn)比ArrayList快速的查找,如果哈希碼是一樣的,,性能就和鏈表的性能是一樣的,。
80.多線程使用Vector和HashTable
final Vector<String> mVList = new Vector<String>();
for (int i = 0; i < 10000; i++) {
mVList.add("火車票" + i);
}
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
String mR = mVList.remove(0);
Log.i("clp", "cur thread id=" + Thread.currentThread().getId() + ";remove =" + mR);
}
}
}).start();
}
多個線程同步,但是不能實現(xiàn),,一個線程讀的時候,,另一個線程在寫。
81.非穩(wěn)定序列推薦使用List
SortedSet<Person> sortSet = new TreeSet<Person>();
sortSet.add(new Person(15, "張三"));
sortSet.add(new Person(10, "張四"));
for (Person per : sortSet) {
Log.i("clp", "id=" + per.id + ";name=" + per.name);
}
04-18 15:44:55.202 31018-31018/com.example.demo I/clp: id=10;name=張四
04-18 15:44:55.202 31018-31018/com.example.demo I/clp: id=15;name=張三
SortedSet<Person> sortSet = new TreeSet<Person>();
sortSet.add(new Person(15, "張三"));
sortSet.add(new Person(10, "張四"));
sortSet.first().id = 20;
for (Person per : sortSet) {
Log.i("clp", "id=" + per.id + ";name=" + per.name);
}
04-18 15:45:49.532 31018-31018/com.example.demo I/clp: id=20;name=張四
04-18 15:45:49.532 31018-31018/com.example.demo I/clp: id=15;name=張三
SortedSet只有在插入的時候,,進行排序,。
sortSet = new TreeSet<Person>(new ArrayList<Person>(sortSet));
可以通過new 重新構(gòu)建。
基本類型,,建議使用SortedSet,如果是自己創(chuàng)建的對象,,可以使用Colletions.sort
82.集合大家族
一,、List
實現(xiàn)List的接口主要有:ArrayList-動態(tài)數(shù)組 LinkedList-雙向鏈表 Vector-線程安全的動態(tài)數(shù)組 Stack-對象棧,先進后出
二,、Set-不包含重復(fù)元素的集合:
EnumSet-枚舉類型的專用Set,,所有的元素都是枚舉類型
HashSet-以哈希碼決定元素位置的Set,與HashMap類似,,提供快速的插入和查找
TreeSet-自動排序的Set,,實現(xiàn)了SortedSet接口
三、Map-分為排序的Map和非排序Map
TreeMap-根據(jù)Key值自動排序
HashMap
HashTable
Properties:HashTable的子類,,主要從Property文件中加載數(shù)據(jù),,并提供方便的讀寫。
EnumMap
WeakHashMap:可以被垃圾回收的HashMap
四,、Queue隊列-分為阻塞和非阻塞隊列
五,、數(shù)組
所有的集合底層存儲的都是數(shù)組,,數(shù)據(jù)可以存儲基本類型,集合不行,。
六,、工具類
數(shù)組的工具類:Array和Arrays
集合的工具類:Collections
如果需要精確排序,則需要使用開源項目,。如pinyin4j,。
枚舉和注解
83.推薦使用枚舉定義常亮
public enum SeaSon {
Sping, Summer, Autumn, Winner;
public static SeaSon getCommonSeason() {
return Sping;
}
}
for (SeaSon s : SeaSon.values()) {
Log.i("clp", "s values =" + s);
}
Log.i("clp", "common =" + SeaSon.getCommonSeason());
04-19 10:26:24.608 14196-14196/com.example.demo I/clp: s values =Sping
04-19 10:26:24.608 14196-14196/com.example.demo I/clp: s values =Summer
04-19 10:26:24.608 14196-14196/com.example.demo I/clp: s values =Autumn
04-19 10:26:24.608 14196-14196/com.example.demo I/clp: s values =Winner
04-19 10:26:24.608 14196-14196/com.example.demo I/clp: common =Sping
84.使用構(gòu)造函數(shù)協(xié)助描述枚舉項
public enum SeaSon {
Sping("春"), Summer("夏"), Autumn("秋"), Winner("冬");
private String desc;
SeaSon(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
public static SeaSon getCommonSeason() {
return Sping;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
for (SeaSon s : SeaSon.values()) {
Log.i("clp", "s values =" + s.getDesc());
}
Log.i("clp", "common =" + SeaSon.getCommonSeason());
構(gòu)造函數(shù)還可以比這個更復(fù)雜,傳遞對象等,。
85.小心switch帶來的空值異常
public void doSwSeaSon(SeaSon seaSon) {
switch (seaSon) {
case Sping:
Log.i("clp", "Sping");
break;
default:
Log.i("clp", "其他類型");
break;
}
}
doSwSeaSon(null);
java.lang.NullPointerException: Attempt to invoke virtual method ‘int com.cp.demo.java.SeaSon.ordinal()’ on a null object reference
case的其實是:SeaSon.Sping.ordinal(),所以要做對象的空值判斷,。
86.在switch的default代碼塊中增加AssertionError錯誤
因為枚舉類型和case沒有強制關(guān)系,如果后續(xù)增加了一個,,沒有case,,就會導(dǎo)致switch漏掉這個枚舉項。
87.枚舉使用valueOf前必須進行校驗
否則會拋出異常
List<String> mList = Arrays.asList("Sping", "sss");
for (int i = 0; i < mList.size(); i++) {
SeaSon sea = SeaSon.valueOf(mList.get(i));
if (sea == null) {
Log.i("clp", "沒有此枚舉值");
} else {
Log.i("clp", "有值");
}
}
java.lang.IllegalArgumentException: sss is not a constant in com.cp.demo.java.SeaSon
兩種方案:
1.捕獲異常
List<String> mList = Arrays.asList("Sping", "sss");
for (int i = 0; i < mList.size(); i++) {
try {
SeaSon sea = SeaSon.valueOf(mList.get(i));
Log.i("clp", "有值");
} catch (IllegalArgumentException e) {
Log.i("clp", "沒有此枚舉值");
}
}
04-19 11:35:20.148 13538-13538/com.example.demo I/clp: 有值
04-19 11:35:20.148 13538-13538/com.example.demo I/clp: 沒有此枚舉值
2.拓展枚舉類
public static boolean contains(String name) {
for (SeaSon sen : values()) {
if (sen.name().equals(name)) {
return true;
}
}
return false;
}
List<String> mList = Arrays.asList("Sping", "sss");
for (int i = 0; i < mList.size(); i++) {
boolean sea = SeaSon.contains(mList.get(i));
if (sea) {
Log.i("clp", "有值");
} else {
Log.i("clp", "沒有此枚舉值");
}
}
88.用枚舉實現(xiàn)工廠方法模式更簡潔
1.非靜態(tài)方法實現(xiàn),。
public interface Car {
public void drive();
}
public class FortCar implements Car {
@Override
public void drive() {
Log.i("clp", "fort drive");
}
}
public class BuickCar implements Car {
@Override
public void drive() {
Log.i("clp", "buick drive");
}
}
public enum CarFactory {
FortCar, BuickCar;
public Car create() {
switch (this) {
case FortCar:
return new FortCar();
case BuickCar:
return new BuickCar();
default:
Log.i("clp", "無效參數(shù)");
}
return null;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
04-19 11:55:34.988 1940-1940/com.example.demo I/clp: fort drive
2.通過抽象方法生成
public enum CarFactory {
FortCar {
@Override
public Car create() {
return new FortCar();
}
}, BuickCar {
@Override
public Car create() {
return new BuickCar();
}
};
public abstract Car create();
}
89.枚舉項的數(shù)量限制的64個以內(nèi)
long e = -1L >>> -65;//value=1
long e = -1L >>> -1;//value=1
long e = -1L >>> 63;//value=1
long e = -1L >>> 1;//9223372036854775807
long e = -1L >>> 62;//value=3
int e = -1 >>> 31;//value=1
int e = -1 >>> 1;//2147483647
小于等于64和大于64處理的機制是不一樣的,。
Enum[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
RegularEnumSet:
void addAll() {
if (universe.length != 0)
elements = -1L >>> -universe.length;
}
JumboEnumSet:
void addAll() {
for (int i = 0; i < elements.length; i++)
elements[i] = -1;
elements[elements.length - 1] >>>= -universe.length;
size = universe.length;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
所以內(nèi)部是以64位拆分進行分組。
90.小心注解繼承
91.枚舉和注解結(jié)合使用威力很大
92.注意@Overrig不同版本的區(qū)別
如果是Java1.6版本的程序移植到1.5版本環(huán)境中,,就需要刪除實現(xiàn)接口方法上的@Override注解
泛型和反射
93.Java的泛型是類型擦除的
java的編譯期和運行期解讀:
http://bbzoh.cn/content/14/0218/23/9440338_353675002.shtml
編譯期:源碼->class文件的過程
運行期:在JVM中運行的過程
public void initList(List<Integer> mList) {
}
public void initList(List<String> mList) {
}
按照上面這種方式寫,,報錯。
initList(List)’ clashes with ‘initList(List)’; both methods have same erasure
List<String> mList = new ArrayList<String>();
List<Integer> mIList = new ArrayList<Integer>();
Log.i("clp", "is equals=" + (mList.getClass() == mIList.getClass()));
04-25 15:49:13.356 2760-2760/old.pkg.com.myapplicati I/clp: is equals=true
他們擦除后的類型都是List
Java泛型-類型擦除:
http://blog.csdn.net/caihaijiang/article/details/6403349
94.不能初始化泛型參數(shù)和數(shù)組
T t = new T();//報錯
T[] mTArray = new T[];//報錯
List<T> mList = new ArrayList<T>();//報錯
以上3個寫法,,在AS上面都報錯,,需要在運行期指定T類型。
95.強制聲明泛型的實際類型
List<Integer> mList = CldCalMiniUtil.asList();//正確
List<Integer> mList = CldCalMiniUtil.<Integer>asList();//正確
List<Number> mList2 = CldCalMiniUtil.asList(1, 2.2);//報錯
List<Number> mList2 = CldCalMiniUtil.<Number>asList(1, 2.2);//正確--這里使用了強制聲明
|