Lesson 1

来源:互联网 发布:mac怎么设置新浪邮箱 编辑:程序博客网 时间:2024/04/28 05:42

实现随机产生100个不重复的手机号码,手机以:13开头

知识点:

          1、java collection list的应用

          2、StringBuffer

          3、Random的用法

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

一、 容器类可以大大提高编程效率和编程能力,在Java2中,所有的容器都由SUN公司的Joshua Bloch进行了重新设计,丰富了容器类库的功能。 
        Java2容器类类库的用途是“保存对象”,它分为两类: 
        Collection----一组独立的元素,通常这些元素都服从某种规则。List必须保持元素特定的顺序,而Set不能有重复元素。 
        Map----一组成对的“键值对”对象,即其元素是成对的对象,最典型的应用就是数据字典,并且还有其它广泛的应用。另外,Map可以返回其所有键组成的Set和其所有值组成的Collection,或其键值对组成的Set,并且还可以像数组一样扩展多维Map,只要让Map中键值对的每个“值”是一个Map即可。
1.迭代器 
        迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。 
        Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。 
        Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
2.List的功能方法 
        List(interface): 次序是List最重要的特点;它确保维护元素特定的顺序。List为Collection添加了许多方法,使得能够向List中间插入与移除元素(只推荐LinkedList使用)。一个List可以生成ListIterator,使用它可以从两个方向遍历List,也可以从List中间插入和删除元素。 
        ArrayList: 由数组实现的List。它允许对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢。ListIterator只应该用来由后向前遍历ArrayList,而不是用来插入和删除元素,因为这比LinkedList开销要大很多。 
        LinkedList: 对顺序访问进行了优化,向List中间插入与删除得开销不大,随机访问则相对较慢(可用ArrayList代替)。它具有方法addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast(),这些方法(没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。
3.Set的功能方法 
        Set(interface): 存入Set的每个元素必须是唯一的,因为Set不保存重复元素。加入Set的Object必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。 
        HashSet: 为快速查找而设计的Set。存入HashSet的对象必须定义hashCode()。 
        TreeSet: 保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。 
        LinkedHashSet: 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。 
        HashSet采用散列函数对元素进行排序,这是专门为快速查询而设计的;TreeSet采用红黑树的数据结构进行排序元素;LinkedHashSet内部使用散列以加快查询速度,同时使用链表维护元素的次序,使得看起来元素是以插入的顺序保存的。需要注意的是,生成自己的类时,Set需要维护元素的存储顺序,因此要实现Comparable接口并定义compareTo()方法。

 

二、

String && StringBuffer的区别:
非可变对象一旦创建之后就不能再被改变,可变对象则可以在创建之后被改变。String对象是非可变对象;StringBuffer对象则是可变对象。为获得更佳的性能需要根据实际情况小心谨慎地选择到底使用这两者中的某一个。

String类用来表示那些创建后就不会再改变的字符串,它是不可变的(immutable);
StringBuffer类用来表示内容可变的字符串;
例:
1.String对象:
String str = "Hello";
str += "World";
//     JVM会创建一个临时的StringBuffer类对象,并调用其append()方法完成字符串的拼接,这是因为 String类是不可变的,拼接操作不得不使用StringBuffer类(并且--JVM会将"Hello"和"World"创建为两个新的 String对象)。之后,再将这个临时StringBuffer对象转型为一个String,代价不菲!可见,在这一个简单的一次拼接过程中,我们让程序创建了四个对象:两个待拼接的String,一个临时StringBuffer,和最后将StringBuffer转型成为的String--它不是最初的str,而是最初的str的引用指向了新生成的String对象"HelloWorld"。
2.StringBuffer对象:
StringBuffer strBuf = new StringBuffer("Hello");
strBuf.append("World");
//     程序将只产生两个对象:最初的strBuf :"Hello"和拼接时的String("World"),不再需要创建临时的StringBuffer类对象而后还得将其转换回String对象。节省额外的系统开销。

如何选择是使用String还是StringBuffer:
取决于两种情况,第一种情况是需要连接的字符串是在编译期决定的还是在运行期决定的,第二种情况是你使用的是StringBuffer还是String。
1) 第一种情况:编译期决定相对于运行期决定;如:
String str = "This " + "is " + "a " + "Java " + "program";
StringBuffer strBuf = new StringBuffer();
strBuf.append("This ");
strBuf.append("is ");
strBuf.append("a ");
strBuf.append("Java ");
strBuf.append("program");

此时,+操作符比StringBuffer.append()方法要快,WHY?这里编译器的优化起了关键作用,编译器简单地在编译期连接多个字符串。它使用编译期决定取代运行期决定,在你使用new关键字来创建String对象的时候也是如此。这里str对象在编译期就决定了而 StringBuffer对象是在运行期决定的。运行期决定需要额外的开销当字符串的值无法预先知道的时候,编译期决定作糜谧址 闹悼梢栽は戎赖氖?候,也就是说String str = "This " + "is " + "a " + "Java " + "program";这段代码在编译时,编译器会对程序作出优化,String str被优化成“This is a Java program”;而StringBuffer strBuf只会在运行时才处理。所以效率是不一样的。(注意,这里的String str = "This " + "is " + "a " + "Java " + "program";与 String str = "Hello";
str += "World";是不一样的);
2) 第二种情况:使用StringBuffer取代String
String str = "Hello";
for(int i = 0; i < 40000; i++) {
     str += "World";
}

