java筆記2

java集合中ArrayList與LinkedList比較
作者 codercjg9 一月 2015, 11:20 下午

ArrayList和LinkedList共同點:都實現了List接口,用來表示動態數組的功能,都是線程不安全的。
不同點:1)實現方式不同,ArrayList內部用數組實現,LinkedList用鏈表實現。所以表中間插入元素時ArrayList需要移動元素,而LinkedList不需要。2)應用場景不同,ArrayList適合隨機查找,而LinkedList適合經常需要插入和刪除元素的場景。3)LinkedList比ArrayList多了addFirst(),addLast()方法4)ArrayList支持隨機查找,LinkedList不支持
下面通過一個例子來比較兩種實現方式的插入和遍歷所需要的時間:
import
java.util.ArrayList;

import
java.util.Iterator;

import
java.util.LinkedList;

public
class
ListSample {

public
static
void
main(String[] args) {

int
circle =
200000
;

ArrayList<String> arrayList =
new
ArrayList<String>(circle);

LinkedList<String> linkedList =
new
LinkedList<String>();

System.out.println(
"比較插入在頭部元素的時間:"
);

long
time = System.currentTimeMillis();

for
(
int
i =
0
; i < circle; i++) {

arrayList.add(
0
, String.valueOf(i));

}

System.out.println(
"ArrayList:"

  • (System.currentTimeMillis() - time));

time = System.currentTimeMillis();

for
(
int
i =
0
; i < circle; i++) {

linkedList.addFirst(String.valueOf(i));

}

System.out.println(
"LinkedList:"

  • (System.currentTimeMillis() - time));

System.out.println();

System.out.println(
"比較for循環方式遍歷的時間:"
);

time = System.currentTimeMillis();

for
(
int
i =
0
; i < circle; i++) {

arrayList.get(i);

}

System.out.println(
"ArrayList:"

  • (System.currentTimeMillis() - time));

time = System.currentTimeMillis();

for
(
int
i =
0
; i < circle; i++) {

linkedList.get(i);

}

System.out.println(
"LinkedList:"

  • (System.currentTimeMillis() - time));

System.out.println();

System.out.println(
"比較foreach方式遍歷的時間:"
);

time = System.currentTimeMillis();

for
(String str: arrayList){

}

System.out.println(
"ArrayList:"

  • (System.currentTimeMillis() - time));

time = System.currentTimeMillis();

for
(String str: linkedList){

}

System.out.println(
"LinkedList:"

  • (System.currentTimeMillis() - time));

System.out.println();

System.out.println(
"比較迭代器方式遍歷的時間:"
);

time = System.currentTimeMillis();

Iterator it = linkedList.iterator();

while
(it.hasNext()){

it.next();

}

System.out.println(
"ArrayList:"

  • (System.currentTimeMillis() - time));

time = System.currentTimeMillis();

it = linkedList.iterator();

while
(it.hasNext()){

it.next();

}

System.out.println(
"LinkedList:"

  • (System.currentTimeMillis() - time));

}

}

運行結果:比較插入在頭部元素的時間:ArrayList:16829LinkedList:234
比較for循環方式遍歷的時間:ArrayList:0LinkedList:110375
比較foreach方式遍歷的時間:ArrayList:31LinkedList:16
比較迭代器方式遍歷的時間:ArrayList:15LinkedList:16
在ArrayList頭部插入元素竟然花了16829ms, 因為ArrayList內部是數組,所以會出現大量移動元素操作.而LinkedList內部是鏈表,所以很容易就在表頭插入新的結點。使用LinkedList for循環遍歷方式竟然花了110375ms, 因為LinkedList不支持隨機查找,每次都會從表頭開始查找,而ArrayList支持隨機查找。
結論:ArrayList適用于需要隨機查找的場景,LinkedList適用于需要大量插入和刪除元素操作的場景。

分類: Java | 評論

java集合ArrayList和Vector
作者 codercjg9 一月 2015, 9:38 下午

