Java中使用String类表示字符串数据,只要使用双引号引用的数据都是字符串,也就是String这个类的一个实例(对象、个体)。
String s = “abc” ;
字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。
String s = "abc";
String s2 = "abc";
当我们将字符串"abc" 表示出来之后,在程序运行的时候,那么就会在方法区的字符串常量池中,后续程序中如果需要使用,直接将整个字符串的对象在常量池中的引用赋值给别引用变量。
String类提供大量的构造方法,有助于在程序快速的将不同的数据转成字符串数据。
public class StringDemo2 {
public static void main(String[] args) {
String s = "abc";
String s2 = "abc";
System.out.println( s );
System.out.println( s2 );
System.out.println( s == s2 );
// s3和s4它们分别指向堆中不同的String对象
// new的String对象中有引用指向常量池中的"abc"对象
String s3 = new String( "abc" );
String s4 = new String( "abc" );
System.out.println( s3 );
System.out.println( s4 );
System.out.println( s3 == s4 );
}
}
public class StringDemo3 {
public static void main(String[] args) throws UnsupportedEncodingException {
byte[] b = {65,66,67,98,102};
// 将byte数组中的数字(编码值)转成字符数据
String s = new String(b , "utf-8" );
System.out.println(s);
char[] chs = {'A','你','好','B','C'};
String s2 = new String(chs , 1 , 3);
System.out.println(s2);
}
}
只要是对字符串操作,首先需要想到String类。
/*
* 统计字符串中指定的某个字符出现的次数
*/
public class StringDemo {
public static void main(String[] args) {
String s = "sdfhsaknzxbmxbrk234rfnfnkjds";
int count = 0;
// 统计'a'的次数
// 1、遍历取出每个字符
for( int i = 0 ; i < s.length() ; i++ ) {
// 2、取出字符
char ch = s.charAt(i);
// 3、判断取出的字符是否与统计的相同
if( ch == 'n' ) {
count++;
}
}
System.out.println(count);
}
}
/*
* 统计子串在长串中出现的次数
*/
public static void demo2() {
String s = "neusoftabcneusoftedneusoftfabcneusoft";
String s2 = "neusoft";
// String中的切割方法
String[] strs = s.split(s2);
//System.out.println(strs.length);
//
int cnt = 0;
int startIndex = 0;
while( ( startIndex = s.indexOf(s2, startIndex) ) != -1 ) {
cnt++;
startIndex = startIndex + s2.length();
}
System.out.println(cnt);
}
/*
* 在一个串中是否包含其他的字符串
*/
private static void demo3() {
String s = "abcABCdef";
String s2 = "ABC";
// indexOf
int index = s.indexOf(s2);
if( index == -1 ) {
System.out.println("不包含");
}else {
System.out.println(s2+"存在于字符串");
}
// contains 判断一个串是否在另外一个串中
boolean b = s.contains(s2);
if( b ) {
System.out.println("包含");
}else {
System.out.println("不包含");
}
}
/*
* 判断两个串的大小
*/
private static void demo4() {
String s = "abbbbbbbbbb";
String s2 = "abc";
/*
* 用两个字符串上相同位置的字符的编码值进行减法运算,返回对应的正数、零、负数
*/
int x = s.compareTo(s2);
System.out.println(x);
}
/*
* 比较两个字符串是否相同
*/
private static void demo5() {
String s = "abcd";
String s2 = "aBCD";
// 严格区分大小写的比较
boolean b = s.equals(s2);
System.out.println(b);
// 忽略大小写比较
boolean b2 = s.equalsIgnoreCase(s2);
System.out.println(b2);
}
/*
* ==和equals的区别
* == : 属于关系(比较)运算符 , 它比较的具体的值
* 针对基本类型:== 比较的两个值是否相同,
* 针对引用类型:== 比较的两个引用的内存地址(引用)值
*
* equals:它本质上属于Object类中的方法,只是一般所有的子类都会复写equals方法。
* public boolean equals(Object obj) {
* return (this == obj);
* }
* 在Object类中的equals依然在使用== 比较两个对象是否相同,
* 而在实际相同中,需要复写Object类中equals方法,
* 然后根据当前类中的一些属性数据确定两个对象是否相同。
*
* 结论:值得比较使用 == , 对象的比较使用equals
*/
private static void demo6() {
String s = "abcd";
String s2 = "aBCD";
System.out.println(s == s2);
s.equals(s2);
}
// 判断是否以指定的内容开始或者结尾
private static void demo7() {
String filename = "abc.avi";
// 判断字符串的后缀
boolean b = filename.endsWith(".avi");
System.out.println(b);
// 判断是否以指定的字符串开始
boolean b2 = filename.startsWith("张三");
System.out.println(b2);
}
// String中的转换的方法
private static void demo8() throws UnsupportedEncodingException {
String s = "abcDEF一二三";
// 字符串中的字母字符全部转成大写
String upperCase = s.toUpperCase();
System.out.println(upperCase);
// 字符串中的所有字母字符全部转成小写
String s3 = s.toLowerCase();
System.out.println(s3);
// 字符串转成字符数组
char[] chs = s.toCharArray();
for (int i = 0; i < chs.length; i++) {
System.out.print(chs[i]+" ");
}
System.out.println();
/*
* 字符串转成字节数组:
* 在使用getBytes方法将某个字符串转成字节数据的时候,
* 如果没有指定编码表,会使用当前项目的默认编码表将字符串中的每个字符转成对应的编码值
*
* GBK:每个汉字2个字节
* UTF-8:每个汉字3个字节
*/
byte[] bs = s.getBytes("GBK");
for (int i = 0; i < bs.length; i++) {
System.out.print(bs[i]+" ");
}
System.out.println();
}
编码和解码一定都要使用相同的编码表,否则可能出现乱码。
// 编码和解码
private static void demo9() throws UnsupportedEncodingException {
// 编码
String s = "你好";
byte[] bs = s.getBytes("utf-8");
for (int i = 0; i < bs.length; i++) {
System.out.print( bs[i] + ",");
}
System.out.println();
// 解码
byte[] bys = {-28,-67,-96,-27,-91,-67};
String s2 = new String( bys , "gbk" );
System.out.println(s2);
}
乱码解决
// 乱码的解决
private static void demo10() throws UnsupportedEncodingException {
String s = "浣犲ソ";
// 编码
byte[] bs = s.getBytes("gbk");
// 解码
String s2 = new String(bs , "utf-8");
System.out.println(s2);
// 上面的乱码处理合并
String s3 = new String( s.getBytes("gbk") , "utf-8" );
System.out.println(s3);
}
// 字符串的截取操作
private static void demo11() {
// 加入身份证号码
String s = "361234202002021234";
// 需要从中截取出出生年月日
String year = s.substring(6, 10);
String month = s.substring(10, 12);
String day = s.substring(12,14);
System.out.println(year+"年"+month+"月"+day+"日");
}
由于字符串是常量不能改变,因此在程序中经常需要对字符串进行操作,这时如果直接使用String类中的部分方法操作,其实是在内存中不断的生成新的字符串。其中就会存在部分字符串没有使用价值。
在JDK中提供的字符串缓冲区,它主要目的是对字符串进行CRUD操作。
缓冲区:临时存储数据的空间。然后可以在临时区域中对数据进行更改操作。
字符串缓冲区:
StringBuffer:它是final修饰,不能被继承。
/*
* 创建字符串缓冲区对象
*/
private static void demo1() {
// 创建字符串缓冲区对象,其中没有任何的字符数据
StringBuffer sb = new StringBuffer();
sb.append("abcdefg1234");
// length() : 容器中字符个数
int len = sb.length();
System.out.println(len);
// capacity() : 当前容器能够存放的最大值
int capacity = sb.capacity();
System.out.println(capacity);
}
/*
* 字符串缓冲区中的添加方法
*/
private static void demo2() {
StringBuffer sb = new StringBuffer();
// 调用append是给缓冲区的后面添加数据
sb.append('A');
sb.append(12);
sb.append(3.14);
sb.append("neu");
// 在缓冲区指定的位置上添加数据
sb.insert(3, "BB");
// 字符串缓冲区操作完之后,一般都需要将数据统一转成一个字符串
String s = sb.toString();
System.out.println(s);
}
/*
* 删除和修改
*/
private static void demo3() {
StringBuffer sb = new StringBuffer("neusoft");
// 删除指定位置上的字符
sb.deleteCharAt(1);
System.out.println(sb.toString());
// 从指定start的位置删除到end位置
sb.delete(1, 3);
System.out.println(sb.toString());
// 修改指定位置上的字符数据
sb.setCharAt(0, 'A');
System.out.println(sb.toString());
// 反转字符串
sb.reverse();
System.out.println(sb.toString());
}
// 替换
private static void demo4() {
StringBuffer sb = new StringBuffer(" neu so ft ");
//sb.replace(0 , 2, "NEU");
System.out.println(sb.toString());
sb.trimToSize();
System.out.println(sb.toString());
String s = " neu soft ";
// trim是String中的一个方法,用于去除字符串收尾的空白
// 会生成一个新的串
String s2 = s.trim();
System.out.println(s);
System.out.println(s2);
}
/**
* 实现对传递的字符串进行明文使用MD5算法加密操作
* @author Administrator
*/
public class MD5Utils {
/**
* 对数据value进行加密的时候,还需要额外的辅助数据,防止相同的明文加密后的密文相同
* @param value 被加密的数据
* @param salt 辅助的数据
* @return 密文
*/
public static String getMD5( String value , String salt) {
StringBuffer sb = new StringBuffer();
sb.append(value.substring(0, value.length()/2));
sb.append(salt.substring(0, value.length()/2));
sb.append(value.substring(value.length()/2));
sb.append(salt.substring(value.length()/2));
return getMD5(sb.toString());
}
/**
* 对传递进来的value数据进行加密
* @param value 被加密的明文数据
* @return 返回加密后的密文数据
*/
public static String getMD5( String value ) {
try {
// JDK中定义
MessageDigest md = MessageDigest.getInstance("md5");
// 加密 后数组中存放16个byte类型的数据
byte[] bs = md.digest( value.getBytes() );
// 使用字符串缓冲区来进行密文的拼接操作
// 每个byte类型的数据需要转成一个十六进制的值
// 一个byte , 8 个二进制数位,正常应该转后是2个十六进制数位的数据
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bs.length; i++) {
// x 值有可能是0~15的数字,转后只有一个十六进制数位
int x = bs[i];
// 首先需要将x全部转成正数或零
int y = x & 0b1111_1111;
String s = Integer.toHexString(y);
if( y >= 0 && y <= 15 ) {
sb.append("0");
sb.append(s);
}else {
sb.append(s);
}
}
return sb.toString();
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
public class Demo {
public static void main(String[] args) {
String md5 = MD5Utils.getMD5("abc");
System.out.println(md5);
// 获取到产生唯一标识的uuid对象
UUID uuid = UUID.randomUUID();
String id = uuid.toString().replaceAll("-", "");
System.out.println(id);
String s = MD5Utils.getMD5("abc" , id );
UUID uuid2= UUID.randomUUID();
String id2 = uuid2.toString().replaceAll("-", "");
System.out.println(id2);
String s2 = MD5Utils.getMD5("abc" , id2 );
System.out.println(s);
System.out.println(s2);
}
}
适配器:将不合适的一些数据转成可以被直接使用的数据。
适配器设计模式:针对接口进行过渡的,当一个接口中的方法大于等于2个的时候,一般都建议给这个接口提供一个适配器类,这时如果程序中需要使用接口,不建议直接去实现接口,而是继承接口的适配器类。在自己的子类中复写需要使用的某个方法即可。