2018-05-30 第二十四天

  1. 云栖社区>
  2. 博客>
  3. 正文

2018-05-30 第二十四天

winniehu 2018-05-30 22:35:26 浏览675
展开阅读全文

一、String

public final class String extends Object implements Serializable, Comparable, CharSequence

 

String 类包括的方法可用于检查序列的单个字符、比较字符串、搜索字符串、提取子字符串、创建字符串副本并将所有字符全部转换为大写或小写。大小写映射基于 Character 类指定的 Unicode 标准版。


例1:

import java.util.Arrays;


public class TestString {


public static void main(String[] args) {

byte[] bs = {65,66,67,68,69};

//通过字节数组创建字符串对象

String str = new String(bs);

//将字符穿对象转换为字节数组

System.out.println(Arrays.toString(str.getBytes()));//{65,66,67,68,69}

System.out.println(str);//ABCDE

//得到字节数组指定区间的字符串对象

System.out.println(new String(bs,1,3));//BCD

//创建一个字符串对象,根据指定的值

str = new String("0123456789");

//0序的

System.out.println(str.charAt(3));//3

//字符串连接 原字符串不变

System.out.println(str.concat("asd"));//0123456789asd

//是否包含某个子字符串

System.out.println(str.contains("0234"));//false

//某个字符串是否以什么结尾

System.out.println(str.endsWith(""));//true

//字符串格式化,

System.out.println(String.format("%s攻击了%s,%s掉了%d滴血", "阿基里斯","赫克托","赫克托",100));//100是自动装箱

//从前往后找

System.out.println(str.indexOf(52));//4

System.out.println(str.indexOf("345"));//3

System.out.println(str.indexOf("345", 6));//-1

//求长度

System.out.println(str.length());//10

//生成一个新的字符串

System.out.println(str.replace("2", "__"));

//切割字符串

str = "123_5435_1232_545_343_DSF";

System.out.println(Arrays.toString(str.split("_")));

System.out.println(str.substring(8));//_1232_545_343_DSF

System.out.println(str.substring(1, 2));//2

//去掉前后的空白字符

str = "      uiu ou ou ou         ";

System.out.println(str.trim());

System.out.println();

System.out.println(str);

}

}

 

例2:

//* 1:在工具类中定义工具方法,对指定的字符串,求出该字符串中,出现指定字符的个数。

//* 2:自定义方法,实现产生一个随机字符串,长度为20,每一个字符要求全部随机产生,然后统计该字符串中的大写字符和小写字符的个数并以数组形式返回统计的个数

//* 3:自定义方法,针对指定的字符串,返回该字符串的逆序形式。

import java.util.Arrays;

import com.bjsxt.util.MyUtil;


public class TestString1 {


public static void main(String[] args) {

System.out.println(getCharCount("3278239782981", '8'));

String str = getRandomStr(20);

System.out.println(str);

System.out.println(Arrays.toString(getLowerAndUpperCharCount(str)));

}

// 在工具类中定义工具方法,对指定的字符串,求出该字符串中,出现指定字符的个数。

public static int getCharCount(String str , char key){

if(str == null)

return -1;

if(str.isEmpty())

return 0;

int counter = 0;

int len = str.length();

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

//取出每个字符进行比对

char c = str.charAt(i);

if(key == c)

counter ++;

}

return counter;

}

//自定义方法,实现产生一个随机字符串,长度为20,每一个字符要求全部随机产生,然后统计该字符串中的大写字符和小写字符的个数并以数组形式返回统计的个数

//随机产生一个指定长度的字符串

public static String getRandomStr(int length){

String str = "";

for(int i=0;i

//得到随机区间的值

int ranNumber = MyUtil.getRandomNumber('A', 'Z'+1);

//随机大小写的字符

char ranChar = (char)(Math.random() > 0.5 ? ranNumber : ranNumber + 32);

str = str.concat(Character.toString(ranChar));

}

return str;

}

//针对指定的字符串,统计字符串中大小写的个数,以数组形式返回。

