一、字符串类
字符串的概念
- 字符串是一系列字符的序列,也就是说字符串是由字符组成的。在Java语言中字符串是由一对双引号括起来的字符序列。例如:”您好”, “hello”
- 在Java语言中不论字符串常量还是字符串变量,都是用类来实现的。
- 字符串中可以包括>=0个字符,如果是0个字符,就表示字符串对象存在,但是没有包含任何字符。
- Java语言中字符串分为两类:一类是字符串创建之后不能再做修改和变动的字符串String;一类是字符串创建之后可以再做修改和变动的字符串StringBuilder。
字符串对象的创建
创建字符串对象的步骤与创建其他类的对象一样,也是两个步骤:
格式一: String 变量名; 变量名 = new String(字符串);
例如: String str; str = new String(“apple”);
格式二:也可以将其合并为一个语句,String 变量名 = new String(字符串);
例如: String str = new String(“apple”);
注:String str = new String(“apple”);创建的是2个对象
格式三 String 变量名 = 字符串常量;
例如: String str = “Apple”;
注:格式一和格式二,它们和格式三之间在存储方式上存在不同。使用new关键字创建对象,new表示申请内存空间。
字符串内存图
String类
String类继承于Object类,String类被final关键字修饰,不可被继承。String类内部结构是数组,对外提供了一系列的操作方法,比如比较、查找、删除、连接等等。String类是不可变字符序列。不可变指的是:一旦定义了一个String类的变量后,就不能在原有值的基础上进行修改(比如比较、查找、删除、连接等)。利用String类中的方法对字符串进行操作,都会产生一个新的String类副本。副本与原字符串是相互独立的,对副本或原字符串的修改不会影响到另一个。
String类的方法
还有一些其他的方法,比如:
- public boolean startsWith(String prefix) 从第一个位置开始判断是否以指定的内容开头
- public boolean startsWith(String prefix,int toffset) 从指定位置开始判断是否以指定内容开头
- public boolean endsWith(String suffix) 判断是否以指定的内容结尾
- public String replaceAll(String regex,String replacement) 替换指定的字符串
- public String replaceFirst(String regex,String replacement) 替换第一个满足条件的字符串
例子
public class StringCLass {
public static void main(String[] args) {
// 方法1:直接赋值
String s1 = "越努力越幸运";
// 方法2:使用new关键字创建对象,表示申请内存空间
String s2 = new String("越努力越幸运");
String s3 = "越努力越幸运";
System.out.println(s1 == s2);// false
System.out.println(s1 == s3);// true
// 考虑编译期和运行期,如果在编译期值可以确定,那么就直接使用已有的对象,否则创建新的对象
String a = "a";
String a1 = a + 1; //在堆中创建
String a2 = "a1";//在常量池中创建
System.out.println(a1 == a2);//false,因为在编译a1时a是变量,所以a的值是不可以确定的,只有在运行期a1的值是可以确定的
final String b="b";//final是常量,在编译期可以确定
String b1=b+1;//在编译期可以确定
String b2="b1";//在编译期可以确定
System.out.println(b1==b2);//true
String c=getC();//c是从方法区里getC方法获取的,方法是必须在运行期才能获得的,c在编译期不可以确定
String c1=c+1;//在编译期不可以确定
String c2="c1";//在编译期可以确定
System.out.println(c1==c2);//false
final String d=getD();//虽然d由final修饰,但d是从方法区里getD方法获取的,方法是必须在运行期才能获得的,d在编译期不可以确定
String d1=d+1;//在编译期不可以确定
String d2="d1";//在编译期可以确定
System.out.println(c1==c2);//false
}
private static String getC() {
return "c";
}
private static String getD() {
return "d";
}
}
如果用String来进行连接操作,用+来完成,会使得代码性能非常低,因为String的内容不可变,而StringBuffer可以解决这个问题。
StringBuffer类
- StringBuffer类与String类相似,都可以用来存储和处理字符串,但是,StringBuffer的内部实现方式和String不同,StringBuffer对象在进行字符串处理时,不产生新的对象,在内存占用上比String对象少。如果经常对一个字符串的内容进行修改,使用StringBuffer的效率更高。
- 在常量相加时没有性能问题,是因为在编译期间进行了优化。然而,在常量与变量进行相加时会有性能的问题,StringBuffer目的就是解决字符串相加时带来的性能问题。
- StringBuffer的内部实现采用字符数组,默认字符长度为16,当超过数组大小时,动态扩充的算法是:原来的长度*2+2。当我们预知要添加的数据长度时,建议使用带初始化容量的方法,来避免动态扩充的次数,从而提高效率。
- StringBuffer是线程安全的,可以在多线程程序中使用。
- StringBuffer对象的创建:StringBuffer sb=new StringBuffer();
StringBuffer和String的相互转换
String s="abc";
StringBuffer sb=new StringBuffer(s);//String对象转化为StringBuffer对象
String s1=sb.toString();//调用StringBuffer的toString()方法将StringBuffer对象转化为String对象
StringBuffer的常用方法
- public StringBuffer append(char c)在末尾添加一个字符
- public StringBuffer append(char[] str)在末尾添加字符数组中的所有字符
- public StringBuffer append(char[] str,int offset,int len)在末尾添加字符串的一部分,该部分在数组中的起始位置是offset,长度是len
- public StringBuffer append(CharSequence s)在末尾添加字符串
- public StringBuffer append(CharSequence s,int start,int end)在末尾添加字符串的一部分,该部分在数组中的起始位置是start,结束位置是end
- 除此之外,还可以把boolean,int,long,float,double类型的变量添加到字符串的末尾。
StringBuilder类
StringBuilder是StringBuffer的兄弟类。StringBuilder是一个可变的字符序列,此类提供一个与StringBuffer兼容的API,但不保证同步。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用此类,因为在大多数实现中,它比StringBuffer要快。
StringBuffer与StringBuilder的区别:
- StringBuffer是线程安全的,性能低,适合在多线程中使用,在JDK1.0后添加
- StringBuilder是线程不安全的,性能高,适合在单线程中使用,这种情况比较多,在JDK1.5后添加
public class StringBuilderDemo {
public static void main(String[] args) {
StringBuilder sb=new StringBuilder();
/*字符串相加操作
1.多个常量相加没有性能问题,在编译期优化
2.变量与常量相加,会产生多个垃圾对象
3.JDK1.5之后字符串相加,在编译后,会使用StringBuilder来优化代码,实现拼接
*/
String a="a"+1;
String b=a+"b";
}
}
StringBuilder的编译原理
String c=null;
for (int i = 0; i < 5; i++) {
//每次循环会产生一个StringBuilder对象实现拼接,性能低,所以最好使用手动创建StringBuilder来拼接
c+=i;
}
二、Math类
Math类是java.lang包下的final类。其方法都是静态方法。Math类中只有一个私有构造方法,因此它无法获得Math类的实例,只能通过类名调用其中包含的公有静态常量和方法。
Math类中的常量:
- Math.PI:圆周率,值为3.141592653589793;
- Math.E:自然对数的底数,值为2.718281828459045。
Math类中的方法:
- Math.abs:求绝对值(参数可以是int,long,float,double)
- Math.sin:正弦函数
- Math.asin:反正弦函数
- Math.cos:余弦函数
- Math.acos:反余弦函数
- Math.tan :正切函数
- Math.atan:反正切函数
- Math.toDegrees:弧度转化为角度
- Math.toRadians:角度转化为弧度
- Math.ceil:得到不小于某数的最小整数,返回值是double类型
- Math.floor:得到不大于某数的最大整数
- Math.sqrt:开平方
- Math.pow:求某数的任意次方
- Math.exp:求e的任意次方
- Math.log10:以10为底的对数
- Math.log:自然对数
- Math.rint:求最接近某数的整数(可能比某数大,也可能比它小),返回double型。负数向左取整,正数向右取整
- Math.rint:求最接近某数的整数(可能比某数大,也可能比它小),返回int 或float型(相当于四舍五入)
- Math.random:返回[0,1)之间的一个随机数。返回值>=0.0,小于1.0。
- Math.round:不管是正值还是负值都是向右取值(比如x.5时)
三、日期类
Date类
Date类表示特定的瞬间,精确到毫秒,也就是运行程序当前的时间。
Date date =new Date();实例化Date对象,表示当前时间。
Calendar类
Calendar,日历类,使用此类可以将时间精确到毫秒显示。
有三种实例化方式:
- Calendar cal=Calendar.getInstance();
- Calendar cal=new GregorianCalendar();
- GregorianCalendar cal=new GregorianCalendar();
GregorianCalendar对象提供了比较丰富的方法,可以对年、月、日、时、分、秒进行修改和加减。
Calendar 对象和Date对象可以相互转换,使用Calendar 对象的getTime()方法将转换Calendar 对象为Date对象。反之,使用setTime()方法将Date对象转换为Calendar 对象。
SimpleDateFormat格式化为一个字符串进行显示。使用SimpleDateFormat,也可以把规定格式的字符串转换为日期。
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date d=new Date();
System.out.println(df.format(d));
字符串转换为日期
SimpleDateFormat df=new SimpleDateFormat();
df.applyPattern("yyyy-MM-dd hh:mm:ss");//规定解析格式
String s="2021-8-20 18:54:13";
Date d=df.parse(s);//字符串解析为Date对象,若解析失败就抛出异常
System.out.println(df.format(d));
日期和时间模式
四、封装类
基本数据类型 | 对应的封装类 |
boolean | Boolean |
byte | Byte |
char | Character |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
提供封装类的原因 :
- 基本数据类型只能按值传递,而封装为对象后,可以按引用传递。
- 在一些应用框架中,必须用对象作参数,而不能用基本类型。
- 基本类型封装为对象后,可以拥有一些方法来处理数据,进行数据类型转换、数据格式化等操作。
基本数据类型与封装类、字符串与基本数据类型封装类之间的转换:
public class FengZhuangClass {
public static void main(String[] args) {
int i = 100;
// 将int变量转化为Integer对象:将基本类型变量的值传入构造函数,生成封装类的对象
Integer iObj = new Integer(i);
// 将Integer对象转化为int变量:调用利用封装类提供的xxxValue()方法,获得基本类型变量
int i1 = iObj.intValue();
// 将字符串转换为基本类型的封装类对象:用封装类的静态方法parseXxx来实现,如果转换失败就抛出NumberFormatException
String s1 = "100";
Integer iObj1 = Integer.parseInt(s1);// 将字符串转化为Integer对象
int i2 = iObj.intValue();// 将Integer对象转化为int变量
}
}
参考资料:《Java程序设计》 主编:谢先伟 梅青平 中国水利水电出版社