ArrayList實現了List接口,是最常用的集合類。它的內部是用數組實現,使用時會根據包含的元素數目自動擴容。至于Vector,功能與實現方式都和ArrayList一樣的,但效率比ArrayLsit略低,因為Vector是ArrayList的同步版本,它的方法前大部分都加了Sychronized, 是多線程安全的,而ArrayList不是。
ArrayList用法比較簡單,可以把它當作容量沒有限制的數組來用,但也會有一些容易忽略的小細節。1)創建ArrayList對象時傳入一個合適的容量,有助于提高效率,因為默認容量是10,如果超出了就需要擴容,這個比較耗cpu時間2)add(), get(), remove()方法中的索引都不能超過ArrayList.size(), 否則運行時會拋越界異常3)contains()方法判斷是否包含某元素是默認調用元素的equals()方法,如果沒有則調用元素的基類Object的equals()方法,該方法默認比較兩個對象的引用,如果想比較對象的內容,需要在元素中重寫equals()方法
下面通過代碼來說明:
Product.java
public
class
Product {

private
int
id;

private
String name;

private
int
price;

public
Product(
int
id, String name,
int
price) {

super
();

this
.id = id;

this
.name = name;

this
.price = price;

}

public
int
getId() {

return
id;

}

public
void
setId(
int
id) {

this
.id = id;

}

public
String getName() {

return
name;

}

public
void
setName(String name) {

this
.name = name;

}

public
int
getPrice() {

return
price;

}

public
void
setPrice(
int
price) {

this
.price = price;

}

@Override

public
int
hashCode() {

final
int
prime =
31
;

int
result =
1
;

result = prime * result + id;

result = prime * result + ((name ==
null
) ?
0
: name.hashCode());

result = prime * result + price;

return
result;

}

@Override

public
boolean
equals(Object obj) {

if
(
this
== obj)

return
true
;

if
(obj ==
null
)

return
false
;

if
(getClass() != obj.getClass())

return
false
;

Product other = (Product) obj;

if
(id != other.id)

return
false
;

if
(name ==
null
) {

if
(other.name !=
null
)

return
false
;

}
else
if
(!name.equals(other.name))

return
false
;

if
(price != other.price)

return
false
;

return
true
;

}

@Override

public
String toString() {

return
"Product [id="

  • id +
    ", name="
  • name +
    ", price="
  • price +
    "]"
    ;

}

}

ArrayListSample.java
import
java.util.ArrayList;

import
java.util.Enumeration;

import
java.util.Iterator;

import
java.util.List;

import
java.util.Vector;

public
class
ArrayListSample {

public
static
void
main(String[] args) {

Product p1 =
new
Product(
1
,
"java"
,
40
);

Product q1 =
new
Product(
1
,
"java"
,
40
);

Product p2 =
new
Product(
2
,
"C++"
,
50
);

Product p3 =
new
Product(
3
,
"php"
,
60
);

Product p4 =
new
Product(
4
,
"pthyon"
,
70
);

Product q4 =
new
Product(
4
,
"pthyon"
,
70
);

//1. ArrayList內部是用數組實現的,容量默認為10,當容量不夠時會擴容,并把原來數組中內容

// 拷貝到新創建的數組中,出于效率考慮,創建ArrayList對象時盡量給它設置一個合適的容量

List<Product> list =
new
ArrayList<Product>();

list.add(p1);

list.add(p2);

list.add(p3);

list.add(
2
, p4);

list.add(
2
, q4);
// 可插入元素

// 2. add() get() remove()方法中的索引不能超過list.size(),否則會拋出越界異常

// list.add(10, p4);

// list.remove(10);

// System.out.println(list.get(100));

// 3. 打印ArrayList對象時,會調用ArrayList的toString()方法,在該方法內部會調用

// Product的toString()方法,如果Product沒有覆蓋Object的toString()方法,那么

// 會調用基類Object的toString()方法,將打印類似Product@77158a類名@對象hashCode的信息

System.out.println(list);

// 4. 調用contains()方法判斷是否包含某個對象時,contains()會調用equals()方法進行判斷,

// 而Object類中quals()方法默認是比較對象的引用,如果想根據內容判斷,可重新Product的equals()

// 和hashCode()方法

System.out.println(list.contains(p1));
// true

System.out.println(list.contains(q1));
// 重寫equals()和hashCode()方法前為false, 重寫后為true

// ArrayList的三種遍歷方法

System.out.println(
"for循環遍歷"
);

int
size = list.size();

for
(
int
i=
0
; i<size; i++){

System.out.println(list.get(i));

}

System.out.println(
"foreach遍歷"
);

for
(Product p:list){

System.out.println(p);

}

System.out.println(
"迭代器遍歷"
);

Iterator<Product> it = list.iterator();

while
(it.hasNext()){

System.out.println(it.next());

}

//實際測得,for循環方式遍歷最快,然后是迭代器方式,最后是foreach方式

Vector <Product> v =
new
Vector<Product>();

v.add(p1);

v.add(p2);

v.add(p3);

v.add(
2
, p4);

v.add(
2
, q4);

// Vector除了可用ArrayList的三種方式遍歷外,還可用下面的Enumeration方式

System.out.println(
"Enumeration遍歷"
);

Enumeration<Product> s= v.elements();

while
(s.hasMoreElements()){

System.out.println(s.nextElement());

}

}

}