public static int[] getLowerAndUpperCharCount(String str){

if(str == null)

return null;

if(str.isEmpty())

return null;

int[] count = new int[2];

//统计

int len = str.length();

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

char c = str.charAt(i);

if(Character.isUpperCase(c)){

count[0]++;

}else if(Character.isLowerCase(c)){

count[1]++;

}

}

return count;

}

// 自定义方法,针对指定的字符串,返回该字符串的逆序形式。

public static String reverse(String str){

//逆序取出来,连接

if(str == null)

return null;

if(str.isEmpty())

return "";

String newStr = "";

int len = str.length();

for (int i = len-1; i >= 0; i--) {

char c = str.charAt(i);

newStr += c;

}

return newStr;

}

}



二、原码分析

1:字符串类型底层使用 char[] 实现。是一个final 修饰的数组。

String 类没有提供对外的任何修改原有字符串的方法。

结论:字符串对象一旦创建,就不能更改。所有的看似对字符串的修改,都不是在原有的字符串对象上的修改,而是会生成一个新的字符串对象。

这样的特点导致了,在程序中使用字符串对象,会在内存中生成大量的字符串对象的碎片。造成对内存的浪费。

java 对String 进行了特殊的处理,来尽量的避免这样的问题。


1240

三、String扣留intern 机制

java 对字符串提供了一种 字符串扣留 intern 机制。

java 对字符串常量 提供了一个 字符串常量池的内存空间。在方法区中。扣留机制的基础。

字符串常量池由String 类自己维护。

在编译期一个类有哪些字符串常量就确定了。在类加载的时候,就会把当前类的所有的字符串常量加载到字符串常量池中。


1:String str = "abc";

在java 语句中,如果存在了一个字符串常量,那么 String 类的扣留机制 会 自动的判断 该常量是否存在于 常量池中

如果存在,那么直接将常量池中的字符串对象的引用返回,不会创建新的字符串对象。

如果在常量池中不存在该常量,那么就将该常量添加到常量池中,并返回常量池字符串的地址。

这样的赋值方式会产生[0-1]个字符串对象。


2:String str = new String("123");

首先对字符串常量"123",进行扣留机制的判断。可能产生[0-1]个对象。

new 出来的String  对象在堆区中被创建。 新的String 对象中的成员  value 指向 常量池中的字符串地址。


这样的创建对象的方式会产生[1-2]个对象。


要求:使用第一种创建字符串对象的方式。


1240


public class TestInternString {


public static void main(String[] args) {

//产生了一个字符串对象 a ,在常量池中

String a = "a";

//产生了一个字符串对象 b ,在常量池中

String b = "b";

//产生了一个字符串对象 ab ,在常量池中

String s1 = "ab";

//编译之后 和 a和b 合并,没有产生 字符串对象,直接指向方法区 "ab";

String s2 = "a"+"b";

//会产生一个新的对象,指向堆的。 涉及到字符串变量的+连接的实现。

String s3 = a + b;

//在堆中产生一个新的对象

String s4 = new String("ab");

//如果"ab" 字符串 已经存在于 常量池中,那么直接返回 常量池的地址。

//如果“ab” 不存在于常量池中。那么就将"ab" 在运行期动态的添加到常量池,并返回常量池字符串的地址。

//intern 将当前字符串对象动态的添加到常量池中,并返回在常量池中的地址。

String s5 = new String(a+b).intern();

System.out.println(s1 == s2);//true

System.out.println(s1 == s3);//false

System.out.println(s1 == s4);//false

System.out.println(s1 == s5);//true

}

}


四、StringBufferStringBuilder

StringBuffer:

可以修改的字符串对象。可以认为是一个增强版的String。

在原有的String的功能上面(有些功能没有),增加了对字符串序列的增删改。

底层使用char[] 数组实现。


StringBuilder是在某些情况下的替代StringBuffer 类的一个类。和StringBuffer类的用法完全一样。API 兼容。


StringBuffer  是线程安全的。

效率相对较低。

StringBuilder 是线程非安全的。

效率更高。


总结:在线程安全的情况下使用StringBuilder


例:

