1 数组
一维数组
- 三种初始化方法
int[] a = new int[2];
a[0] = 1;
a[1] = 2;
int[] b = new int[]{5, 1};
int[] c = {8, 9};
数组长度
int[] a = new int[15];
//值为int型常量
a.length = 15;
- 如果只是对数组进行声明,没有进行创建,则该数组为null,调用length函数会出现空指针异常。
int a[];
// 空指针异常
System.out.println(a.length);
- 如果对数组进行声明并创建空数组,则数组不为null,length函数正常运行,返回结果为0
int a[] = new int[0];
// 返回结果为0
System.out.println(a.length);
数组判空
if (nums == null || nums.length <= 0)
Arrays类方法
Arrays.toString
将数组转换成String类型输出的(否则输出的是数组的地址)
Arrays.sort
-
对一个数组的所有元素进行从小到大的排序
Arrays.sort(int[] arr)
-
对数组a的下标从fromIndex到toIndex-1的元素排序,注意:下标为toIndex的元素不参与排序。
Arrays.sort(int[] arr, int fromIndex, int toIndex)
-
对一个数组的所有元素进行从大到小的排序
Arrays.sort(int[] arr, (a, b) -> b - a);
// 泛型不能使用基本类型(int,double,char),而要使用它们对应的类
Integer[] arr = {1, 4, 2};
Arrays.sort(arr, (a,b) -> b - a);
// [4, 2, 1]
System.out.println(Arrays.toString(arr));
Arrays.asList()
- 将数组转化成list集合的方法
List<String> list = Arrays.asList("a", "b", "c");
note:
- 该方法适用于对象型数据的数组(Integer、String …),不建议使用于基本数据(int、byte …)
2)不支持add()、remove()、clear()等方法
二维数组
- 类似一维数组三种初始化方法
int[][] ar1 = {{1, 2}, {3, 4}};
int[][] ar2 = new int[][] {{1, 2}, {3, 4}};
int[][] ar3 = new int[2][3]
ar3[0] = new int[] {0, 1, 2}
ar3[1][0] = 3;
ar3[1][1] = 4;
ar3[1][2] = 5;
2 字符串
字符串赋值初始化
//空的对象不能做任何操作,相当于string a = null;
string a;
//引用字符串常量
String str = "时间";
//利用构造方法直接实例化
Stringn b = new String("ying")
String c = new String(a);
字符串长度
- 字符串用length(),数组用length
- length()方法返回的字符串长度包括字符串中的空格。
- null字符串不能使用length()
String pass = "123";
int size = pass.length();
字符串判空
1)if (s == null || s.equals(""))
方法直观方便,但是效率比较低
2)if (s == null || s.length() <= 0)
比较字符串长度,效率高
3)if (s == null || s.isEmpty())
Java SE 6.0才开始提供的方法,效率和方法二几乎相等,推荐使用
- List判空
if (lcList == null || lcList.size() == 0)
拼接字符串
//"+"运算符
String a = "12" + "34";
//API,在末尾位置拼接字符串
String str = "ab";
str = str.concat("cd");
数字转为字符串
//显示转换,任意数字类型或布尔型
String strInt = String.valueOf(12);
String strLong = String.valueOf(12L);
String strDouble = String.valueOf(12.34);
String strFloat = String.valueOf(3.14f);
String strBool = String.valueOf(false);
//隐式转换,“” +
String str1 = "" + 12;
String str2 = "12" + 34;
获取指定位置的字符
//获取第一个字符,ch = p
String name = "Peter";
char ch = name.charAt(0);
//获取第一次出现的索引,index = 1
String str = "We are";
int index = str.indexOf("e");
//从指定位置往后查索引,index = 5
String str = "We are";
int index = str.indexOf("e", 3);
//获取倒数第一次出现的索引,index = 7
String str = "Let it go!";
int lastIndex = str.lastIndexOf("g");
判断内容
//判断字符串结尾内容
String fileName = "Hello.java";
Boolean bool1 = fileName.endsWith(".java");
//判断字符串句首内容
String str = "小明..."
Boolean bool2 = str.startsWith("小明");
//判断子字符串是否存在
String str = "8D8";
Boolean bool1 = str.contains("D");
//比较字符串是否相等,"=="判断的是内存地址,"equals"判断的是存储的值
String name1 = new String("tom");
String name2 = new String("tom");
boolean bool = name1.equals(name2)
//"equalsIgnoreCase"忽略大小写
String str1 = new String("abc");
String str2 = new String("ABC");
boolean bool = str1.equalsIgnoreCase(str2)
将字符串变成字符数组
String str = "字符串";
char[] ch = str.toCharArray();
截取字符串
- 指定开始的位置、结束位置(可省略):索引
// 23,从起始位置开始到结束位置前
String id = "123456";
String substr = id.substring(1,3);
System.out.println(substr);
字符串替换
- replace():旧字符序列换成新字符序列
- replaceAll():将旧字符串或正则表达式内容,替换成新字符串
- replaceFirst():替换一次
- 正则表达式是含有一些具有特殊意义字符的字符串,这些特殊字符称为正则表达式的元字符。例如,“\d”表示数字0~9中的任何一个,“\d”就是元字符;“\.”表示“.”;“\s”表示空格。
- 转义字符:\n表示换行
// yi文yi个
String str = "一文一个";
String restr = str.replace("一","yi");
System.out.println(restr);
// ???abc
String str = "123abc";
String restr = str.replaceAll("\\d","?");
System.out.println(restr);
// [abc] 去除空白内容
String str = " a bc";
String restr = str.replaceAll("\\s","");
System.out.println("["+restr+"]");
// JAva
String str = "Java";
String restr = str.replaceFirst("a","A");
System.out.println(restr);
字符串分割
- split:将字符串按照指定的符号分割成数组
// ab cd ef
String str = "ab,cd,ef";
String strarray[] = str.spilt(",");
for (int i=0; i<strarray.length; i++){
System.out.println(strarray[i]);
}
// [192][168][0][1] [192][168.0.1]
// 通过参数限定分割的次数
String str = "192.168.0.1";
String strarray1[] = str.split("\\.");
String strarray2[] = str.split("\\.", 2);
for (int i = 0; i < strarray1.length; i++) {
System.out.print("[" + strarray1[i] + "]");
}
System.out.println();
for (int i = 0; i < strarray2.length; i++) {
System.out.print("[" + strarray2[i] + "]");
}
字符串大小写转换
- 将字符串变成大写:toUpperCase()
- 将字符串变成小写:toLowerCase()
// ABCD abcd
String str = "abCD";
String str1 = str.toUpperCase();
String str2 = str.toLowerCase();
System.out.println(str1);
System.out.println(str2);
格式化字符串
- 时间格式化
// Thu Jul 15 18:55:22 CST 2021
Date date = new Date();
System.out.println(date);
// 2021 七月 15
String year = String.format("%tY", date);
String month = String.format("%tB", date);
String day = String.format("%td", date);
System.out.println(year+" "+month+" "+day);
// 19 01 17
String hour = String.format("%tH", date);
String minute = String.format("%tM", date);
String second = String.format("%tS", date);
System.out.println(hour+" "+minute+" "+second);
// tF格式:2021-07-15
String str1 = String.format("%tF", date);
System.out.println("tF格式: "+str1);
// tD格式:07/15/21
String str2 = String.format("%tD", date);
System.out.println("tD格式: "+str2);
// tc格式:星期四 七月 15 19:05:58 CST 2021
String str3 = String.format("%tc", date);
System.out.println("tc格式: "+str3);
// tr格式:07:05:58 下午
String str4 = String.format("%tr", date);
System.out.println("tr格式: "+str4);
- 数字格式化
// 长度为5的字符串| 123|
// 右对齐|123 |
System.out.println(String.format("长度为5的字符串|%5d|", 123));
System.out.println(String.format("右对齐|%-5d|", 123));
// 33的8进制结果041
// 33的8进制结果0x21
System.out.println(String.format("33的8进制结果%#o", 33));
System.out.println(String.format("33的8进制结果%#x", 33));
// 我是正数+1
// 我是负数-1
System.out.println(String.format("我是正数%+d", 1));
System.out.println(String.format("我是负数%+d", -1));
// 我是正数,没有括号1
// 我是负数,有括号(1)
System.out.println(String.format("我是正数,没有括号%(d", 1));
System.out.println(String.format("我是负数,有括号%(d", -1));
// 我是正数00123
System.out.println(String.format("我是正数%05d", 123));
// 这是一个金额123,456,789
System.out.println(String.format("这是一个金额%,d", 123456789));
- 常规格式化
// 字母x大写:X
String str1 = String.format("字母x大写:%c",'X');
System.out.println(str1);
// 12+34的结果是:46
System.out.println(String.format("12+34的结果是:%d", 12+34));
// n取两位小数点:3.14
System.out.println(String.format("n取两位小数点:%.2f", Math.PI));
// 2<3的结果:true
System.out.println(String.format("2<3的结果:%b", 2<3));
// 1200000.1用科学计数法表示:1.200000e+06
System.out.println(String.format("1200000.1用科学计数法表示:%e", 1200000.1));
// 灵感1%,汗水99%
System.out.println(String.format("灵感%d%%,汗水%d%%", 1,99));
3 集合
HashMap
- 创建映射关系
//Map<key, value> 相当于key是键(地址),value是值(地址里的值)
Map<Integer, String> map = new HashMap<>();
- put(k, v)函数,将键值送入映射
//输入,将键为1,值为one送入hashMap
map.put(1, "one");
map.put(2, "two");
System.out.println(map);
//输出
{1=one, 2=two}
- get(k)函数
//得到键为1的值one
System.out.println(map.get(1));
- map(k)函数
//map的长度,2
System.out.println(map.size());
- idEmpty()函数
//判断map是否为空,false
System.out.println(map.isEmpty());
- containsKey(k),containsValue(k)函数
//判断映射中是否有某个键为2,若有,返回true
System.out.println(map.containsKey(2));
//判断映射中是否有某个值为two,若有,返回true
System.out.println(map.containsValue("two"));
- putAll()函数
//新建一个映射关系map1
Map<Integer, String> map1 = new HashMap<>();
map1.put(3, "three");
map1.put(4, "four");
//将map1中所有键值送入map中
map.putAll(map1);
System.out.println(map);
//输出
{1=one, 2=two, 3=three, 4=four}
- remove(k)函数
//移除映射中的键值
map.remove(2);
System.out.println(map);
//输出
{1=one, 3=three, 4=four}
- keySet(),values()函数
//只返回键,不输出值
System.out.println(map.keySet());
//输出
[1, 3, 4, 5]
//返回所有的值
System.out.println(map.values());
//输出
[one, three, four, five]
- equals()函数
//判断两个映射是否相等
Map<Integer, String> map2 = new HashMap<>();
map1.put(3, "three");
map1.put(4, "four");
//map2.put(5, "five");
//比较指定的对象与此映射是否相等(判断两个映射是否完全相同,是就返回true)
System.out.println(map1.equals(map2));
- clear()函数
//清除所有映射
map.clear();
System.out.println(map);
//输出
{}
ArrayList(动态数组)
Stack(栈)
Stack栈“先进后出”;
Stack本质是一个List,其具备List所有的方法;
Stack和ArrayList的区别
stack和ArrayList的最大区别是stack是线程安全的,而ArrayList不是线程安全的。所以,当涉及到多线程问题时,优先考虑使用stack。
因为stack实现了List接口,则可以将stack转换为list;
List<Integer> list = new ArrayList<Integer>(pre)
Stack方法
- 初始化
Stack stack = new Stack();
- 判断Stack是否为空
isEmpty()
- 添加元素
push(E item)
- 获取栈顶值,元素不出栈(栈为空时抛异常)
peek()
stack调用peek后,item还是在栈中的,并未被移除,然后在调用peek时要判断stack中是否有元素,否则会引发异常。 - 是否存在obj
search(Object obj)
返回值为int,若存在,返回值为obj距离栈顶的位置,若不存在,返回-1 - 移除栈顶
pop()
此方法是移除栈顶的元素,并且返回值是移除的item
4 常用函数
获取当前时间
- System.currentTimeMillis():获取当前的总毫秒数
- Date:获取当前日期
- SimpleDateFormat:按指定格式获取当前日期
public class demo {
public static void main(String[] args) {
//总毫秒数 从1970年1月1日开始计算
long totalMilisSeconds = System.currentTimeMillis();
//总秒数
long totalSeconds = totalMilisSeconds / 1000;
//当前秒数
long currentSeconds = totalSeconds % 60;
//总分钟
long totalMinutes = totalSeconds / 60;
//当前分钟
long currentMinutes = totalMinutes % 60;
//总小时(中国时区需加8小时)
long totalHours = totalMinutes / 60 + 8;
//当前小时
long currentHours = totalHours % 24;
//总天数
long totalDays = totalHours / 24;
Date date = new Date();
System.out.println("总毫秒数:" + totalMilisSeconds);
System.out.println("总秒数:" + totalSeconds);
System.out.println("总分钟数:" + totalMinutes);
System.out.println("总小时:" + totalHours);
System.out.println("当前秒:" + currentSeconds);
System.out.println("当前分钟数:" + currentMinutes);
System.out.println("当前小时:" + currentHours);
System.out.println("总天数:" + totalDays);
SimpleDateFormat sdFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(date);
System.out.println(sdFormatter.format(date));
}
}
// 输出
总毫秒数:1629090995569
总秒数:1629090995
总分钟数:27151516
总小时:452533
当前秒:35
当前分钟数:16
当前小时:13
总天数:18855
Mon Aug 16 13:16:35 CST 2021
2021-08-16 13:16:35
Math.min
- Math.min(a, b);
返回值为小的那个数,
1)a,b必须是同一类型的数据,返回值类型根据a,b的类型而定。
2)a,b可接受double、float、int、long四种类型。
5 常用关键字
String、StringBuilder以及StringBuffer
1)String类
String类是final类,异味这String类不能继承。一旦一个String对象对创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象对销毁。
String a = "123";
a = "456";
可以看出来,再次给a赋值时,并不是对原来堆中实例对象进行重新赋值,而是生成一个新的实例对象,并且指向“456”这个字符串,a则指向最新生成的实例对象,之前的实例对象仍然存在,如果没有被再次引用,则会被垃圾回收。
对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象
2)String str = "hello world"和String str = new String(“hello world”)区别
public class demo {
public static void main(String[] args) {
String str1 = "hello world";
String str2 = new String("hello world");
String str3 = "hello world";
String str4 = new String("hello world");
System.out.println(str1==str2);
System.out.println(str1==str3);
System.out.println(str2==str4);
}
}
// 输出
false
true
false
class文件中有一部分 来存储编译期间生成的 字面常量以及符号引用,这部分叫做class文件常量池,在运行期间对应着方法区的运行时常量池。
因此在上述代码中,String str1 = “hello world”;和String str3 = “hello world”; 都在编译期间生成了 字面常量和符号引用,运行期间字面常量"hello world"被存储在运行时常量池(当然只保存了一份)。通过这种方式来将String对象跟引用绑定的话,JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。
众所周知,通过new关键字来生成对象是在堆区进行的,而在堆区进行对象生成的过程是不会去检测该对象是否已经存在的。因此通过new来创建对象,创建出的一定是不同的对象,即使字符串的内容是相同的。
2)StringBuilder
public class demo {
public static void main(String[] args) {
String string = "";
for(int i=0;i<10000;i++){
string += "hello";
}
}
}
这句 string += “hello”;的过程相当于将原有的string变量指向的对象内容取出与"hello"作字符串相加操作再存进另一个新的String对象当中,再让string变量指向新生成的对象。
实际上,string+="hello"的操作事实上会自动被JVM优化成:(其实还是有点差距)
StringBuilder str = new StringBuilder(string);
str.append("hello");
str.toString();
public class demo {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
for(int i=0;i<10000;i++){
stringBuilder.append("hello");
}
}
}
反编译字节码文件得到,并且new操作只进行了一次,也就是说只生成了一个对象,append操作是在原有对象的基础上进行的。因此在循环了10000次之后,这段代码所占的资源要比上面小得多。
3)StringBuffer
查看源代码可知,StringBuilder和StringBuffer类拥有的成员属性以及成员方法基本相同,区别是StringBuffer类的成员方法前面多了一个关键字:synchronized,不用多说,这个关键字是在多线程访问时起到安全保护作用的,也就是说StringBuffer是线程安全的。
4)不同场景三个类的性能测试
public class demo {
private static final int time = 50000;
public static void main(String[] args) {
testString();
testStringBuffer();
testStringBuilder();
test1String();
test2String();
}
public static void testString () {
String s="";
long begin = System.currentTimeMillis();
for(int i=0; i<time; i++){
s += "java";
}
long over = System.currentTimeMillis();
System.out.println("操作"+s.getClass().getName()+"类型使用的时间为:"+(over-begin)+"毫秒");
}
public static void testStringBuffer () {
StringBuffer sb = new StringBuffer();
long begin = System.currentTimeMillis();
for(int i=0; i<time; i++){
sb.append("java");
}
long over = System.currentTimeMillis();
System.out.println("操作"+sb.getClass().getName()+"类型使用的时间为:"+(over-begin)+"毫秒");
}
public static void testStringBuilder () {
StringBuilder sb = new StringBuilder();
long begin = System.currentTimeMillis();
for(int i=0; i<time; i++){
sb.append("java");
}
long over = System.currentTimeMillis();
System.out.println("操作"+sb.getClass().getName()+"类型使用的时间为:"+(over-begin)+"毫秒");
}
public static void test1String () {
long begin = System.currentTimeMillis();
for(int i=0; i<time; i++){
String s = "I"+"love"+"java";
}
long over = System.currentTimeMillis();
System.out.println("字符串直接相加操作:"+(over-begin)+"毫秒");
}
public static void test2String () {
String s1 ="I";
String s2 = "love";
String s3 = "java";
long begin = System.currentTimeMillis();
for(int i=0; i<time; i++){
String s = s1+s2+s3;
}
long over = System.currentTimeMillis();
System.out.println("字符串间接相加操作:"+(over-begin)+"毫秒");
}
}
// 输出
操作java.lang.String类型使用的时间为:3765毫秒
操作java.lang.StringBuffer类型使用的时间为:2毫秒
操作java.lang.StringBuilder类型使用的时间为:1毫秒
字符串直接相加操作:1毫秒
字符串间接相加操作:5毫秒
- 对于直接相加字符串,效率很高,因为在编译器便确定了它的值,也就是说形如"I"+“love”+“java”; 的字符串相加,在编译期间便被优化成了"Ilovejava"。
- 对于间接相加(即包含字符串引用),形如s1+s2+s3; 效率要比直接相加低,因为在编译器不会对引用变量进行优化。
- String、StringBuilder、StringBuffer三者的执行效率:StringBuilder > StringBuffer > String
当然这个是相对的,不一定在所有情况下都是这样。比如String str = “hello”+ "world"的效率就比 StringBuilder st = new StringBuilder().append(“hello”).append(“world”)要高。
因此,这三个类是各有利弊,应当根据不同的情况来进行选择使用:
- 当字符串相加操作或者改动较少的情况下,建议使用 String str="hello"这种形式;
- 当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。