執行結果:[Product [id=1, name=java, price=40], Product [id=2, name=C++, price=50], Product [id=4, name=pthyon, price=70], Product [id=4, name=pthyon, price=70], Product [id=3, name=php, price=60]]truetruefor循環遍歷Product [id=1, name=java, price=40]Product [id=2, name=C++, price=50]Product [id=4, name=pthyon, price=70]Product [id=4, name=pthyon, price=70]Product [id=3, name=php, price=60]foreach遍歷Product [id=1, name=java, price=40]Product [id=2, name=C++, price=50]Product [id=4, name=pthyon, price=70]Product [id=4, name=pthyon, price=70]Product [id=3, name=php, price=60]迭代器遍歷Product [id=1, name=java, price=40]Product [id=2, name=C++, price=50]Product [id=4, name=pthyon, price=70]Product [id=4, name=pthyon, price=70]Product [id=3, name=php, price=60]Enumeration遍歷Product [id=1, name=java, price=40]Product [id=2, name=C++, price=50]Product [id=4, name=pthyon, price=70]Product [id=4, name=pthyon, price=70]Product [id=3, name=php, price=60]
java中的static與final
作者 codercjg8 一月 2015, 11:34 上午

static變量:非static變量告訴編譯器每創建一個對象都為該變量分配一份存儲空間。而static變量是告訴編譯器為該變量只分配一份存儲空間,和創建多少對象沒關系,甚至根本不需要創建對象。所以無論是類static成員變量還是方法中的static局部變量都只有一份存儲空間,它的值會累積。
static方法:調用非static方法時編譯器會把一個表示當前對象的this句柄作為參數傳入該方法,而static修飾方法時是告訴編譯器不要傳入參數this句柄,所以static方法中不能調用非靜態方法和引用類中的非靜態成員變量,因為他們需要傳入this。
static內部類:內部類默認需要持有創建它的外部類對象的this句柄,所以創建內部類對象前需要創建一個外部類對象。在內部類前加了static關鍵字后,就是告訴編譯器不需要這個句柄,所以創建該static內部類對象前不需要創建一個外部內對象。因為沒有外部內對象的this句柄,所以也不能使用與外部類對象相關的變量和方法。
總結:static 變量作用:告訴編譯器只為該變量分配一份存儲空間,和有多個對象沒關系,即使沒有對象也會分配一份存儲空間
static方法作用是:告訴編譯器調用該方法時不需要傳入this參數,那么自然不用創建對象了,當然在它里面也不能使用與對象關聯的類成員變量,和需要傳入this參數的非static方法了。
static內部類作用:創建內部類對象時,不需要創建外部內對象。
final修飾變量:告訴編譯器該變量只能被賦一次初值(編譯期或運行期都可以),之后它的值不能被改變,否則編譯器提示出錯。編譯器會保證final變量有初值,未指定初值需在構造函數中指定。
public
class
Test{

public
static
final
int
A=
1
;
//告訴編譯器只分配一份存儲空間,且A不能被修改。

//private final int a; // 沒有初值

private
final
int
a_1;
// 構造函數中賦初值

private
final
int
b =
1
;

private
int
c =
1
;

private
final
int
d = ++c;
//運行時賦賦初值

public
Test(){

a_1 =
1
;

}

public
void
change(
final
int
arg1){

//arg1 = 1; // 不能修改

//b = 1; // 不能修改

}

public
static
void
main(String[] args){

Test test =
new
Test();

test.change(
1
);

}

}

上面的注釋掉的代碼行編譯時會出錯。
final方法:1.出于設計的考慮把方法鎖定,告訴編譯器該方法不能被繼承它的類修改它的含義,所以不能被覆蓋2.早期jdk版本出于效率的考慮,用于告訴編譯器把該方法作為一個內聯函數,在調用時用代碼展開,省去通過壓棧傳入參數后跳轉到指定代碼執行,然后跳回并清理棧中的參數的開銷。但j2se5/6之后jvm會自動處理效率問題。所以除非明確禁止覆蓋時,才設置方法為final的。類中所有的private方法都隱式指定為final的,由于無法取用private方法,所以也就無法覆蓋它。
final類:告訴編譯器該類不能被修改,不允許被繼承

