一. 字符串String
1. 含义
可以存储多个字符组成的内容(文本)的数据类型,就叫做字符串
2. 如何存储多个字符
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
//String的value属性,用来保存字符串
private final char[] value;
/*
* String 重写了equals方法
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
/*
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
*/
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
//构造方法
public String() {
this.value = "".value;
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
}
- String不能被继承,不会产生多态
- String可以序列化(可以把对象保存在磁盘上)
- String可以相互比较,进行排序
- String中数据类型为字符数组的属性value
- 我们的字符串保存在该数组中
- String在实例化时,必须为value属性赋值,一旦赋值就再也不能修改它了
3. 字符串的创建
package com.qfedu;
public class Demo01 {
public static void main(String[] args) {
/*
* 字符串对象的创建
*/
String str = "java2204";
System.out.println(str);
String str2 = new String(); //值为空字符串 ""
System.out.println(str2);
String str3 = new String("abc");
System.out.println(str3);
char[] arr = {97, 98, 'c', 100, 101}; //abcde
String str4 = new String(arr);
System.out.println(str4);
String str5 = new String(arr, 1 ,3);
System.out.println(str5);
}
}
4. 字符串在内存的存储
-
String str1 = "abc";
- 在常量池中查找有没有一个常量对象内保存的值是abc
- 如果没有找到呢,就创建一个常量对象,保存abc,在栈中保存str1变量值,指向到该常量对象
- 如果找到了呢,在栈中保存str1变量值,直接指向到该常量对象
-
String str1 = new String("abc");
- 每次创建在堆中开辟空间,保存对象值
package com.qfedu;
public class Demo02 {
public static void main(String[] args) {
/*
* String类重写了equals方法,比较两个字符串的值,只要值相等,就返回true
*
*
* String str1 = "abc";
* 1. 在常量池中查找有没有一个常量对象内保存的值是abc
* 2. 如果没有找到呢,就创建一个常量对象,保存abc,在栈中保存str1变量值,指向到该常量对象
* 3. 如果找到了呢,在栈中保存str1变量值,直接指向到该常量对象
*
*/
String str1 = "abc";
String str2 = "abc";
boolean r1 = str1 == str2; //true
boolean r2 = str1.equals(str2); //true
System.out.println(r1);
System.out.println(r2);
String str3 = new String("abc");
String str4 = new String("abc");
boolean r3 = str3 == str4; //false
boolean r4 = str3.equals(str4); //true
boolean r5 = str1 == str3; //false
boolean r6 = str1.equals(str3); //true
}
}
5. 如果理解不可变
- String类型定义的字符串不可变
- 如果发生字符串的拼接,是重新开辟内存的空间,保存拼接后的值
- 变的是String类型的变量的引用
package com.qfedu;
public class Demo03 {
public static void main(String[] args) {
String str = "ab";
str += "cd";
System.out.println(str);
}
}
6. 字符串中方法
package com.qfedu;
import java.util.Arrays;
public class Demo04 {
public static void main(String[] args) {
String str = "abcdefg";
/*
* 字符串中的每一个字符都有一个下标
* 下标从0开始,依次递增1
*
* charAt(下标) : 获取执行下标上的字符
*/
char c = str.charAt(0);
System.out.println(c);
/*
* length() : 获取字符串字符的个数(长度)
*/
int len = str.length();
System.out.println(len);
//遍历数组
for(int i=0; i<str.length(); i++) {
System.out.print(str.charAt(i)+" ");
}
System.out.println();
/*
* contains() : 是否包含
*
* indexOf() : 首次出现的下标
* - 如果出现,就返回这个字符串第一个字符首次出现的下标
* - 如果不包含,就返回-1
*
* lastIndexOf : 最后一次出现
* - 如果出现,就返回这个字符串第一个字符最后一次出现的下标
* - 如果不包含,就返回-1
*
*/
str = "abcdefgab";
String str2 = "ab";
boolean r1 = str.contains(str2);
System.out.println(r1);
int index = str.indexOf(str2);
System.out.println(index);
int lastIndex = str.lastIndexOf(str2);
System.out.println(lastIndex);
/*
* 字符串转化为字符数组
*/
str = "abcdefg";
char[] arr = str.toCharArray();
System.out.println(Arrays.toString(arr));
/*
* 以什么字符串开头或结尾
*
* startsWith() 开头
* endsWith() 结尾
*/
str = "abcdefg";
boolean r2 = str.startsWith("ac"); //false
boolean r3 = str.endsWith("fg"); //true
/*
* 转化为大写,小写
*
* toUpperCase(); 大写
* toLowerCase(); 小写
*/
str = "abcdefg";
String r4 = str.toUpperCase();
System.out.println(r4);
String r5 = r4.toLowerCase();
System.out.println(r5);
/*
* 截取
*
* substring(beginIndex); 从这个下标开始截取(包含此下标),一直截取到结束
* substring(beginIndex, endIndex); 从这个下标开始截取(包含此下标),一直截取到endIndex下标位置(不包含)
* 包含前,不包含后
*/
str = "abcdefg";
//截取 defg
String r6 = str.substring(3);
System.out.println(r6);
//截取 def
String r7 = str.substring(3, 5);
System.out.println(r7);
/*
* 去空 : 去除前,去除后的空格
*/
str = " ab c ";
String r8 = str.trim();
System.out.println(r8);
/*
* 分割
*/
str = "abcdefdg";
String[] strArr = str.split("de");
System.out.println(Arrays.toString(strArr));
/*
* 替换 (删除)
*/
str = "abcdefdgc";
String r9 = str.replace("cd", "C");
// String r9 = str.replace("c", ""); //删除某一个字符串
System.out.println(r9);
}
}
7. 字符串的排序
package com.qfedu;
import java.util.Arrays;
public class Demo05 {
/*
* 字符串比较
*
* 正数 >
* 零 =
* 负数 <
*
* 字符串类型的数组就可以进行排序
*/
public static void main(String[] args) {
String str1 = "abc";
String str2 = "ab";
int r = str1.compareTo(str2);
System.out.println(r);
String[] arr = {"bdd","abc", "ab"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
二. 可变字符串
如果频繁的操作字符串,可以使用可变字符串,提高性能
- StringBuilder
- 每个方法都没有synchronized关键,线程不安全
- 性能高
- StringBuffer
- 每个方法都有synchronized关键,线程安全
- 性能低
三. 日期
1. java.util.Date
- 表示当前时间
- 作为属性的数据类型
package com.qfedu;
import java.util.Date;
public class Demo01 {
public static void main(String[] args) {
//获取当前时间
Date date = new Date();
System.out.println(date);
long time = date.getTime(); // 1970-01-01 00:00:00 到现在的毫秒数
System.out.println(time);
}
}
class Student {
String name;
String gender;
Date birthday; //作为属性的数据类型
}
2. Calendar
- 操作日期
package com.qfedu;
import java.util.Calendar;
public class Demo02 {
/*
* Calendar 操作日期
*/
public static void main(String[] args) {
//创建Calendar对象
Calendar cal = Calendar.getInstance();
/*
* get(field) : 获取当前时间的年,月,日,时,分,秒,星期,天数
* - Calendar.YEAR
* - Calendar.MONTH
* - Calendar.WEEK_OF_YEAR
*/
int year = cal.get(Calendar.YEAR);
System.out.println(year);
int month = cal.get(Calendar.MONTH); // 月份从0开始
System.out.println(month);
int weeks = cal.get(Calendar.WEEK_OF_YEAR);
System.out.println(weeks);
/*
* 设置/操作 时间
*
* set(field, 值);
* add(field, 值);
*/
//2022-12-1 17:24:22
// cal.set(Calendar.MONTH, 5);
System.out.println(cal.getTime());
cal.add(Calendar.YEAR, -10);
cal.add(Calendar.MONTH, 2);
System.out.println(cal.getTime());
/*
* 获取本月的最后一天日期
*/
cal = Calendar.getInstance();
cal.set(Calendar.DATE, 1);
cal.add(Calendar.MONTH, 1);
cal.add(Calendar.DATE, -1);
System.out.println(cal.getTime());
}
}
四. 内部类
- 成员内部类
- 在一个类中,定义一个和成员变量同级的类
- 静态内部类
- 使用static修饰的成员内部类
- 局部内部类
- 定义在方法中的类
- 目的就是该类的作用范围在该方法中
- 匿名内部类
package com.qfedu;
public class Out {
private String str;
private A a;
//定义成员内部类,该类只能在外部类中使用
//但是不能定义静态的变量
private class A {
int a;
int b;
// static int c;
}
//使用static修饰的成员内部类,叫做静态内部类
private static class B {
int a;
int b;
static int c;
}
public void m(int a) {
int a2 = 8;
//局部内部类,该类只能作用在该方法内
class C {
public void cm() {
// a = 6;
System.out.println(a);
}
}
C c = new C();
}
public static void main(String[] args) {
//匿名内部类
Inter inter = new Inter() {
@Override
public void meth() {
System.out.println("实现了meth方法");
}
};
inter.meth();
}
}
interface Inter {
void meth();
}