StringBuffer类
String
类的特征
- 每一个字符串的常量都属于一个
String
类的匿名对象, 并且不可更改 -
String
有两个常量池: 静态常量池, 运行时常量池 -
String
类对象实例化建议直接赋值的形式完成, 这样可以直接将对象保存在对象池之中以方便下次重用 -
String
最大的弊端: 内容不允许修改,StringBuffer
允许修改
String与StringBuffer的对比
StringBuffer
并不像String
类那样拥有两种对象实例化方式, StringBuffer必须像普通类对象那样首先进行对象实例化而后可以调用方法执行处理
构造方法
public StringBuffer();
数据追加
public StringBuffer append(数据类型 变量) // 相当于字符串中的 "+" 操作
所有的 "+" 在编译以后都变成了StrngBuffer
中的append()
方法, 并且在程序之中StringBuffer和String可以相互转换:
-
String
类对象变为StringBuffer
可以依靠StringBuffer
类的构造方法或者用append()
方法 - 所有的类对象都可以通过
toString()
转成String
类对象
StringBuffer
常用方法
1.插入数据
public StringBuffer insert(int offset, 数据类型 b)
public static void main(String[] args) {
StringBuffer buf = new StringBuffer();
buf.append("哈哈哈哈").insert(0, "yyyy").insert(4, "xxx");
System.out.println(buf);
}
2.删除数据
public StringBuffer delete(int start, int end)
public static void main(String[] args) {
StringBuffer buf = new StringBuffer();
buf.append("哈哈哈哈").insert(0, "yyyy").insert(4, "xxx").delete(2, 6);
System.out.println(buf);
}
3.字符串翻转
public StringBuffer reverse()
public static void main(String[] args) {
StringBuffer buf = new StringBuffer();
buf.append("哈哈哈哈").append("yyyy").reverse();
System.out.println(buf);
}
实际上与StringBuffer
类还有一个类似的功能类StringBuilder
类.StringBuffer
是线程安全类, 方法全部使用了synchronized
关键字修饰, 而StringBuilder
类不是.
String
, StringBuffer
和StringBuilder
三者的区别
-
String
类是字符串的首选类型, 其最大的特点是内容不允许改变 -
StringBuffer
与StringBuilder
允许修改 -
StringBuffer
是在JDK 1.0
的时候提供的, 属于线程安全的操作, 而StringBuilder
是在JDK1.5
提供的不属于线程安全的操作
CharSequence
CharSequence
是一个描述字符串结构的接口, 在这个接口里一般有三种常用的子类
String类 |
StringBuffer类 |
StringBuilder类 |
---|---|---|
public final class String extends Object implemens Serializable, Comparable |
public final class StringBuffer extends Object implemens Serializable, CharSequence |
public final class StringBuilder extends Object implemens Serializable, CharSequence |
现在只要有字符串就可以为
CharSequence
接口实例化.
CharSequence
本身就是一个接口, 在该接口之中也定义了如下的操作方法
- 获取指定索引字符:
public char charAt(int index);
- 获取字符串的长度:
public int length();
- 截取部分字符串:
public CharSequence subSequence(int start, int end)
AutoCloseable
主要用于实现资源的自动关闭(释放资源)
- 关闭方法:
public void close() throws Exception;
注意事项 - 要想实现自动关闭处理, 除了要使用
AutoCloseable
之外, 还需要结合有异常处理语句才可以正常调用
Runtime类
Runtime
描述的事运行时的状态, 也就是在整个JVM
中, Runtime
类是唯一一个与JVM
运行状态有关的类, 并且会默认提供一个该类的实例化对象.
由于在一个JVM
进程只允许有一个Runtime
类的对象, 所以类的构造方法被私有化, Runtime
类使用的是单例设计模式
由于是单例设计模式, 如果想获取实例化对象, 那么就要依靠类中的getRuntime()
方法完成.
- 获取实例化对象:
public static Runtime getRuntime();
- 获取最大可用内存空间:
public long maxMemory()
// 默认配置为本机系统内存的1/4 - 获取可用内存空间:
public long totalMemory()
// 默认配置是本机系统的1/64 - 获取空闲内存空间:
public long freeMemory()
- 手工进行GC处理:
public void gc()
System类
- 数组拷贝:
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
- 获取当前的日期时间数值:
public static long currentTimeMillis();
- 进行垃圾回收:
public static void gc();
利用currentTimeMillis
获取操作耗时
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 0; i < 30000; i++) {
System.out.println("i");
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
System也提供了一个gc
方法, 这个方法并不是重新定义的新方法, 而是继续执行了Runtime
类中的gc
方法.
对象克隆
所谓的对象克隆, 其实就是深复制, 用已有对象的内容创建一个新的对象. 需要使用到Object类中提供的clone
方法:
protected Object clone() throws CloneNotSupportedException;
所有的类都会继承Object
父类, 所以所有的类都一定有clone()
方法, 如果想实现对象克隆, 那么对象所在的类需要实现一个Cloneable
接口
class Eg implements Cloneable {
private int age;
private String name;
public Eg(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "[" + super.toString() + "]" + ", age:" + this.age + ", name:" + this.name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Main {
public static void main(String[] args) throws Exception {
Eg eg = new Eg("A", 20);
Eg egs = (Eg)eg.clone();
System.out.println(eg);
System.out.println(egs);
}
}
Math数学计算类
Math
构造方法被私有化, 但是并不是单例, 所有的方法均是static
.都可以通过类名直接调用.
Random随机数生成类
- 产生一个不大于边界的随机数(正整数和0):
public int nextInt(int bound)
大数字处理类
大数字处理类可以实现海量数字的计算(能提供的也只是基础计算),
大数字处理类分为两种:
-
BigInteger
BigInteger
类构造:public BigInteger(String val);
-
BigDecimal
BigDecimal
类构造:public BigDecimal(String val);
两个类均继承Number
类
四则运算
public static void main(String[] args) throws Exception {
BigInteger bigA = new BigInteger("273827382738927837");
BigInteger bigB = new BigInteger("273827382738927837");
System.out.println(bigA.add(bigB)); // 加法
System.out.println(bigA.subtract(bigB)); // 减法
System.out.println(bigA.multiply(bigB)); // 乘法
System.out.println(bigA.divide(bigB)); // 除法
BigInteger result [] = bigA.divideAndRemainder(bigB);
System.out.println("商:" + result[0] + ", 余数:" + result[1]);
}
Date日期处理类
Date
类的构造方法
public Date() {
this(System.currentTimeMillis());
}
public Date(long date) {
fastTime = date;
}
获取当前日期
public static void main(String[] args) throws Exception {
Date date = new Date();
System.out.println(date);
}
获取当前时间戳
public static void main(String[] args) throws Exception {
long currentTime = new Date().getTime();
System.out.println(currentTime);
}
将时间戳转为日期
public static void main(String[] args) throws Exception {
long time = 1563375702346L;
Date date = new Date(time);
System.out.println(date);
}
SimpleDateFormat
构造方法: public SimpleDateFormat(String pattern);
格式化日期
- 日期格式化:
public final String format(Date date);
- 将字符串转为日期:
public Date parse(String source) throws ParseException;
日期格式
年(yyyy)-月(MM)-日(dd) 时(HH):分(mm):秒(ss).毫秒(SSS)
将当前时间格式化
public static void main(String[] args) throws Exception {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println(format.format(date));
}
将某个时间转为日期
String str = "2019-07-17 22:57:36.029";
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date date = fmt.parse(str);
System.out.println(date);
将某个时间戳格式化
public static void main(String[] args) throws Exception {
long time = 1563375702346L;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println(format.format(time));
}
将某个日期转成时间戳
public static void main(String[] args) throws Exception {
String str = "2019-07-17 22:57:36.029";
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date date = fmt.parse(str);
System.out.println(date.getTime());
}
NumberFormat(货币格式化)
public static void main(String[] args) throws Exception {
double money = 2829839389d;
String moneyStr = NumberFormat.getInstance().format(money);
System.out.println(moneyStr);
}
输出
2,829,839,389
UUID类
UUID 根据时间戳生成一个无重复的字符串定义.
- 获取UUID对象:
public static UUID randomUUID();
- 根据字符串获取UUID对象:
public static UUID fromString(String name);
public static void main(String[] args) throws Exception {
UUID uuid = UUID.randomUUID();
String uuidStr = uuid.toString();
uuid = UUID.fromString(uuidStr);
System.out.println(uuidStr);
System.out.println(uuid);
}
Optional
可以实现null
的处理操作, 提供了以下的操作方法:
- 返回空数据:
public static
Optional empty(); - 获取数据:
public T get();
- 保存数据, 但是不允许出现
null
:public static
Optional of(T value); - 如果在保存数据的时候存在
null
, 则会抛出NullPointerException
异常;
- 如果在保存数据的时候存在
- 保存数据, 允许为空:
public static
Optional ofNullable(T value); - 空的时候返回其他数据:
public T orElse(T other)
ThreadLocal
ThreadLocal
主要用于解决多线程资源引用传递的问题, 很多地方叫做线程本地变量,也有些地方叫做线程本地存储, 即按照线程来存储数据.
- 构造方法
public ThreadLocal();
- 设置数据
public void set(T value);
- 取出数据
public T get();
- 删除数据
public void remove();
问题代码
三个线程发送三个消息.
class Message { // 要发送的消息体
private String info;
public void setInfo(String info) {
this.info = info;
}
public String getInfo() {
return info;
}
}
class Channel { // 消息的发送通道
private static Message message;
private Channel() {}
public static void setMessage(Message m) {
message = m;
}
public static void send() {
System.out.println("[" + Thread.currentThread().getName() + ", 消息发送" + message.getInfo());
}
}
public class JavaAPIDemo {
public static void main(String[] args) {
new Thread(()->{
Message msg = new Message();
msg.setInfo("发送消息A");
Channel.setMessage(msg);
Channel.send();
}, "线程A").start();
new Thread(()->{
Message msg = new Message();
msg.setInfo("发送消息B");
Channel.setMessage(msg);
Channel.send();
}, "线程B").start();
new Thread(()->{
Message msg = new Message();
msg.setInfo("发送消息C");
Channel.setMessage(msg);
Channel.send();
}, "线程C").start();
}
}
输出结果(跑几次)
[线程A, 消息发送发送消息A
[线程B, 消息发送发送消息A
[线程C, 消息发送发送消息C
问题产生: 多个线程之间的消息产生了相互影响, 主要的原因是Channel
中的message
使用的是static
定义的, 在B线程先给message
赋值, 尚未发送的时候, A线程重新赋值, 然后A线程发出, B线程发出, 导致出现问题
在不改变代码结构的情况下需要使用ThreadLocal
解决这个问题, 代码如下:
class Message { // 要发送的消息体
private String info;
public void setInfo(String info) {
this.info = info;
}
public String getInfo() {
return info;
}
}
class Channel { // 消息的发送通道
private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
private Channel() {}
public static void setMessage(Message m) {
THREAD_LOCAL.set(m); // 想ThreadLocal中保存数据
}
public static void send() {
System.out.println("[" + Thread.currentThread().getName() + ", 消息发送:" + THREAD_LOCAL.get().getInfo());
}
}
public class JavaAPIDemo {
public static void main(String[] args) {
new Thread(()->{
Message msg = new Message();
msg.setInfo("发送消息A");
Channel.setMessage(msg);
Channel.send();
}, "线程A").start();
new Thread(()->{
Message msg = new Message();
msg.setInfo("发送消息B");
Channel.setMessage(msg);
Channel.send();
}, "线程B").start();
new Thread(()->{
Message msg = new Message();
msg.setInfo("发送消息C");
Channel.setMessage(msg);
Channel.send();
}, "线程C").start();
}
}
输出结果, 不论运行多少次, 线程和消息都可以一一对应
[线程B, 消息发送:发送消息B
[线程A, 消息发送:发送消息A
[线程C, 消息发送:发送消息C
定时调度
定时器的主要操作就是定时任务的处理, 只是实现了一种间隔出发的操作.
如果想要实现定时的处理操作, 主要需要有一个定时操作的主体类, 以及定时任务的控制, 可以使用两个类来控制
-
java.util.TimerTask
类: 实现定时任务处理 -
java.util.Timer
类: 进行任务的启动- 任务启动:
public void schedule(TimerTask task, long delay); //delay为延时, 延时的单位是毫秒
- 间隔触发:
public void scheduleAtFixedRate(TimerTask task, long delay, long period);
- 任务启动:
class myTask extends TimerTask {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": " + System.currentTimeMillis());
}
}
public class JavaAPIDemo {
public static void main(String[] args) {
Timer timer = new Timer();
// 定义间隔任务, 1000毫秒后开始执行, 每次执行1次, 周期为1000毫秒
timer.scheduleAtFixedRate(new myTask(), 1000, 1000);
}
}
Base64
since: JDK1.8
-
Base64.Encoder
: 进行加密处理- 加密处理:
public byte[] encode(byte[] src);
- 加密处理:
-
Base64.Decoder
: 进行解密处理- 解密处理:
public byte[] decode(String src);
- 解密处理:
public static void main(String[] args) {
String msg = "这是需要加密的字符串";
String encMsg = new String(Base64.getEncoder().encode(msg.getBytes()));
System.out.println("encMsg:" + encMsg);
String decMsg = new String(Base64.getDecoder().decode(encMsg.getBytes()));
System.out.println("decMsg:" + decMsg);
}
最好的加密应该增加盐值, 并且盐值先加密, 最后使用2-3种加密方式.
比较器
系统类型(Integer
, String
)数组比较, 一般使用sort()
. 自定义对象比较, 一般使用比较器.
Comparable比较器
实现一个Person
类, 比较年纪
class Person implements Comparable {
private String name;
private int age;
public Person(String name, int age) {
this.age = age;
this.name = name;
}
@Override
public int compareTo(Person o) {
return this.age - o.age;
}
@Override
public String toString() {
return "姓名:" + this.name + ", 年龄:" + this.age;
}
}
public class JavaAPIDemo {
public static void main(String[] args) {
Person perA = new Person("小强A", 26);
Person perB = new Person("小强B", 126);
Person perC = new Person("小强C", 86);
Person list [] = new Person[] {
perA,
perB,
perC
};
Arrays.sort(list);
System.out.println(Arrays.toString(list));
}
}
Comparator比较器
Comparator
是一种挽救的比较器支持, 目的是解决一些没有使用Comparable
排序的类的数组排序操作.
比如上面的Person
类并没有继承Comparable
, 在Person
类本体不被修改的情况下, 需要进行排序
class PersonComparator implements Comparator {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.age = age;
this.name = name;
}
public int getAge() {
return this.age;
}
public String getName() {
return this.name;
}
@Override
public String toString() {
return "姓名:" + this.name + ", 年龄:" + this.age;
}
}
public class JavaAPIDemo {
public static void main(String[] args) {
Person perA = new Person("小强A", 26);
Person perB = new Person("小强B", 126);
Person perC = new Person("小强C", 86);
Person list [] = new Person[] {
perA,
perB,
perC
};
Arrays.sort(list, new PersonComparator());
System.out.println(Arrays.toString(list));
}
}
排序尽量使用Comparable
.
Comparable
与Comparator
的区别
-
java.lang.Comparable
是在类定义的时候实现的父接口, 主要用于定义排序规则, 里面只有一个compareTo
的方法 -
java.util.Comparator
是挽救的比较器操作, 需要单独设置比较器规则类实现排序, 里面有compare
方法.