String類的實現和陷阱
作者 codercjg8 一月 2015, 12:31 上午

String中的數據結構:
public
final
class
String

implements
java.io.Serializable, Comparable<String>, CharSequence

{

/** The value is used for character storage. */

private
final
char
value[];

/** The offset is the first index of the storage that is used. */

private
final
int
offset;

/** The count is the number of characters in the String. */

private
final
int
count;

}

從String源碼中可知String對象用字符數組value存儲字符串常量,有效內容為value[offset~count-1];String中每一個看似會改變其內容的方法其實是返回了一個新new的String對象,字符串則存在String對象中新new的字符數組里。
當兩個String對象擁有相同的值時,會引用字符串常量池中的同一個拷貝,如下所示
String str1=
"abc"
;

String str2=
"abc"
;

String str3=
new
String(
"abc"
);

System.out.println(str1==str2);
// true

System.out.println(str1==str3);
// false;

System.out.println(str1==str3.intern());
// true

因為”abc”是一個String對象,str1和str2都指向String對象”abc”;而String3指向了另一個新new的對象,而這個對象的字符數組指向{‘a’,'b’,'c’}
String中的方法:String.toString():返回字符串一個打印對象地址的陷阱:
public
class
A{

public
String toString(){

return
""

this
;

}

}

調用類A中的toString()方法時會得到一個異常,因為”"+this時,編譯器會調用toString()方法,這樣就構成了一個沒有出口的遞歸。如果要打印對象的地址,應該調用Object.toString(), super.toString().
如果經常要進行類似str1+”sss”+”str2″這樣的操作,應該選用StringBuilder.append()方法。至于StringBuffer, 和StringBuilder功能類似,只是用于多線程的同步版本。如果String經常要用findString()查找的話,那么可以選擇StringTokenizer,這個效率更高。

分類: Java | 評論

gravity layout_gravity和layout_weight
作者 codercjg6 一月 2015, 4:56 下午

linearlayout中三個參數比較搞啊gravity:view中文字的對齊方式layout_gravity:view在linearlayout中的位置layout_weight:線性布局所占寬度減去所有子控件layout_width(orition=horizontal)或者layout_height(orition=vertical)后剩余空間所占的比例,默認為0如下面的例子:剩余空間=父控件寬度-三個TextView寬度其中父控件為線性布局,占滿整個屏幕。設屏幕寬度為W所以寬度W,三個TextView的寬度為W1,W2,W3, 剩余寬度為SW,則SW= W-W1-W2-W3又因為W1=W2=W3=0所以剩余空間SW=W屏幕的寬度其中三個TextView的layout_weight比例關系為1:1:1所以他們的寬度都為1/3屏幕寬度
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>

<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"

android:layout_width

"match_parent"

android:layout_height

"match_parent"

android:orientation

"horizontal"

<
TextView

android:layout_width

"0dp"

android:layout_height

"wrap_content"

android:layout_weight

"1"

android:text

"1"

android:background

"#FF0000"
/>

<
TextView

android:layout_width

"0dp"

android:layout_height

"wrap_content"

android:layout_weight

"1"

android:text

"1"

android:background

"#00FF00"

android:gravity

"center"
/>

<
TextView

android:layout_width

"0dp"

android:layout_height

"wrap_content"

android:layout_weight

"1"

android:text

"1"

android:background

"#0000FF"

android:layout_gravity

"center"
/>

</
LinearLayout

分類: Android | 評論

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • 多態 任何域的訪問操作都將有編譯器解析,如果某個方法是靜態的,它的行為就不具有多態性 java默認對象的銷毀順序與...
    yueyue_projects閱讀 986評論 0 1
  • 一. Java基礎部分.................................................
    wy_sure閱讀 3,835評論 0 11
  • 概念 jsp是一種簡化的servlet 有人說servlet是java里面嵌入html,jsp是html里面嵌入j...
    arkulo閱讀 294評論 0 1
  • 大過節的,Sir還要被催債。 一部讓人感慨萬千的港劇。 Sir敢說,如此執著為它打call的毒飯,你們一定很懷舊。...
    Sir電影閱讀 1,300評論 2 10