1 第十一天
1.1 string stringbuffer stringbulider
1.三者在执行速度方面的比较:StringBuilder > StringBuffer > String
2.String <(StringBuffer,StringBuilder)的原因
String:字符串常量
StringBuffer:字符创变量
StringBuilder:字符创变量
从上面的名字可以看到,String是“字符创常量”,也就是不可改变的对象。对于这句话的理解你可能会产生这样一个疑问 ,比如这段代码:
1 String s = "abcd";
2 s = s+1;
3 System.out.print(s);// result : abcd1
我们明明就是改变了String型的变量s的,为什么说是没有改变呢? 其实这是一种欺骗,JVM是这样解析这段代码的:首先创建对象s,赋予一个abcd,然后再创建一个新的对象s用来
执行第二行代码,也就是说我们之前对象s并没有变化,所以我们说String类型是不可改变的对象了,由于这种机制,每当用String操作字符串时,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉,可想而知这样执行效率会有多底。
而StringBuffer与StringBuilder就不一样了,他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,这样就不会像String一样创建一些而外的对象进行操作了,当然速度就快了。
3.一个特殊的例子:
1 String str = “This is only a” + “ simple” + “ test”;
3 StringBuffer builder = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
你会很惊讶的发现,生成str对象的速度简直太快了,而这个时候StringBuffer居然速度上根本一点都不占优势。其实这是JVM的一个把戏,实际上:
String str = “This is only a” + “ simple” + “test”;
其实就是:
String str = “This is only a simple test”;
所以不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的String对象的话,速度就没那么快了,譬如:
String str2 = “This is only a”;
String str3 = “ simple”;
String str4 = “ test”;
String str1 = str2 +str3 + str4;
这时候JVM会规规矩矩的按照原来的方式去做。
4.StringBuilder与 StringBuffer
StringBuilder:线程非安全的
StringBuffer:线程安全的
当我们在字符串缓冲去被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。
对于三者使用的总结:
1.如果要操作少量的数据用 = String
2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
1.2 线程安全与不安全
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
比如一个 ArrayList 类,在添加一个元素的时候,它可能会有两步来完成:1. 在 Items[Size] 的位置存放此元素;2. 增大 Size 的值。
在单线程运行的情况下,如果 Size = 0,添加一个元素后,此元素在位置 0,而且 Size=1;
而如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList 添加元素,因为此时 Size 仍然等于 0 (注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size 的值。
那好,我们来看看 ArrayList 的情况,元素实际上只有一个,存放在位置 0,而 Size 却等于 2。这就是“线程不安全”了。
1.3 字符串操作函数
1.3.1 获取长度 字符串.Length
String s = “232”;s.Length;
1.3.2 大小写转换 str.ToUpper()大写 str.ToLoewr()小写
1.3.3 判断是否相等 str.Equals()
返回布尔值,括号加逗号可以看到重载。
第二个参数:StringComparison.OrdinalIgnoreCase是不区分大小写,默认不写区分。StringComparison是枚举类型。例如:str.Equals(“fsaff”, StringComparison.OrdinalIgnoreCase);
1.3.4 包含 str.Contains(“比较字符串”)
返回布尔值。
1.3.5 是否以某个字符串开始 str.StartsWith(“比较字符串”)
返回布尔值
1.3.6 是否以某个字符串结束 str.EndsWith(“比较字符串”)
返回布尔值
1.3.7 分割字符串 str.Split(char数组,StringSplitOptions.RemoveEmptyEntries);
第二个参数是处理空白字符(用于以空白字符串分割)。返回string类型的数组。
字符串会根据Char类型的数组中的字符来分割自己,且分割后的字符不包含char字符本身。
1.3.8 字符串与char数组转换
字符串本身是一个char类型的只读数组.并且使用str[n]的方式读取的数据类型是char,判断时需要用char类型来判断,否则会出错。
Char[] chs = str.ToCharArray();
Str = new string(chs);
1.3.9 字符串在某字符串中的开始位置和结束位置
Str.IndexOf(“比较字符串”,开始数字,可以不写,默认从0开始找)
返回字符串所在索引数,没找到返回-1,索引从0开始
例如:str.IndexOf(“fsd”,6);从第六个开始找
Str.LastIndexOf(“比较字符串”,开始数字,可以不写,默认从最后开始找)
倒着找,用法和上面一样
1.3.10 去掉空格
String str1 = Str.Trim();去掉前后空格,不能去中间的
String str1 = Str.TrimEnd();去掉后面的空格
String str1 = Str.TrimStart();去掉前面的空格
返回字符串,必须用字符串变量接收。
1.3.11 替换
Str.Replace(被替换字符串,替换成的内容);举例:
Str.Replace(“aa”,”bb”);
1.3.12 判断是否为空串或空字符串
空字符串虽然什么都没存,但是占用空间。Str=””;
空间null不占空间。Str=null; 可以用来释放空间
String.IsNullOrEmpty();
返回值为布尔值。
1.3.13 连接字符串 string.Join()
String s = stirng.Join(“|”,”dafsd”,”fdsfa”);
第一个是连接字符,后面是连接内容,后面可以用数组表示,int数组也可以
1.3.14 截取字符串
String ss = s.SubString(1);从第一字符开始截取到最后
String ss= s.SubString(1,3);从字符串的第一个位置开始截取,截取3个字符。
1.3.15 格式化字符串
String str = String.Format();按想要的格式输出。返回字符串
格式字符串形式内容:
1、 格式化货币(跟系统环境有关,中文人民币,英文美元)
String.Format(“{0:C}”,0.2) 结果¥0.20(英文系统$0.20)
默认保留两位小数,可以指定:
String.Format(“{0:C1}”,0.2222) 结果¥0.2(自动四舍五入)
还可以一次性格式化多个:
String.Format(“市场价:{0:C},优惠价{1:C3}”,23.15,19.82);
2、 格式化十进制的数字(格式化成固定的位数,位数不能少于未格式化前,只支持整型)
String.Format(“{0:D3}”,23); 结果023
String.Format(“{0:D2}”,1232); 结果1232(2只能代表格式化的最小位数,不会自己取舍)
3、 用分号隔数字,并指定小数位数
String.Format(“{0:N}”,14200); 结果14,200.00(默认为两位小数)
String.Format(“{0:D3}”,14200.2345); 142.235(自动四舍五入)
4、格式化百分比
String.Format(“{0:P}”,0.24583); 24.58%默认两位小数
String.Format(“{0:P1}”,0.24583); 24.6%四舍五入
5、零占位符和数字占位符效果和第2条类似,但支持整数和小数
String.Format(“{0:0000.00}”,123456.344);123456.34
String.Format(“{0:0000.00}”,123.4455);0123.45
String.Format(“{0:####.##}”,123445.5645); 123445.56
String.Format(“{0:####.#}”,194.0394);194
空格占位符
String.Format(“{0,-50}”,”abcde”); //格式化成50个字符,原字符左对齐,不足则补充空格
String.Format(“{0,50}”,”abcde”); //格式化成50个字符,原字符右对齐,不足则补充空格
6、日期格式化
String.Format(“{0:d}”,System.DateTime.Now);2009-3-2
String.Format(“{0:D}”,System.DateTime.Now);2009年3月20日
String.Format(“{0:f}”,System.DateTime.Now);2009年3月20日 15:37
String.Format(“{0:F}”,System.DateTime.Now); 2009年3月20日 15:37:52
String.Format(“{0:g}”,System.DateTime.Now); 2009-3-2 15:37
String.Format(“{0:G}”,System.DateTime.Now); 2009-3-2 15:37:27
String.Format(“{0:m}”,System.DateTime.Now);3月20日
String.Format(“{0:t}”,System.DateTime.Now);15:41
String.Format(“{0:T}”,System.DateTime.Now);15:41:50
1.4 数组类(数组操作函数)
属性
1 | IsFixedSize |
2 | IsReadOnly |
3 | Length |
4 | LongLength |
5 | Rank |
下表列出了 Array 类中一些最常用的方法:
序号 | 方法 & 描述 |
1 | Clear |
2 | Copy(Array, Array, Int32) |
3 | CopyTo(Array, Int32) |
4 | GetLength |
5 | GetLongLength |
6 | GetLowerBound |
7 | GetType |
8 | GetUpperBound |
9 | GetValue(Int32) |
10 | IndexOf(Array, Object) |
11 | Reverse(Array) |
12 | SetValue(Object, Int32) |
13 | Sort(Array) |
14 | ToString |
1.5 ArrayList集合(动态数组) (不推荐用)
1.5.1 ArrayList集合
长度随便,类型随便,集合的元素都是object类型,任何元素添加到集合中后,都会被装箱成object类型
使用前,必须引用命名空间using System.Collections;
ArrayList list = new ArrayList();
List.Add(2);
List.Add(“sadfsda”);list.Add(对象);
Add();可以添加任意类型的变量值。
任何一个数据类型都可以使用is来判断,判断后都可以使用强制转换。例如,对象,数组,结构体等。
If(List[i] is int[]){
For(int j=0;j<((int[])list[i]).Length;i++){
Cw(((int[])list[i])[j]);
}
}
1.5.2 ArrayList方法(自己学习)
Add();添加元素
AddRange();可以将集合的元素直接添加的集合中,主要是集合和数组中的元素,用此函数会直接添加元素,不会出现输出只显示命名空间的情况
Remove(“元素值”);移除指定的元素。例如:list.Remove(3);移除值为3的元素
RemoveAt();移除下标的元素。例如:list.RemoveAt(0);移除第一个元素
List. RemoveRange();用于删除一批元素,通过指定开始的索引和删除的数量来删除List.Insert(位置,值);插入一个元素,例如:list.Insert(3,”ddf”);第四个(下标为3的)就会变成ddf
List.InsertRange(位置,数组元素);插入一个集合
List.clear();移除集合中所有元素。
List.Reverse();反转
List.Sort ();升序排序
List.Contains();集合中是否包含某个元素,例如list.Contains(2);判断集合中是否包含2
TrimSize方法
这个方法用于将ArrayList固定到实际元素的大小,当动态数组元素确定不在添加的时候,可以调用这个方法来释放空余的内存。
ToArray方法
这个方法把ArrayList的元素Copy到一个新的数组中。Int32[] values = (Int32[])List.ToArray(typeof(Int32));
Int32[] values = new Int32[List.Count];
List.CopyTo(values);
1.6 键值对集合HashTable哈希表(类似PHP的字符串数组)
Hashtable中的元素存储在DictionaryEntry对象中
命名空间和ArrayList一样,using Collections;
定义:Hashtable t = new Hashtable();
键是唯一的,通过键找值
添加:t.Add(“键”,”值”);t.Add(true,false);t.Add(1.5f,”aa”);重复键使用add添加会报错。
或者 t[0] = 5;//添加一个键为0值为5的元素,t[“sdaf”] = “safs”;相同键会覆盖值
添加键值对没有顺序。
1.6.1 键值对的遍历
Foreach(var ii in t.Keys){
Console.WriteLine(“键{0},值{1}”,ii,t[ii]);
}
Foreach(DictionaryEntry ii in t){
Console.WriteLine(“键{0},值{1}”,ii.Key,ii.Value);
}
1.6.2 ArrayList长度
List.count 集合中实际存在的元素个数
List.Capacity 集合里最大的长度,即集合可以容纳多少个元素,根据实际的容纳量自动扩充的。永远比count大。
1.7 字典集合(键值对集合的一种)
Dictionary<键的类型,值的类型> 名称= new Dictionary<键的类型,值的类型>;
例如:Dictionary<int,string> dis = new Dictionary<int,string>;
添加方式:
Dis.Add(1,”234234”);
Dis[4] = “dd”; 如果键已存在会覆盖,没有就会创建
字典长度:dis.Count
字典的遍历:
for循环不能遍历,哪怕字典键都是int也不能,因为可能存在空缺的键。
Foreach(KeyValuePair<int,string> item in dis){
Cw(“键{0}值{1}”,item.Key,item.Value);
}
Foreach(var fff in dis.Keys){
Cw(“键{0}值{1}”,fff,dis[fff]);
}
1.8 List泛型集合
List<T> 尖括号内T代表任意类型,是一个类型的占位符
例如:List<int> list = new List<int>();
list.Add(1); list.Add(2); list.Add(3);
list.AddRange(new int[]{5,6,7,8,9});
list.AddRange(list);
长度:list.Count
转成数组:ToArray();
Int[] aa= list.ToArray();
数组转集合:
List<int> ll = aa.ToList();
1.9 自定义的泛型类
Class 类名<T> where T:struct
T是任意类型,where是类型限定(根据需要写,可以不写),struct是限定为值类型,class是限定引用类型。
IComparable是限定只能是本接口的子类。
T只是一个代表,使用什么字母都行,一般用T。
Where T:Class,new(); 限定为引用类型,并且使用了无参构造函数
举例:
Public class Person<T> where {
Private int _age;
Private T _a;
Public T A{}
Public void sayhello(){
}
}
调用:
Person<int> p = new Person<int>();
1.9.1 自定义泛型类的方法
Public void Change<T>(ref T a ,ref T b){就是在方法名后加上泛型符号
T temp = a;
A= b;
B = temp;
}
Int a =5;int b=8;
调用:p.Change<int>(ref a,ref b);
普通类中可以有泛型方法,泛型类中也可以有普通方法
1.10 重载运算符
自己去定义运算符的意义,只能在类中重载,也只能对重载所在类的对象起作用。
关键字:operator
1、 必须用public修饰
2、 必须是类的静态方法
3、 重载运算符==时,也必须重载!=运算符
4、 重载关系运算符>,>=时,也必须重载<,<=
5、 可以重载一元运算符:!,++,--,true,false
6、 可以重载的二元运算符:+,-,*,/,%,&,|,^,<<,>>
7、 可以重载关系运算符:==,!=,<,>,<=,>=
8、 一元运算符只能有一个参数,二元运算符有两个参数
9、 在某种情况下,参数的类型必须与声明的运算符的类或结构类型相同
举例:
public class Person{
public int num1{get;set;}
public int num2{get;set;}
//public static Person operator +(参数列表,该参数必须与类的结构或者运算符的结构相同){//重载加好运算符,
}
public static Person operator +(Person op1,Person op2){
Person p = new Person();
p.num1=op1.num1+op2.num1+op1.num2+op2.num2;
p.num2=op1.num1+op2.num1;
renturn p;
}
}
调用:
Person p1= new person();
P1.num1 = 3;
P1.num2 = 5;
Person p2 = new person();
P2.num1 = 4;
P2.num2 = 8;
Person p = p1+p2;//此时加号就是重载过的双目运算符
Cw(“num1-{0},num2-{1}”,p.num1,p.num2);//p.num1=20;p.num2=7;
1.11 文件类File
处理小型文件的读取和写入,因为该类的方法会将文件整个内容都读取到内存中。该类属于静态类
使用需要导入system.IO类库
Flie.Create(路径及文件名,大小限制); 创建文件,返回值是fileStream
例如:File.Create(@“c:\cc\cc.txt”);
File.Delete(路径及文件名);删除文件,
建议删除创建之前先判断有没有,使用File.Exists();
File.Copy(复制的文件及路径,复制到的文件和路径名);粘贴文件
File.Copy(@“c:\cc\cc.txt”, @“c:\cc\bb.txt”);
剪切
File.Move(@“c:\cc\cc.txt”, @“c:\cc\bb.txt”);
上述方法的路径一定要存在,系统不会自动创建文件夹路径,并且,如果该文件已存在会直接报错
1.11.1 文件编码
存储文件:存储数据的一种表现形式。
乱码:存储文件和读取文件时编码方式不一样。
ASC码表 0-127 ASCII 0-255 GB2312 BIG5 Unicode(UTF-8, UTF-7)
一般使用UTF-8传输交互数据:3个字节表示一个汉字
1.11.2 文件类的操作
文件内容读取:
FileStream fs = File.Open(“路径文件名”,打开方式(FileMode.Open));
或者通过流的方式打开文件:FileStream fs = new FileStream(“路径”,Filemode.Append);
打开方式为FileMode.Open,后写入的内容会覆盖掉。Filemode.Append时不是覆盖,而是追加。
Fs.Read(字节数组,第几个开始,读几个);返回值是int,返回的内容是真是字节的长度,例如:Fs.Read(创建一个空字节数组,0,buffer.length);
fs.Length字节流长度
str = File.ReadAllText(“路径”);返回字符串,读取所有文件内容为str
string[] strs = File.ReadAllLines(“路径”);返回字符串数组,每一行为数组的一个元素,读取文件内容的每一行为string数组
File.ReadAllBytes(路径及文件名);读取文件中所有行,然后关闭该文件,返回值byte[]字节数组
Encoding.编码格式.GetString(File.ReadAllBytes(路径及文件名));把byte[]数组转化成字符串,返回值字符串。
Encoding 是system.Text类库的内容,需要先加载该命名空间
文件内容写入:
FileStrem Fs = Flie.Create(路径及文件名,大小限制);
Fs.Write(字节数,第几个开始写,写几个);使用该方法第一步应该讲对应字符串内容转化成字节数,但转换字节数,需要先获取编码。
Byte[] buffer = System.Text.Encoding.编码格式.GetBytes(str);f返回字节数组
写完后,必须将fs.Close();关闭文件流,负责会出现文件占用的问题。
此外还有File.WriteAllBytes方法
举例说明:string str = “dsfasdfafdsaf”;
Byte[] bb = Encoding.Default.GetBytes(str);//default是默认编码模式
File.WriteAllBytes(路径及名称,bb);该写入操作会直接将原文件内容覆盖掉。
1.11.3 FileInfo类
FileInfo 是密封类:能继承别的类,别的类不能继承密封类,只能坐子类。
FileInfo是非静态类,用对象对文件进行操作。
例如: FileInfo s = new FileInfo(路径及文件名);
s.Create();
s.CopyTo();
s.MoveTo();
s.Delete();
1.11.4 对文件夹操作的静态类Directory
Directory是静态类
Directory.CreateDirectory(@“目录结构\文件夹名”);创建文件夹,已有不再创建
Bool exits = Directory.Exists(@“路径文件夹”);是否存在该文件夹