1 Java核心API
API(Application Programming Interface,应用程序接口)是一些预先定义的函数,或指软件系统不同组成部分衔接的约定。 目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问原码,或理解内部工作机制的细节。
1.1 Object
- public class Object
Class Object是类Object结构的根。 每个类都有Object作为超类。 所有对象(包括数组)都实现了这个类的方法。
1.2 包装类:
- Java程序中基本类型的变量可以直接在常量池中读取字面量。常量池也就是方法区的一部分,是内存的逻辑分区。
- 基本类型的包装类Byte,Short,Integer,Long,Character,Boolean都实现了常量池技术
- 什么时候使用常量池?
Byte,Short,Integer,Long,Character这5种整型的包装类
在自动装箱拆箱过程中,只有是在数值byte范围内(-128,127)时候,才使用常量池,否则都是分配新的内存空间。
案例:
Integer i1=new Integer(1);
Integer i2=new Integer(1);
//i1,i2对象具有不同的内存地址
System.out.println(i1==i2);//输出false
Integer i3=1;
Integer i4=1;
//i3,i4指向常量池中同一个字面值,即同一个内存位置,因此下面语句返回true
System.out.println(i3==i4);//输出true
Integer i3=1234;
Integer i4=1234;
//i3,i4 int的值大于127或者小于-128,那么变量不会引用常量池中的字面量
System.out.println(i3==i4);//输出false
源码的体现:
Integer内部类实现了Integer类型常量数组,类加载的时候,static静态代码段执行初始化-128到127之间的Integer对象,存放到cache数组中。Cache属于常量,存储于java的方法区内。
池化技术主要用于减少对象的数量,以减少内存占用和提高性能。Byte Short Integer Long Character Boolean都实现了池化技术。
1.3 String&常量池
Class String
java.lang.Object
1.3.1 字符串特性:
字符串可以用两种方式赋值,且有一个非常重要的特征,即不可变性;
一旦一个字符串被创建后,它的值就不能被修改
String s1 = "QQ1";
s1 = "QQ2";
QQ1仍然还在原来的存储区域,不过是新开辟了一块空间赋值了World,然后s1的地址指向World
- 常量池概念:
1.重用一些不变的字符串
2.凡是用=号直接赋值的方法得到字符串,都在常量池,相同则共用一个具体字符串
3.new创建的字符串一定是分配新的内存空间
1.3.2 常见API:
1.3.3 常见方法:
startsWith:
endsWith:
equals:
valueOf:
split:
1.3.4 课堂练习:
有一个字符串 “hello,java,Hello,world”,使用字符串处理方法处理后,结果为: “HelloJavaHelloWorld”
public class Stest {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 用户输入一个邮箱地址:knouwn@foxmail.com
// 基本校验:要求有只有一个@;要求至少包含一个. ,这个、要在@的后面,不能直接和|@相邻. 不能在最后一位
// 我们根据用户输入的邮箱,得到其用户名 得到的是@前面的字符串knowno
System.out.println("请输入你的邮箱!");
// 错误次数
int count = 4;
// 循环允许错误次数,重新输入
for (int j = 0; j <= 3; j++) {
// 控制台输入
Scanner input = new Scanner(System.in);
String i = input.next();
//@ 不能没有 . 不能没有
if (i.indexOf('@') != -1 && i.indexOf('.') != -1
//@ 的下标要比 . 小
&& ((i.indexOf('.') - i.indexOf('@')>1))
//@ . 不能是第一个
&& i.lastIndexOf('@') != 0
&& i.lastIndexOf('.') != 0
//@ . 不能是最后一个 @就不用了,上面有限制@的下标了
&& i.lastIndexOf('.') != i.length()-1
//@ . 只能有一个
&& (i.indexOf('.') == i.lastIndexOf('.'))
&& (i.indexOf('@') == i.lastIndexOf('@'))) {
String result = i.substring(0, i.indexOf('@'));
System.out.println(result);
break;
} else {
count--;
System.err.print("输入的邮箱格式不规范,请重新输入!");
System.err.print("目前还有" + count + "次输入机会");
}
}
}
}
}
}
用户输入一个邮箱地址:knouwn@foxmail.com
基本校验:要求有只有一个@;要求至少包含一个. ,这个、要在@的后面,不能直接和|@相邻. 不能在最后一位
public class Stest {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 我们根据用户输入的邮箱,得到其用户名 得到的是@前面的字符串knowno
System.out.println("请输入你的邮箱!");
// 错误次数
int count = 4;
// 循环允许错误次数,重新输入
for (int j = 0; j <= 3; j++) {
// 控制台输入
Scanner input = new Scanner(System.in);
String i = input.next();
//@ 不能没有 . 不能没有
if (i.indexOf('@') != -1 && i.indexOf('.') != -1
//@ 的下标要比 . 小
&& ((i.indexOf('.') - i.indexOf('@')>1))
//@ . 不能是第一个
&& i.lastIndexOf('@') != 0
&& i.lastIndexOf('.') != 0
//@ . 不能是最后一个
&& i.lastIndexOf('.') != i.length()-1
&& i.endsWith("@")
//@ . 只能有一个
&& (i.indexOf('.') == i.lastIndexOf('.'))
&& (i.indexOf('@') == i.lastIndexOf('@'))) {
String result = i.substring(0, i.indexOf('@'));
System.out.println(result);
break;
} else {
count--;
System.err.print("输入的邮箱格式不规范,请重新输入!");
System.err.print("目前还有" + count + "次输入机会");
}
}
}
}
1.3.5 直接赋值:
public void t1() {
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);
}
返回值为true。
以上代码采用字面值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在"hello"这个对象。
public void t2() {
String str3 = new String("hello");
String str4 = new String("hello");
System.out.println(str3 == str4);
}
没有用常量池,每次都分配新的空间,指向一个新的hello;
1.3.6 判断输出结果。
String str = “ILoveJava”;
String str1 = “I”;
String str2 = “Love”;
String str3 = “Java”;
System.out.println(str == (str1 + str2 + str3));// 堆 false
String str4 = "I" + "Love" + "Java";//字面值拼接 池
System.out.println(str == str4);// true
反汇编,我们发现,控制代码中
str1 + str2 + str3
StringBuilder.append();
StringBuilder.append();
package day16;
/**
- 进阶版: 字符串特性,池,以及JVM优化
- @author Administrator
*/
public class TestString5 {
public static void main(String[] args) {
String str = “ILoveJava”;
String str1 = “I”;
String str2 = “Love”;
String str3 = “Java”;
//一种是使用引用名进行拼结
//前方高能:
//false JVM做了自动优化,使用StringBuilder进行了拼接(append); 堆
System.out.println(str == (str1 + str2 + str3));
//一种是使用"字面值",处理就是"常量池"中
String str4 = "I" + "Love" + "Java";
System.out.println(str == str4);
}
}
1.3.7 字符串常见方法:
//子串截取相关方法:
String s = "helqoo";
//从0开始数
//输出从第一个字符开始的字符e elqo
System.out.println(s.substring(1));
//输出从第2个字符l开始的,到4-1=3个字符q为止,就是lq
System.out.println(s.substring(2,4));
System.out.println("*********************");
String a = "BeijingETC";
//截取e在字符串中的位置(第一次出现)
System.out.println(a.indexOf('a'));
//截取e在字符串中的位置(最后一次出现)
System.out.println(a.lastIndexOf('e'));
//返回从在第三个字符以后,j的第一次出现位置
System.out.println(a.indexOf('j', 3));
//返回第一次出现字符串jing的
System.out.println(a.indexOf("jing"));
//返回从第四个字符开始,第一次出现字符串jing的,没有所以是false
System.out.println(a.indexOf("jing",4));
//返回字符串中第四个字符,注意是从0开始数
System.out.println(a.charAt(4));
System.out.println("*********************");
String b = " A C E";
char c = 'c';
boolean bl = true;
char arr[] = {'1','2','3'};
String end = "atfaewgawe";
System.out.println(b.trim());
System.out.println(String.valueOf(b));
System.out.println(String.valueOf(c));
System.out.println(String.valueOf(bl));
System.out.println(String.valueOf(arr));
System.out.println(String.valueOf(arr, 1, 2));
System.out.println(end.endsWith("e"));
System.out.println(end.startsWith("a"));
实践应用:
模拟邮箱验证
// 用户输入一个邮箱地址:knouwn@foxmail.com
// 基本校验:要求有只有一个@;要求至少包含一个. ,这个、要在@的后面,不能直接和|@相邻. 不能在最后一位
// 我们根据用户输入的邮箱,得到其用户名 得到的是@前面的字符串knowno
System.out.println("请输入你的邮箱!");
// 错误次数
int count = 4;
// 循环允许错误次数,重新输入
for (int j = 0; j <= 3; j++) {
// 控制台输入
Scanner input = new Scanner(System.in);
String i = input.next();
//@ 不能没有 . 不能没有
if (i.indexOf('@') != -1 && i.indexOf('.') != -1
//@ 的下标要比 . 小
&& ((i.indexOf('.') - i.indexOf('@')>1))
//@ . 不能是第一个
&& i.lastIndexOf('@') != 0
&& i.lastIndexOf('.') != 0
//@ . 不能是最后一个 @就不用了,上面有限制@的下标了
&& i.lastIndexOf('.') != i.length()-1
//@ . 只能有一个
&& (i.indexOf('.') == i.lastIndexOf('.'))
&& (i.indexOf('@') == i.lastIndexOf('@'))) {
String result = i.substring(0, i.indexOf('@'));
System.out.println(result);
break;
} else {
count--;
System.err.print("输入的邮箱格式不规范,请重新输入!");
System.err.print("目前还有" + count + "次输入机会");
}
}
1.3.8 StringBuffer:
StringBuffer 线程同步的。
任务:
分别使用String,StringBuffer,StringBuilder完成字符串对象创建,拼接,体会区别;
String 不可变
StringBuilder 可变 单线程 不安全
StringBuffer 可变 多线程 安全
1.4 数学API
static double pow(double a, double b)
将第一个参数的值返回到第二个参数的幂。
static double random()
返回值为 double值为正号,大于等于 0.0 ,小于 1.0 。
1.4.1 随机数+数组:
BigDecimal d1 = new BigDecimal(4.3);
BigDecimal d2 = new BigDecimal(5.8);
System.out.println(d1.add(d2).setScale(2, BigDecimal.ROUND_HALF_DOWN));
1.5 随机API –》Random类
//随机数0 - 10 ,10取不到
//写法1:Math.random()
//int random = (int)(Math.random()*7);
//写法2:实例化Random对象再调方法
Random r = new Random();
int random = r.nextInt(6)+1;
1.6 UUID
- UUID是通用唯一识别码(唯一机器生成的标识符)
- 可以被序列化
- 有自然顺序
- 不能是人工生成(风险太高)
- 16字节128位长的数字,通常以36字节的字符创串表示
- 通常在生成分布式系统中用来生成唯一ID;
import java.util.UUID;
public class TestUUID {
public static void main(String[] args) {
//生成UUID码
UUID uuid = UUID.randomUUID();
System.out.println(uuid);
//还要设置其他,暂时不好用
UUID uuid1 = new UUID(0, 100);
System.out.println(uuid1);
}
}
1.7 日期API
1.7.1 Date:
Java.util.Date类表示时间,在JDK1.1后推荐使用Calendar类,且只剩两个没过时的构造:
对象创建
//创建 Date对象(正常创建)
Date date = new Date();
System.out.println(date);
//使用当前时间构建Date对象
Date();
//使用long类型的值构建Date对象
Date(long date)
1.7.2 Calendar:
对象创建
//对象创建采用类.getInstance();
Calendar c = Calendar.getInstance();
c.set(2017, 12, 18);
System.out.println(c);
在这里插入代码片
1.8 JDK1.8 API:
日期中有很多static final 修饰的方法,所以不能直接实例化对象,但是这些方法提供了特殊方法,可以调用来创建对象
1.8.1 LocalDate:
- JDK1.8后有,用来表示日期(不包含时间)格式为:yyyy-MM-dd
//使用当前时间生成LocalDate对象
LocalDate.now();
//使用预设的时间生成LocalDate对象
LocalDate.of(year, month, dayOfMonth)
//返回年、月、日字段值
getYear(); getMonthValue(); getDayOfMonth()
案例:
import java.time.LocalDate;
public class TestLocalDate {
public static void main(String[] args) {
// TODO Auto-generated method stub
//得到LocalDate对象date1
LocalDate date1 = LocalDate.now();
System.out.println("date1:" + date1);
//得到LocalDate对象date2
LocalDate date2 = LocalDate.of(2020, 10, 10);
System.out.println("date2:" + date2);
String str = "2020-10-10";
//CharSequence -> String
LocalDate date3 = LocalDate.parse(str);
System.out.println("返回年字段值:" + date3.getYear());
System.out.println("返回月字段值::" + date3.getMonthValue());
System.out.println("返回日字段值::" + date3.getDayOfMonth());
}
}
1.8.2 LocalTime:
- JDK1.8后有,用来表示时间(不包含日期)格式为:HH-mm-ss
//使用当前时间生成LocalTime对象
LocalTime.now();
//使用预设的时间生成LocalTime对象
LocalTime.of(hour, minute, second)
//返回年、月、日字段值
getHour(); getMinute(); getSecond()
案例:
import java.time.LocalTime;
public class TestLocalTime {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 得到LocalTime对象time1
LocalTime time1 = LocalTime.now();
System.out.println("time1:" + time1);
// 得到LocalTime对象time2
LocalTime time2 = LocalTime.of(17,30,00);
System.out.println("time2:" + time2);
String str1 = "06:30:00";
// CharSequence -> String
LocalTime time3 = LocalTime.parse(str1);
System.out.println("返回小时字段值:" + time3.getHour());
System.out.println("返回分钟字段值:" + time3.getMinute());
System.out.println("返回秒字段值:" + time3.getSecond());
}
}
1.8.3 时间格式转换:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class TestDateTimeFormatter {
public static void main(String[] args) {
// 得到LocalDate对象
LocalTime time = LocalTime.now();
System.out.println(time);
LocalDate ldate = LocalDate.now();
System.out.println(ldate);
System.out.println("*********LocalDate LocalTime LocalDateTime ==> String*******************");
DateTimeFormatter format1 = DateTimeFormatter.ofPattern("yyyy/MM/dd");
System.out.println(ldate.format(format1));
System.out.println("********************");
DateTimeFormatter format2 = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(time.format(format2));
System.out.println("********* String ==>LocalDate LocalTime LocalDateTime *******************");
String str2 = "15点25分";
DateTimeFormatter time1Formater = DateTimeFormatter.ofPattern("HH点mm分");
LocalTime time2 = LocalTime.parse(str2, time1Formater);
System.out.println("time2:" + time2);
String str3 = "2020年11月11日";
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
LocalDate date2 = LocalDate.parse(str3, dateFormatter);
System.out.println("date2:" + date2);
}
}
1.8.4 包装类方法的进制转换:
二进制:toBinaryString
八进制:toOctalString
十六进制:toHexString
System.out.print("二进制:");
System.out.println(Integer.toBinaryString(64));
System.out.print("八进制:");
System.out.println(Integer.toOctalString(64));
System.out.print("十六进制:");
System.out.println(Integer.toHexString(64));
1.8.5 练习:
- 分别创建 Date对象和Calendar对象,体会二者的不同
//创建Date对象
Date date = new Date();
System.out.println(date);
//创建Calendar对象
Calendar c = Calendar.getInstance();
c.setTime(date);
System.out.println(c);
- 学会二者相互转换: Date<->Calendar
//Date -> Calendar
Calendar c = Calendar.getInstance();
c.setTimeInMillis(date.getTime());
System.out.println(c);
//Calendar->Date
Calendar c1 = Calendar.getInstance();
Date d1 = c1.getTime();
System.out.println("d1:" + d1);
- 得到一个时间的输出结果为: 2020年10月29日 (时间格式转换)
方法1:
//输出一个时间的结果为2020年10月29日
int year = c1.get(Calendar.YEAR);
int month = c1.get(Calendar.MONTH);
int day = c1.get(Calendar.DATE);
System.out.println(year + "年" + month + "月" + day + "日");
方法2:
我们希望把一个字符串转换为时间格式:
就两个方法:
SimpleDateForamt:
Format 将时间转换为字符串
Parse 将字符串转换为时间Date (要异常处理)
String inputDate = "2020-10-29 14:17:12";
//Format 将时间转换为字符串
SimpleDateFormat s1 = new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
//Parse 将字符串转换为时间Date (要异常处理)
Date d3 = s1.parse(inputDate);
System.out.println(d3);
1.9 总结1:
- Java.lang.Object的常见方法
equals,hashCode(),toString()等 - Java.lang.String的常见方法
String——length(),equals(Object),substring();valueOf()
StringBuilder——append
StringBuffer——(synchronized)append - Java.lang.Math的常见方法
静态方法:random() - Java.lang系统默认导入的
1.10 system
java.lang.object
Static final 静态、常量
public final class System
extends Object
System类包含几个有用的类字段和方法,不能被实例化
//毫秒
system.out.print(System.currentTimeMillis());
//纳秒
system.out.print(System.nanoTime());
1.11 class
java.lang.Object
java.lang.Class
反射还会用到
作用:
1.可以表示任何其他类型
2.可以构建其他类的对象
3.类似透视
实例化对象的方法(并用c引用名完成一些调用)
//得到class对象
Class c = Class.forName("包名.类名");
//调用方法
c.newInstance();
除此之外,还有
//类.class
Class c1 = Apple.class;
//返回值类型是class类型
//native方法(只能调用)
//对象.getClass方法
Class c2 = "".getClass();
类型判断
if(obj instanceof Human){}
初步类型转换
package package11;
import java.util.Scanner;
public class TestClass{
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
// 包.类名
Class c = Class.forName("package11.Apple");
//通过c来完成一些调用
Object obj = c.newInstance();
//需要将Object转换为Apple
Apple apple = (Apple)obj;
//调用Apple的方法
apple.show();
}
}
class Apple{
public void show() {
System.out.println("我要开始秀了!");
}
}
应用场景
eg:控制台输入完成某个类,使用Class对象得到某个类的对象
package package11;
import java.util.Scanner;
public class TestClass {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
System.out.println("请输入类型:包.类名");
String str = input.next();
//Class.forName("day19.Apple") 返回值为Class类型的对象
Class c = Class.forName(str);
//通过c来完成一些调用
Object obj = c.newInstance();
System.out.println(obj);
}
}
class Apple{
public void show() {
System.out.println("我要开始秀了!");
}
}
1.12 内部类(❥四个类)
主要分为: 成员内部类、局部内部类、静态内部(static)类、匿名内部类
格式:(会生成两个字节码文件OuterClass.class和OuterClass$InnerClass.class)
//外部类
public class OuterClass{
//内部类
public class InnerClass1{
}
protected class InnerClass1{
}
class InnerClass1{
}
private class InnerClass1{
}
}
- 成员内部类
要注意的点
1.成员内部类中不能存在任何Static类的变量和方法
2.成员内部类依附于外围类,所以是先有外围类再有内部类
这里要注意构建成员内部内的形式(步骤)
1.首先构建外部类对象
2.以外部类.内部类的形式进行声明
3.以外部类对象.new内部类构造方法()的方式构建对象
public class OuterClass {
private String name;
private int age;
//内部类
public class InnerClass{
//构造方法
public InnerClass() {
name = "白菜";
age = 23;
}
//普通方法
public void display() {
System.out.println("name:"+name+"age:"+age);
}
}
//主程序
public static void main(String[] args) {
// TODO Auto-generated method stub
//构建内部类的形式
//1.首先构建外部类对象
OuterClass outerClass = new OuterClass();
//2.以外部内.内部类的形式进行声明
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
//3.以外部内对象.new内部类构造方法()的方式构建对象
innerClass.display();
}
}
- 局部内部类
内部类定义在了方法的内部,只能在方法体里面使用
这边的 display() 外部不能访问,只能在 InnerClass 里使用
//内部类
public class InnerClass{
//构造方法
public InnerClass() {
name = "白菜";
age = 23;
}
//普通方法
//display方法外部不能访问
public void display() {
System.out.println("name:"+name+"age:"+age);
}
}
- 静态内部类
1.创建不需要依赖外部类
2.不能使用任何外部类的非static成员变量和方法
3.static内部类能够声明static的成员(和成员内部类不同)
//静态内部类
public class OuterClass {
private int age;
private static String name = "白菜静态外部";
//内部类
static class InnerClass{
//这里可以定义成静态成员
public static String staticName = "白菜静态内部";
//普通方法
public void display() {
System.out.println("name:"+ name);
}
}
public void display() {
System.out.println(InnerClass.staticName);
new OuterClass.InnerClass().display();
//static内部类构建对象时不需要依赖外部类的对象,可以不写外部类对象OuterClass
// new InnerClass().display();
}
//主程序
public static void main(String[] args) {
// TODO Auto-generated method stub
OuterClass Outer = new OuterClass();
Outer.display();
}
}
- 匿名内部类
1.如果一类内部类仅需要构建一个单一的对象,那么这个类其实并不需要额外取一个特有的名字,对于不存在名字的内部类,我们称为匿名内部类
2.匿名内部类必须继承一个父类或实现一个接口
3.匿名内部类没有构造方法(没有显式类名)
4.匿名内容类可以交由类初始化或实例初始化代码块来完成初始化工作
5.匿名内部类对类成员、方法临时变量的访问规则和具备名字的内部类保持一致
匿名内部类的声明使用方法如下:
[访问权限] [修饰符]父类名/接口名 引用名 = new 父类名/接口名([父类构造方法参数列表]){
匿名内部类成员;
}
IFoo foo = new IFoo() { };
//匿名内部类
public class OuterClass {
private int age;
private String name = "白菜静态外部";
//这就是匿名内部类!
IFoo foo = new IFoo() {
public void display() {
System.out.println("name:"+name);
}
};
//主程序
public static void main(String[] args) {
// TODO Auto-generated method stub
OuterClass o = new OuterClass();
o.foo.display();
}
}
interface IFoo {
public void display();
}
1.把内部类当成是外部类的成员
2.内部类可以很方便的访问外部类的成员,反之不行(外部类不能访问内部类的属性)
3.折中解决了Java不可以支持多继承的问题(完善多重继承)(通过内部继承其他父类来实现多继承)以及形成闭包
4.方法内部定义的
1.13 总结1:
- 非常重要:String
- StringBuffer,StringBuilder
- 随机数:Random
类型转换:nextInt(int n)——包括0但是不包括n - UUID
- Date和Calendar
- 转换时间格式和字符串类: SimpleDateFormat
1.14 回顾API知识点:
1.14.1 基本类型和包装类型对照表:
基本类型 byte int char boolean float double long short
包装类型 Byte Integer Character Boolean Float Double Long Short
1.14.2 如何将字符串转换为数字格式?
String str = “128”;
String str = "128";
//Integer a1 = new Integer(a);
//这里转成数字格式
int num =Integer.parseInt(str);
System.out.println(num);
1.14.3 Java.util.Date如何转换为字符串?反之呢?
将时间格式 -> 指定格式的字符串 “yyyy-MM-dd”
SimpleDateFormat
//时间格式化
//创建SimpleDateFormat对象
SimpleDateFormat s1 = new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
//创建日期对象,得到当前时间
Date d1 = new Date();
//将日期对象进行格式化输出
System.out.println(s1.format(d1));
将 指定格式的字符串 “yyyy-MM-dd” -> 时间格式
SimpleDateForma
//时间格式化
//创建SimpleDateFormat对象
SimpleDateFormat s1 = new SimpleDateFormat("YYYY-MM-dd hh:mm:ss");
//创建日历对象,指定时间2017-12-18 9:09:09
Calendar c1 = Calendar.getInstance();
c1.set(2017, 12, 18, 9, 9,9);
//将日历对象用getTime方法转换Date对象,使用format格式化输出
System.out.println(s1.format(c1.getTime()));
1.14.4 String、StringBuilder和StringBuffer有什么区别
String | StringBuilder | StringBuffer | |
---|---|---|---|
是否可变 | 只读字符串,不可变 | 可以直接修改 | 可以直接修改 |
使用特殊情况 | 单线程使用(没有被synchronized修饰,效率比StringBuffer高) | 被synchronized修饰,线程安全 |