java笔记2

java集合中ArrayList与LinkedList比较
作者 codercjg 在 9 一月 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 arrayList =
new
ArrayList(circle);

LinkedList linkedList =
new
LinkedList();

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
作者 codercjg 在 9 一月 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 list =
new
ArrayList();

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

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

}

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

for
(Product p:list){

System.out.println(p);

}

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

Iterator it = list.iterator();

while
(it.hasNext()){

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

}

//实际测得,for循环方式遍历最快,然后是迭代器方式,最后是foreach方式

Vector v =
new
Vector();

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 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
作者 codercjg 在 8 一月 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类的实现和陷阱
作者 codercjg 在 8 一月 2015, 12:31 上午

String中的数据结构:
public
final
class
String

implements
java.io.Serializable, Comparable, 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
作者 codercjg 在 6 一月 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

linearlayout

分类: Android | 评论

你可能感兴趣的:(java笔记2)