保证类只能创建出一个对象——单例模式
单例模式创建对象
类构造器私有(private) 不让外部类调用此类构造器函数
类内部 new类,创建对象 自己创建一个对象
提供公开静态方法 通过类名调用静态方法
把自己创建的对象 通过这个静态方法返回
饿汉式
提供私有构造函数[自行定义];
自己创建一个私有对象 [ 私有静态-- 存放置方法区 类加载时就被创建]
提供静态方法,通过类名调用这个静态方法来获取类实例化的对象
把创建的对象,通过这个静态方法返回
//单例模式 饿汉式
public class Demo1Singleton1 {
private static Demo1Singleton1 s1=new Demo1Singleton1();
// 在类加载是,对象就会被创建
private Demo1Singleton1(){
//私有化构造方法,静止外部直接创建对象
}
public static synchronized Demo1Singleton1 getInstance(){
//创建公开静态方法 便于外部调用
return s1;
}
}
class Test1{
public static void main(String[] args) {
//单例模式 饿汉式
Demo1Singleton1 t1=Demo1Singleton1.getInstance();
Demo1Singleton1 t2=Demo1Singleton1.getInstance();
System.out.println(t1==t2);//true
}
}
懒汉式
提供私有构造函数;[自行定义]
提供公开静态方法 通过类名调用静态方法
定义一个静态变量
在静态方法中做判断,静态变量为null,则创建对象[new 类];不为null,则返回静态变量[对象]
//单例模式 懒汉式
class Singleton2{
private static Singleton2 s2;// 定义一个私有静态的变量 默认值为null
private Singleton2(){
//构建私有的构造函数
}
public static synchronized Singleton2 getInstance(){
if(s2==null)
s2=new Singleton2(); //提供公开静态方法
//只有在调用静态方法时,才考虑是否创建对象
return s2;
}
}
class Test1{
public static void main(String[] args) {
//单例默认 懒汉式
Singleton2 t3=Singleton2.getInstance();
Singleton2 t4=Singleton2.getInstance();
System.out.println(t3==t4);//true
}
}
面试题-单例模式写个冒泡排序
第一, 类满足单例模式
第二, 提供排序方法 [对象调用此方法]
//利用单例写个冒泡排序
//类满足单例
//提供排序方法 对象调用方法
class Singleton3{
//类满足单例
private static Singleton3 s3=new Singleton3();
private Singleton3(){
}
public static synchronized Singleton3 getInstance(){
return s3; //实例化 获取对象
}
//提供排序方法
public int[] maoPao(int[] a){
for (int i=0;i<a.length-1;i++)
for(int j=0;j<a.length-1-i;j++){
if(a[j]>a[j+1]){
int t=a[j];
a[j]=a[j+1];
a[j+1]=a[j];
}
}
return a;
}
}
class Test1{
public static void main(String[] args) {
//利用单例模式写个冒泡排序
int[] a=null;
int[] a1={2,3,1,4,6,5};
//获取单例对象
Singleton3 t5=Singleton3.getInstance();
//对象调用方法
int[] m1=t5.maoPao(a);
System.out.println(Arrays.toString(m1));
int[] m2=t5.maoPao(a1);
System.out.println(Arrays.toString(m2));
}
}
单例模式:一个类只有一个对象被创建(只实例化一次),这种类就满足单列模式
非单例:一个类可创建出多个对象,就是非单例
实例化:创建对象的过程,就是实例化 例如new 类型()
synchronized关键字: 同步;一次只允许一个调用这个方法
String类中的方法使用
字符串.indexOf()
字符串.indexOf(子串)
字符串.indexOf(子串) 找到某个字符串在原字符串的位置
找到就返回这个指定字符串[首字符位置],找不到就返回-1
public static void main(String[] args) {
String str="abtomcdtomefto1tom2tom";
//"tom" 是一个子字符串
//找到字符串tom
//字符串.indexOf(子串) 找到某个字符串在原字符串的位置
//找到就返回这个指定字符串[首字符位置],找不到就返回-1
int i = str.indexOf("tom"); //2
int i1 = str.indexOf("tom1"); //-1
}
字符串.indexOf(子串,n) 从指定位置开始找
public static void main(String[] args) {
String str="abtomcdtomefto1tom2tom";
//"tom" 是一个子字符串
//从指定位置开始找
//字符串.indexOf(子串,n) 从指定位置开始找
int i2=str.indexOf("tom",3);//7
//统计"tom"的个数
int a=-1;
int count=-1;
do {
count++;
a=str.indexOf("tom",a+1);
}while (a!=-1);
System.out.println("统计tom的个数:"+count);
}
字符串.lastIndexOf(),从后往前找
字符串. lastIndexOf(字符串)
从后往前找,找到最后一个出现的字符串的索引位置;
若未找到,返回-1
public static void main(String[] args) {
String str="abtomcdtomefto1tom2tom";
//"tom" 是一个子字符串
//lastIndexOf(字符串)
//从后往前找,找到最后一个出现的字符串的索引位置;若未找到,返回-1
System.out.println(str.lastIndexOf("tom"));//19
}
字符串. lastIndexOf(字符串,index)
字符串. lastIndexOf(字符串,index),从后往前 指定位置[结尾位置]
public static void main(String[] args) {
String str="abtomcdtomefto1tom2tom";
//"tom" 是一个子字符串
//lastIndexOf(字符串,index),从后往前 指定位置[结尾位置]
System.out.println(str.lastIndexOf("tom",6));//2
}
索引超出范围,依旧返回-1
字符串.substring(); 截取子字符串
s.substring(起始位置); 指定起始位置,默认到结尾
String s="tomjackalicerose";
System.out.println(s.substring(0));//tomjackalicerose
s.substring(起始位置,末尾位置);
s.substring(起始位置,末尾位置),指定起始位置到[末尾-1位置];
包含前面,不包含后面
System.out.println(s.substring(0,3));//tom
int i=s.indexOf("jack");
System.out.println(s.substring(i,i+"jack".length()));//jack
System.out.println(s.substring(s.indexOf("rose"),s.indexOf("rose")+"rose".length()));//rose
三个字母为一组截取为子字符串,保存在字符数组中
方法一
String str="abcdefghigklmn";
String[] n=new String[0];
int m=0;
int m1=3;
for(int i1=0;i1<str.length();i1=i1+3){
String sub;
if(i1+3>str.length())
sub=str.substring(i1);
else{
sub=str.substring(i1,i1+3);
};
n= Arrays.copyOf(n,n.length+1);
n[n.length-1]=sub;
}
System.out.println(Arrays.toString(n));
方法二
String str="abcdefghigklmn";
String[] n=new String[0];
while (true){
if(str.length()>3){
n= Arrays.copyOf(n,n.length+1);
n[n.length-1]=str.substring(0,3);;
str=str.substring(3);
}
else {
n= Arrays.copyOf(n,n.length+1);
n[n.length-1]=str.substring(0);;
break;
}
}
System.out.println(Arrays.toString(n));
字节数组 & 字符编码
utf-8, 一个中文字符三个字节
gbk , 一个中文两个字节
public static void main(String[] args) throws Exception{
String str = "中国你好";
byte[] bytes = str.getBytes();
// 没有指定编码,就看当前软件使用的编码方式
System.out.println(Arrays.toString(bytes) + "----" + bytes.length);
byte[] bytes1 = str.getBytes("utf-8"); // 一个中文字符三个字节
byte[] gbks = str.getBytes("gbk"); // 一个中文两个字节
System.out.println(Arrays.toString(bytes1) + "----" +
bytes1.length);
System.out.println(Arrays.toString(gbks) + "----" + gbks.length);
byte[] bytes2 = str.getBytes(StandardCharsets.UTF_8);
//StandardCharsets.UTF_8 -- 常量
// 字符串的构造函数
String str1 = new String("hello");
String str2 = new String(gbks);
// gbks中存的是gbk编码获取的字节数组, 类使用的utf-8编码
str2 = new String(gbks , "gbk");
System.out.println(str2); // 乱码
char[] c = {'a','b','c'};
String str3 =new String(c);
System.out.println(str3);
}
正则表达式
正则表达式的介绍
可以出现的字符
[] 任意一个字符
[abc] a、b、c中任意一个
[^] 除此以外的任意一个
[^abc] 除a、b、c以外的任意一个
[a-z && [^bc] ] 在a-z中除b、c的任意一个
可以出现的字符简写
. 任意一个字符
\d 任意一个数字字符[0-9]
\D 任意一个非数字字符 [^0-9 ]
\s 空白字符
\S非空白字符
\w 任意一个单词字符[a-zA-z0-9]
\W 任意一个非单词字符
字符串出现的次数限定
X? 表示0个或1个X
X* 表示0个或任意多个X
X+ 表示1个或任意多个X
X{n} 表示n个X
X{n,} 表示n个到任意多个[大于等于n]
X{n,m} 表示n个到m个X[大于等于n个且小于m个X]
其他规定
String中正则表达式的使用
regex : 正则
能出现哪些字符
出现的次数
特殊规定:限定开始,限定结尾
全局查询,忽略大小写
split()方法
split()方法,把字符串按照指定的分隔符,分割为字符串数组
String str="aa12321bb3434cc1dd343ee33";
String regex="[0-9]{1,}";
String regex1="[^0-9]{1,}";
String[] split = str.split(regex);
String[] split1 = str.split(regex1);
System.out.println(Arrays.toString(split));
//[aa, bb, cc, dd, ee]
System.out.println(Arrays.toString(split1));
//[, 12321, 3434, 1, 343, 33]
//2023.8.3转换2023-8-3
String year="2023.8.3";
regex="\\.";
String[] ys=year.split(regex);
System.out.println(ys[0]+"-"+ys[1]+"-"+ys[2]);
//2023-8-3
“0123456789”,变成0-1-2-3-4-5-6-7-8-9
String old="0123456789";
regex="";//数字直接有间隔 空字符串
String[] split2 = old.split(regex);
String s="";
for(int i=0;i<split2.length;i++){
s+="-"+split2[i];
}
s=s.substring(1);//去掉首字符
System.out.println(s);//0-1-2-3-4-5-6-7-8-9
replaceAll()方法
replaceAll()方法,把正则匹配的内容,替换为指定的字符串
“abtomcdtomefto1tom2tom” tom替换为TOM
String s2="abtomcdtomefto1tom2tom";
regex="tom";
//replaceAll(regex, 替换为str)
String tom = s2.replaceAll(regex, "TOM");
old="你妈最近身体好吗,你妹妹最近考上了那个大学.我最喜欢的明星范冰冰,我妈妈也是,因为演技好.";
// regex="妈{1,}|妹{1,}|冰{1,}";
regex="[妈妹冰]{1,}";
String newStr=old.replaceAll(regex,"***");
System.out.println(newStr);
//你***最近身体好吗,你***最近考上了那个大学.我最喜欢的明星范***,我***也是,因为演技好.
StringBuffer & StringBuilder
StringBuffer
StringBuffer封装可变的字符串, StringBuffer对象创建后,可以通过调用方法,修改字符串的内容
StringBuffer构造器函数
public StringBuffer();
public StringBuffer(String str);
StringBuffer提供的操作字符串的方法: append , insert , delete ,replace,reverse等
StringBuffer提供的很多方法,返回值是StringBuffer (return this ),所以支持链式操作
StringBuffersb = new StringBuffer(“a”);
sb.append(“b”).append(“b”)........
StringBuilder
StringBuilder封装可变的字符串, StringBuilder对象创建后,可以通过调用方法,修改字符串的内容。
StringBuilder构造器函数
public StringBuilder();
public StringBuilder(String str);
StringBuilder提供的很多方法,返回值是StringBuilder (return this ) , 所以支持链式操作:
StringBuilder sb = new StringBuilder(“a”);
sb.append(“b”).append(“b”)........
方法使用
append–末尾追加
insert–插入,指定位置之前
delete–删除
replace–替换
reverse–反转
public static void main(String[] args) {
StringBuilder sb=new StringBuilder();
//追加append()
sb.append("今天天气很好");
System.out.println(sb);//今天天气很好
//指定位置之前插入insert()
sb.insert(2,"是星期四");
System.out.println(sb.toString());//今天是星期四天气很好
//替换replace()
int i=sb.indexOf("星期四");//索引
sb.replace(i,i+"星期四".length(),"XQS");//今天是XQS天气很好
System.out.println(sb);
//删除 delete()
i=sb.indexOf("是XQS");
sb.delete(i,i+"是XQS".length());//今天天气很好
System.out.println(sb);
//反转 reverse()
sb.reverse();
System.out.println(sb);//好很气天天今
}
判断 "上海自来水来自海上"是否回文
String str="上海自来水来自海上";
//判断 "上海自来水来自海上"是否回文
StringBuilder sb1=new StringBuilder();
sb1.append(str);
sb1.reverse();
if(str.equals(sb1.toString()))//两个字符串比较
System.out.println("是回文");
else
System.out.println("不是回文");
String、StringBuilder和StringBuffer的区别
执行速度来看:String<StringBuffer<StringBuilder
String 类
不可变性: String 对象一 旦被创建,其值就不可更改
每次对string 进行修改(如拼接、裁剪等操作)都会产生一个新的String 对象,原来的对象不变这会导致频繁的对象创建,可能会对性能产生影响
线程安全
由于string 对象不可变,它是线程安全的,可以在多线程环境下共享而无需担心数据致性问题
StringBuffer 类
可变性: StringBuffer 是可变的
可以对其进行增删改查操作而不会创建新的对象,这使得在频繁操作字符串时,更加高效,尤其是涉及大量拼接操作时
.线程安全:
StringBuffer 是线程安全的,所有的方法都经过同步处理,因此可以在多线程环境下使用,但是同 步可能会带来些性能开销
StringBuilder
可变性: StringBuilder 也是可变的,类似于StringBuffer
可以对其进行增删改查操作,但与StringBuffer不同,StringBuilder 并没有进行同步处理,因此在单线程环境下执行操作会更快
线程不安全
由于没有同步处理,StringBuilder 不适合在多线程环境下共享,因为可能导致数据不一致的问题
今日学习题:
给定一个字符串编码规则,如输入字符串"Y3E12S!3",字母后面的数字表示该字符重复几次。
如果字符后没有数字则表示一个字符,最终输出转码后的字符串’ YYYEEEEEEEEEEEES !!!’
试写出转码的函数
将两个字母之间的数字取出
方法一:计数[双层循环]
public static String one(String str){
String newStr=""; //存放每一次数字
String newStr1=""; //最终字符串
int pre=0; //记录每一次数字前的字母位置
int i=0;//循环的次数
int count=0;//控制里层循环遇见两次不是数字就终止
boolean b=true;
while (b){//死循环
do {//找出数字
if(i<=str.length()-1){
if(!(str.charAt(i)>='0' && str.charAt(i)<='9')){
count++;
if (count==1) //记录数字前字符的位置
pre=i;
}
else{
newStr+=str.charAt(i);//一直是数字就加在一次
}
i++;//下标累加,直到遇见第二个字符结束
}
else{
b=false; //小标已经超出长度,则字符已遍历完,结束循环
break;
}
}while (count<2);
if(newStr.equals("")){
newStr1+=str.charAt(pre); //如果数字为""则两个字母连着,没有数字
}
else{
newStr1+=String.valueOf(str.charAt(pre)).repeat(Integer.parseInt(newStr));
//String.valueOf(str.charAt(pre)) 先把字符通过记录下标找出来,再转换为字符串类型
//Integer.parseInt(newStr) 将字符串转换为Integer类型的数字
//String1.repeat(Integer.parseInt(newStr));将该字符串重复newStr次数
}
count=0; //找到一次清零,继续下一次寻找
newStr="";//找到一次清零,继续下一次寻找
i--; //内层循环退出时,i多加了,所以需要i--;
if (!b)//b为false则遍历结束
break;
}
System.out.println(newStr1);
return newStr1;
}
方法二:正则
public static String two(String str){
String regex="[0-9]{1,}";
String regex1="[^0-9]{1,}";
String[] split = str.split(regex);
//取出字符串中所以的数字,有序保存为数组 //[, 8, 12, 15, 4, 4]
String[] split1 = str.split(regex1);
//取出字符串中所有的非字符串的数,有序保持为数组 //[YE, S , H, T, T!!]
//由于数字数组首位不要,且需要对最后面做判断
String newStr="";
for (int i=0;i<split.length;i++){
if(i+1>split1.length-1){
newStr+=split[split.length-1];
break;
}
else
newStr+=split[i].substring(0,split[i].length()-1)+split[i].substring(split[i].length()-1).repeat(Integer.parseInt(split1[i+1]));
}
System.out.println(newStr);
return newStr;
}