StringBuffer strBuf = new StringBuffer("Hello");
for(int i = 0; i < 40000; i++) {
      strBuf.append("World");
}
此时,StringBuffer.append()方法要比+操作符快得多,WHY?原因是两者都是在运行期决定字符串对象,但是+操作符使用不同于StringBuffer.append()的规则;它是通过String和StringBuffer来完成字符串的连接操作的。

另外,在使用StringBuffer时,可以通过StringBuffer的构造函数来设定它的初始化容量,这样可以明显地提升性能。这里提到的构造函数是StringBuffer(int length),length参数表示当前的StringBuffer能保持的字符数量。如:

(1)StringBuffer strBuf = new StringBuffer();
             for(int i = 0; i < 40000; i++) {
                  strBuf.append("Hello");
             }
(2)
StringBuffer strBuf = new StringBuffer(100000);
             for(int i = 0; i < 40000; i++) {
                  strBuf.append("Hello");
             }
此时,(2) 的效率好于 (1),因为StringBuffer内部实现是char数组,当使用缺省的构造函数来创建StringBuffer对象的时候,因为没有设置初始化字符长度,StringBuffer的容量被初始化为16个字符,也就是说缺省容量就是16个字符。当StringBuffer达到最大容量的时候,它会将自身容量增加到当前的2倍再加2,也就是(2*旧值+2)。 如果使用缺省值,初始化之后接着往里面追加字符,在追加到第16个字符的时候它会将容量增加到 34(2*16+2),当追加到34个字符的时候就会将容量增加到70(2*34+2)。无论何事只要StringBuffer到达它的最大容量它就不得不创建一个新的字符数组然后重新将旧字符和新字符都拷贝一遍。所以总是给StringBuffer设置一个合理的初始化容量值是错不了的,这样会带来立竿见影的性能增益。(2)避免了复制数组的开销。

创建String对象:
String str = "Hello";
//   JVM先根据内容"Hello"查找对象,如果没找到,则在heap(堆栈)*上创建新对象,并将其赋予str,否则使用已经存在的对象。

String str = new String("Hello");
//   
据内不管heap上有没有"Hello"这个对象,JVM都会在heap上创建一个新String对象;此时heap上可能会出现内容相同,地址不同的String对象。
推荐使用String str = "Hello";这种方法创建String类型的对象,这样会使heap中只存在唯一的一个存放"Hello"对象的内存地址;实际上我们不需要多个独立的"Hello"对象,因为要运行它们的话浪费时间+浪费内存。我们也不必因使用new String("Hello");创建了多个”Hello”对象而发愁,可以使用intern()方法来避免在堆内存上创建重复的String对象来改善Java的运行性能。String intern()方法检查字符串对象的存在性,如果需要的字符串已经存在,那么它将会引用指向已经存在的字符串对象而不是重新创建一个。这和使用 String str = "Hello";这种方法创建对象就作用上来说是一致的。使用intern():
String str = new String("Hello");
str = str.intern();

String对象的比较:
"=="            //比较地址;
"equals"    //比较内容;

String str1 = "a";
String str2 = "a";
String str3 = new String("a");
str1 == str2        //    true
str1 == str3        //    false
str1.equals(str2);       //   true
str1.equals(str3);       //   true

但是StringBuffer类并没有实现Objcet类的Equals方法,所以不能用这个方法来比较两个StringBuffer类的字符串是否相等:
StringBuffer strBuf1 = new StringBuffer(“a”);
StringBuffer strBuf2 = new StringBuffer(“a”);
     System.out.println(
strBuf1.equals(strBuf2
));
程序输出:false

*这里想对“heap(堆栈)”做一下更正:应该是heap(堆),而非堆栈。
“堆”是一种通用的内存池,用于存放所有的Java对象。当使用“new”实例化一个对象时,编译器会自动在堆里进行存储分配。
C++在堆栈中创建对象,Java对象引用存储在堆栈中;而Java对象并不存储于其中。
堆栈:堆栈指针向下移动,分配新内存,向上移动,释放内存;创建程序时编译器必须知道存储在堆栈中所有数据的确切大小和生命周期,因为要通过代码实现来控制上下移动堆栈指针,这一约束限制了程序的灵活性。而如果是在堆上创建对象,编译器不需要知道从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。

 

三、StringBuffer的用法

描述:在实际应用中,经常回遇到对字符串进行动态修改。这时候,String类的功能受到限制,而StringBuffer类可以完成字符串的动态添加、插入和替换等操作。

1、构造函数。

StringBuffer() :构造一个没有任何字符的StringBuffer类。
StringBuffer(int length) : :构造一个没有任何字符的StringBuffer类,并且,其长度为length。
StringBuffer(String str) :以str为初始值构造一个StringBuffer类。

 