/**

 * 对于指定的一个字符串,将该字符串的统计表示形式[asdasdasd---a(3)s(3)d(3)]保存到一个StringBuffer中,并最后打印输出。

 * 思路:逐个遍历字符串中的每个字符,将统计的结果放到一个StringBuffer中,如果被遍历的字符还没有出现在

 * StringBuffer 中,则在StringBuffer中尾部添加该字符并在该字符后增加 (1) ,如果已经存在 与StringBuffer

 * 则将该字符后的小括号中的字符串取出,转换为int,然后+1后,再插入原位置。 最后返回StringBuffer的字符串形式。

 */

public static String countTypeChar(String str){

if(str == null)

return null;

if(str.isEmpty())

return "";

int len = str.length();

StringBuffer sb = new StringBuffer();

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

char c = str.charAt(i);

//得到c 在 sb 中的 位置

int index = sb.indexOf(Character.toString(c));

//c 已经存在sb 中了。那么将原有的数量获得,并删除,加1 之后插入回去。

if(index >=0 ){

//先获得sb 中c 的数量

//数量的起始索引,和结束索引

int start = index + 2;//当前字符的右边的第二个符号

int end = sb.indexOf(")", start);

//获得当前字符的在sb 中 数量的值

int count = Integer.parseInt(sb.substring(start, end));

//删除 数量 字符串 

sb.delete(start, end);

//原有数量+1 插入回去

count ++;

sb.insert(start, Integer.toString(count));

}else{//不在sb 中 尾部添加 即可

sb.append(c+"(1)");

}

}

return sb.toString();

}


五、String类的 + 连接的实现

/**

 * String 类的+ 连接实现

 *

 */

public class TestStringBuffer1 {


public static void main(String[] args) {

String a = "a";

//直接指向常量池

String b = "a" + "b";

//变量 相加 或者是 变量和常量相加 底层使用StringBuilder 实现。

//在StringBuilder 没有出来之前,使用StringBuffer 实现 + 连接。

String c = a + b + "a";

String str = new  StringBuilder(a).append(b).append("a").toString();

}

}


六、字符串连接性能测试

public class TestStringConcat {


public static void main(String[] args) {

long time = System.currentTimeMillis();

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

concat6("rewrewrewfewrewfdwefewfrewfew", "32lkfjklwejrl2o3kdlemfrl243kj", "fjoweurolenmflkdnmvklsdnlkfew",

"fu98u798rjhoifdjiefldsfjdskljfvcd", "9123ljkrlemwfklmwe,.fm c,.dmv", "23oirjelkfmnkdslnmvkldsnmvdsklmnfds");

}

long cost = System.currentTimeMillis()-time;

System.out.println("cost = " + cost);

}

//210ms  会创建6个StringBuilder 对象

static String concat1(String s1,String s2,String s3,String s4,String s5,String s6){

String str = "";

str += s1;

str += s2;

str += s3;

str += s4;

str += s5;

str += s6;

return str;

}

//95  线程安全的,创建了一个StringBuffer 对象,存在多次扩容的行为

static String concat2(String s1,String s2,String s3,String s4,String s5,String s6){

StringBuffer sb = new StringBuffer();

sb.append(s1).append(s2).append(s3).append(s4).append(s5).append(s6);

return sb.toString();

}

//85 线程非安全的,创建了一个StringBuilder 对象,存在多次扩容的行为

static String concat3(String s1,String s2,String s3,String s4,String s5,String s6){

StringBuilder sb = new StringBuilder();

sb.append(s1).append(s2).append(s3).append(s4).append(s5).append(s6);

return sb.toString();

}

//62 创建了一个StringBuilder对象,存在多次扩容

static String concat4(String s1,String s2,String s3,String s4,String s5,String s6){

return s1 + s2 + s3 + s4 + s5 + s6;

}

//67 创建一个StringBuffer 对象,不存在扩容行为

static String concat5(String s1,String s2,String s3,String s4,String s5,String s6){

StringBuffer sb = new StringBuffer(s1.length()+s2.length() + s3.length() + s4.length() + s5.length() +s6.length());

sb.append(s1).append(s2).append(s3).append(s4).append(s5).append(s6);

return sb.toString();

}