2、方法。
说明:
1. 所有方法均为public;
2. 书写格式:[修饰符] <返回类型> <方法名([参数列表])>

如:
static int parseInt(String s) 表示:此方法(parseInt)为类方法(static),返回类型为(int),方法所需参数为String类型。

1. StringBuffer append(boolean b)
2. StringBuffer append(char c)
3. StringBuffer append(char[] str)
4. StringBuffer append(char[] str, int offset, int len)
5. StringBuffer append(double d)
6. StringBuffer append(float f)
7. StringBuffer append(int i)
8. StringBuffer append(long l)
9. StringBuffer append(Object obj)
10. StringBuffer append(String str)
11. StringBuffer append(StringBuffer sb)


以上的方法都是向字符串缓冲区“追加”元素,但是,这个“元素”参数可以是布尔量、字符、字符数组、双精度数、浮点数、整型数、长整型数对象类型的字符串、字符串和StringBuffer类等。如果添加的字符超出了字符串缓冲区的长度,Java将自动进行扩充。


String question = new String("1+1=");
int answer = 3;
boolean result = (1+1==3);

StringBuffer sb = new StringBuffer();
sb.append(question);
sb.append(answer);
sb.append('/t');
sb.append(result);

System.out.println(sb);
结果为:
1+1=3   false


12. int capacity() :返回当前StringBuffer对象(字符串缓冲区)的总空间,而非字符号串的长度。
13. char charAt(int index) :在当前StringBuffer对象中取索引号为index的字符。第一个字符的索引为“0”
14. StringBuffer delete(int start, int end) :删除当前StringBuffer对象中以索引号start开始,到end结束的子串。
15. StringBuffer deleteCharAt(int index) :删除当前StringBuffer对象中索引号为index的字符。
16. void ensureCapacity(int minimumCapacity) :重新设置字符号串缓冲区的总空间。如果minimumCapacity大于当前的总空间,则新的空间被设置:一种结果是minimumCapacity;另一种结果是{“老空间”乘2加2}。


StringBuffer sb1 = new StringBuffer(5);
StringBuffer sb2 = new StringBuffer(5);

sb1.ensureCapacity(6);
sb2.ensureCapacity(100);

System.out.println( "sb1.Capacity: " + sb1.capacity() );
System.out.println( "sb2.Capacity: " + sb2.capacity() );
结果为:
sb1.Capacity: 12
sb2.Capacity: 100

17. void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) :从当前StringBuffer对象的索引号srcBegin开始,到srcEnd结束的子串,赋值到字符数组dst中,并且从dst的索引号dstBegin开始。


StringBuffer sb = new StringBuffer("I love her!");
char[] i = {'I',' ','l','o','v','e',' ','y','o','u'};

sb.getChars(7,10,i,7);

System.out.println( "sb: " + sb );
结果为:sb: I love her!


18. int indexOf(String str) :返回当前StringBuffer对象中,第一个满足str子串的位置。
19. int indexOf(String str, int fromIndex) :从当前StringBuffer对象的fromIndex开始查找,返回第一个满足str子串的位置。
20. StringBuffer insert(int offset, boolean b)
21. StringBuffer insert(int offset, char c)
22. StringBuffer insert(int offset, char[] str)
23. StringBuffer insert(int index, char[] str, int offset, int len)
24. StringBuffer insert(int offset, double d)
25. StringBuffer insert(int offset, float f)
26. StringBuffer insert(int offset, int i)
27. StringBuffer insert(int offset, long l)
28. StringBuffer insert(int offset, Object obj)
29. StringBuffer insert(int offset, String str)


以上的方法都是在当前StringBuffer对象中插入一个元素,在索引号offset处插入相应的值。
30. int lastIndexOf(String str) :返回当前StringBuffer对象中,最后一个满足str子串的位置。
31. int lastIndexOf(String str, int fromIndex) :从当前StringBuffer对象的fromIndex开始查找,返回最后一个满足str子串的位置。
32. int length() :返回当前StringBuffer对象(字符缓冲区)中,字符串的长度。注意:此方法与capacity() 不同。
33. StringBuffer replace(int start, int end, String str) :替换当前StringBuffer对象的字符串。从start开始,到end结束的位置替换成str。
34. StringBuffer reverse() :将字符串翻转。


StringBuffer sb = new StringBuffer("0123456789");
System.out.println( "sb.reverse(): " + sb.reverse() );
结果为:sb.reverse(): 9876543210


35. void setCharAt(int index, char ch) :设置索引号index的字符为ch。
36. void setLength(int newLength) :重新设置字符串缓冲区中字符串的长度,如果newLength小于当前的字符串长度,将截去多余的字符。


StringBuffer sb = new StringBuffer("0123456789");
sb.setLength(5);
System.out.println( "sb: " + sb );
结果为:sb: 01234

37. String substring(int start) :取当前StringBuffer对象中,从start开始到结尾的子串。
38. String substring(int start, int end) :取当前StringBuffer对象中,从start开始到end的子串。
39. String toString() :将当前StringBuffer对象转换成String对象。

 

原创粉丝点击