//48 创建一个StringBuilder 对象,不存在扩容行为

static String concat6(String s1,String s2,String s3,String s4,String s5,String s6){

StringBuilder sb = new StringBuilder(s1.length()+s2.length() + s3.length() + s4.length() + s5.length() +s6.length());

sb.append(s1).append(s2).append(s3).append(s4).append(s5).append(s6);

return sb.toString();

}

}

 

七、File

一个File对象既可以表示一个文件,也可以表示一个目录。


提供了对文件对象和目录对象的各种操作的方法。


对文件的操作:

创建文件

删除文件

修改文件的属性,不能修改文件的内容。

判断是文件还是目录

得到目录下是所有的文件对象。

创建目录,删除目录

判断文件或者目录是否存在

获得文件的绝对路径。

获得文件的名字

重命名文件

......


绝对路径:相对于盘符的路径。

相对路径:相当于当前工程根目录。

 

例:

import java.io.File;

import java.io.IOException;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.Date;


public class TestFile {


// 在相对路径中创建1.txt 文件 工程目录下

// 在c盘的根目录下创建文件2.txt, 并修改其修改的时间 1970-05-20 13:14:20。

// 在c盘的根目录下创建文件c:/7/7/2.txt

// 将指定的目录下的,指定的后缀的文件全部删除

// 使用递归将某个目录下的所有的文件以及子目录中的文件 文件的个数的统计。

// 使用递归实现,将指定的目录以及其子目录全部删除。

public static void main(String[] args) {

// 从当前系统动态获得的路径分隔符 和 目录分隔符

System.out.println(File.pathSeparator);// ;

System.out.println(File.separator);// \


// deleteFilesBySuffix("c:\\class\\501", "class");

test2();

}


// 在res 的相对目录中,创建 或者删除指定的文件

static void test1() {

File file = new File("." + File.separator + "res" + File.separator

+ "1.txt");

if (file.exists()) {// 文件存在,删除,

file.delete();

else {// 不存在,创建新的

try {

file.createNewFile();

catch (IOException e) {

e.printStackTrace();

}

}

}


// 在c盘的根目录下创建文件2.txt, 并修改其修改的时间 1970-05-20 13:14:20。

static void test2() {

File file = new File("F:\\2.txt");

if (!file.exists()) {

try {

file.createNewFile();

catch (IOException e) {

e.printStackTrace();

}

}

// 修改 time 要求是 距离 1970 年1月1日 的毫秒的时间差

try {

file.setLastModified(Long

.parseLong(dateToStamp("1970-05-20 13:14:20")));

catch (NumberFormatException e) {

e.printStackTrace();

catch (ParseException e) {

e.printStackTrace();

}

// file.lastModified()

}


// 在c盘的根目录下创建文件c:/7/7/2.txt

static void test3() {

File file = new File("c:\\88\\88");

// 先创建目录

// file.mkdir() 只能创建一层

file.mkdirs();


// 再创建文件

File file2 = new File(file, "2.txt");

if (!file2.exists()) {

try {

file2.createNewFile();

catch (IOException e) {

e.printStackTrace();

}

}

}


/**

*删除指定目录下的指定的后缀的文件

 *

 * @param path

 * @param suffix

 */

static void deleteFilesBySuffix(String path, String suffix) {

File file = new File(path);

// 得到当前目录下的所有的文件

File[] files = file.listFiles();

// 遍历所有的文件,如果文件的名字以suffix 结尾 就删除

for (File file2 : files) {

// 获得文件的名字

String name = file2.getName();

if (name.endsWith(suffix)) {

file2.delete();

}

}

}


/*

 * 将时间转换为时间戳

· public static String dateToStamp(String s) throws ParseException {

String res;

SimpleDateFormat simpleDateFormat = new SimpleDateFormat(

"yyyy-MM-dd HH:mm:ss");

Date date = simpleDateFormat.parse(s);

long ts = date.getTime();

res = String.valueOf(ts);

return res;

}

}

 

1240

网友评论

登录后评论
0/500
评论
winniehu
+ 关注