19.Java常用类String、Date、Comparable

Java常用类String、Date、Comparable


  • String字符串

    • 不可被继承;实现了Comparable、Serializable

    • String的不可变性

    • String的实例化方式

      • 方式一:使用字面量方式。 String s = “hello”
      • 方式二:String s = new String(“hello”);
      • 【面试题】String s = new String(“hello”)在内存中创建了几个对象? 两个!
      • 内存解析:
        • jdk6时,字符串常量池是存放在永久代
        • jdk7时,字符串常量池改为存放在堆空间
        • jdk8时,取消了永久代,取而代之的是元空间(使用直接内存)
    • 连接操作:+

    • String的常用方法

    • String与其他相关结构的转换:包装类、字符数组、字节数组

    • String的常用算法题目

一、字符串的使用

1.1 String的介绍

	 * 1. public final class String implements java.io.Serializable, Comparable
	 *  > 不可被继承
	 *  > Serializable:标识接口,实现序列化机制的接口
	 *  > Comparable:实现对象比较大小的接口
	 *  > String是类,属于引用类型变量。

1.2 String的不可变性

@Test
	public void test1(){
		//"hello"声明在字符串常量池中
		String s1 = "hello"; //int num = 10; Date date = new Date();
		String s2 = "hello";
		
		System.out.println(s1.equals(s2));//true
		System.out.println(s1 == s2);//true
		
		//*******************
		s1 = "java";
		System.out.println(s2);//hello
		
		//****************
		String s3 = "hadoop";//new char[]{'h','a','d','o','o','p'}
		String s4 = "hadoop";
		
		s3 += "spark";
		System.out.println(s3);//hadoopspark
		System.out.println(s4);//hadoop
		
		//****************
		String s5 = "flink";
		String s6 = "flink";
		
		String s7 = s5.replace('f', 'h');
		System.out.println(s5);//flink
		System.out.println(s6);//flink
		System.out.println(s7);//hlink
	}

对应的内存图为:

在这里插入图片描述

在这里插入图片描述

应用举例:

		Person p1 = new Person("Tom",12);
		Person p2 = new Person("Tom",12);
		System.out.println(p1.name == p2.name);//true
		
		p1.name = "Jerry";
		System.out.println(p2.name);//Tom
public class Person {
	String name;
	int age;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	
}

1.3 String的实例化的情况

/*
	 * String的实例化的情况
	 * 
	 * 两种方式:
	 * 方式一:使用字面量的方式
	 * 方式二:使用new的方式
	 * 
	 * 面试题:使用new的方式创建一个字符串,内存中创建了几个对象? 堆空间中创建的对象、字符串常量池中。
	 */
	@Test
	public void test2(){
		//方式一:使用字面量的方式
		String s1 = "hello";
		
		String s2 = new String("hello");
		
		System.out.println(s1.equals(s2));//true
		
		System.out.println(s1 == s2);//false
		

	}

1.4 String的连接操作

/*
	 *  String的连接操作
	 * 
	 * 1. 连接运算中,如果使用的都是字面量,则在常量池中声明此字符串或使用现有的字符串。
	 * 2. 连接运算中,如果使用的是变量,则需要在堆中重新开辟空间,保存此字符串的值。
	 * 3. 通过字符串调用intern(),返回此字符串在字符串常量池中的字面量。
	 */
	@Test
	public void test3(){
		String s1 = "java";
		String s2 = "hadoop";
		
		String s3 = "javahadoop";
		String s4 = "java" + "hadoop";
		String s5 = "java" + s2;
		String s6 = s1 + "hadoop";
		String s7 = s1 + s2;
		
		String s8 = s7.intern();
		String s9 = s5.intern();
		
		System.out.println(s3 == s4);//true
		System.out.println(s3 == s5);//false
		System.out.println(s3 == s6);//false
		System.out.println(s3 == s7);//false
		System.out.println(s5 == s6);//false
		System.out.println(s5 == s7);//false
		
		System.out.println(s3 == s8);//true
		System.out.println(s3 == s9);//true
		
	}

1.5 String中的常用方法

/*
	 * int length():返回字符串的长度: return value.length
	 * char charAt(int index): 返回某索引处的字符return value[index]
	 * boolean isEmpty():判断是否是空字符串:return value.length == 0
	 * String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写
	 * String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写
	 * String trim():返回字符串的副本,忽略前导空白和尾部空白
	 * boolean equals(Object obj):比较字符串的内容是否相同
	 * boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
	 * String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+”
	 * int compareTo(String anotherString):比较两个字符串的大小
	 * String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。 
	 * String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。 
	 * 
	 * 
	 * 
	 * 
	 */
	
	@Test
	public void test1(){
		String s1 = "hello123";
		char c = s1.charAt(4);
		System.out.println(c);
		
		System.out.println(s1.toUpperCase());
		
		String s2 = "  abc   def g   ";
		System.out.println(s2.trim());
		
		String s3 = "abc";
		String s4 = "abe";
		System.out.println(s3.compareTo(s4));
		
		String s5 = "北京尚硅谷教育";
		String s6 = s5.substring(2);
		System.out.println(s5);//北京尚硅谷教育
		System.out.println(s6);//尚硅谷教育
		
		String s7 = s5.substring(2, 5);
		System.out.println(s7);
	}
	
	/*
	 * boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束 
	 * boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始 
	 * boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始
	 * boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true
	 * int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引 
	 * int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始 
	 * int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引 
	 * int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索 
	 * 注:indexOf和lastIndexOf方法如果未找到都是返回-1
	 * 
	 * String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。 
	 * String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。 

	 */
	@Test
	public void test2(){
		String s1 = "helloworlld";
		System.out.println(s1.endsWith("rld"));
		System.out.println(s1.startsWith("hea"));
		System.out.println(s1.startsWith("ll", 2));
		
		System.out.println(s1.contains("wor"));
		
		System.out.println(s1.indexOf("ll"));
		System.out.println(s1.lastIndexOf("ll"));
		System.out.println(s1.lastIndexOf("la"));
		System.out.println(s1.indexOf("ll", 4));
		
		String s2 = s1.replace("ll", "ww");
		System.out.println(s1);
		System.out.println(s2);
		
	}

exOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
* int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
* 注:indexOf和lastIndexOf方法如果未找到都是返回-1
*
* String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
* String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。

@Test
public void test2(){
	String s1 = "helloworlld";
	System.out.println(s1.endsWith("rld"));
	System.out.println(s1.startsWith("hea"));
	System.out.println(s1.startsWith("ll", 2));
	
	System.out.println(s1.contains("wor"));
	
	System.out.println(s1.indexOf("ll"));
	System.out.println(s1.lastIndexOf("ll"));
	System.out.println(s1.lastIndexOf("la"));
	System.out.println(s1.indexOf("ll", 4));
	
	String s2 = s1.replace("ll", "ww");
	System.out.println(s1);
	System.out.println(s2);
	
}

二、String、StringBuffer、StringBuilder

2.1 String 与其他类之间的转换

  • String与包装类、基本数据类型之间的转化
/*
	 * String与包装类、基本数据类型之间的转化
	 */
	@Test
	public void test1(){
		//String-->包装类、基本数据类型:调用包装类Xxx的parseXxx()
		String str = "123";
		int num = Integer.parseInt(str);
		System.out.println(num);
		
//		包装类、基本数据类型--> String:调用String的valueOf()
		String str1 = String.valueOf(num);
		System.out.println(str1);
		
		String str2 = num + "";//底层需要创建SringBuilder,并调用append()导致效率第一valueOf()
		System.out.println(str2);
	}
  • String与char[]之间的转化
/*
	 * String与char[]之间的转化
	 */
	@Test
	public void test2(){
		String str1 = "hello";
		//String--->char[]:调动String的toCharArray()
		char[] arr1 = str1.toCharArray();
		for(int i = 0;i < arr1.length;i++){
			System.out.println(arr1[i]);
		}
		
		//char[] ---> String:调用String的构造器
		String str2 = new String(arr1, 0, arr1.length);//new String(arr1);
		System.out.println(str2);
	}
	

  • String与byte[]之间的转化
	/*
	 * String与byte[]之间的转化
	 * 
	 * 
	 * 1. 关联:
	 * 内存层面:
	 * char:用2个字节存储
	 * 
	 * 存储层面:
	 * 一个char,应该用几个字节存储呢?跟字符集有关系,具体问题具体分析
	 * 
	 * ASCII:给26个英文大小写字母,0-9等都分配了对应的一个字节数值。比如:a --> 97   A--> 65
	 * GBK:兼容了ASCII(如果出现英文字母,0-9时,仍然使用1个字节存储),一个汉字使用2个字节存储
	 * UTF-8:兼容了ASCII(如果出现英文字母,0-9时,仍然使用1个字节存储),一个汉字使用3个字节存储
	 * 
	 * 2. 
	 * 编码: 字符、字符串--->字节、字节数组
	 * 	> 从看得懂的,转换为看不懂的。
	 * 
	 * 解码:字节、字节数组 --> 字符、字符串
	 *  > 从看不懂的,转换为看得懂的。
	 *  
	 * 结论:编码集要与解码集一致。否则会出现乱码!
	 */
	@Test
	public void test3() throws Exception{
		String str1 = "hello中国";
		//编码:String--->byte[]:getBytes()
		byte[] arr1 = str1.getBytes();//使用默认的字符集:UTF-8
		System.out.println(Arrays.toString(arr1));
		
		byte[] arr2 = str1.getBytes("gbk");//显式指定字符集。
		System.out.println(Arrays.toString(arr2));
		
		//解码:byte[] ---> String:使用构造器
		
		String str2 = new String(arr1);//使用默认的字符集:UTF-8
		System.out.println(str2);
		
		String str3 = new String(arr2);
		System.out.println(str3);//因为编码集和现在的解码集不一致,导致出现乱码!
		
		String str4 = new String(arr2,"gbk");
		System.out.println(str4);//因为编码集和现在的解码集都是使用gbk,没有乱码
	}
  • String、StringBuffer、StringBuilder
//String --> StringBuffer、StringBuilder
String str = "hello";
StringBuffer s1 = new StringBuffer(str);
StringBuilder s2 = new StringBuilder(str);

//StringBuffer、StringBuilder --> String
String str1 = s1.toString();
String str2 = s2.toString();

String str3 = new String(s1);
String str3 = new String(s2);

2.2 String的相关算法

关于笔试中常考的算法问题,主要就集中在数组和字符串的考查!

练习1:

// 将一个字符串进行反转。将字符串中指定部分进行反转。比如“abcdefg”反转为”abfedcg”
	// 方式一:
	public String reverse1(String str, int start, int end) {// start:2,end:5
		if (str != null) {
			// 1.
			char[] charArray = str.toCharArray();
			// 2.
			for (int i = start, j = end; i < j; i++, j--) {
				char temp = charArray[i];
				charArray[i] = charArray[j];
				charArray[j] = temp;
			}
			// 3.
			return new String(charArray);
		}
		return null;

	}

	// 方式二:
	public String reverse2(String str, int start, int end) {
		// 1.
		String newStr = str.substring(0, start);// ab
		// 2.
		for (int i = end; i >= start; i--) {
			newStr += str.charAt(i);
		} // abfedc
			// 3.
		newStr += str.substring(end + 1);
		return newStr;
	}

	// 方式三:推荐 (相较于方式二做的改进)
	public String reverse3(String str, int start, int end) {

		// 1.
		StringBuilder s = new StringBuilder(str.length());
		// 2.
		s.append(str.substring(0, start));// ab
		// 3.
		for (int i = end; i >= start; i--) {
			s.append(str.charAt(i));
		}

		// 4.
		s.append(str.substring(end + 1));

		// 5.
		return s.toString();

	}

	@Test
	public void testReverse() {
		String str = "abcdefg";
		String str1 = reverse3(str, 2, 5);
		System.out.println(str1);// abfedcg

	}

练习2:

// 获取一个字符串在另一个字符串中出现的次数。
	// 比如:获取“ab”在 “abkkcadkabkebfkabkskab” 中出现的次数
	public int getCount(String mainStr, String subStr) {
		if (mainStr.length() >= subStr.length()) {
			int count = 0;//记录次数
			int index = 0;
			// while((index = mainStr.indexOf(subStr)) != -1){
			// 		count++;
			// 		mainStr = mainStr.substring(index + subStr.length());
			// }
			// 改进:
			while ((index = mainStr.indexOf(subStr, index)) != -1) {
				index += subStr.length();
				count++;
			}

			return count;
		} else {
			return 0;
		}

	}

	@Test
	public void testGetCount() {
		String str1 = "cdabkkcadkabkebfkabkskab";
		String str2 = "ab";
		int count = getCount(str1, str2);
		System.out.println(count);
	}

练习3:

//获取两个字符串中最大相同子串。比如:
//	   str1 = "abcwerthelloyuiodef"; str2 = "cvhellobnm"
//	      提示:将短的那个串进行长度依次递减的子串与较长的串比较。
	public String getMaxSameString(String str1,String str2){
		if(str1 != null && str2 != null){
			
			String maxStr = (str1.length() >= str2.length())? str1:str2;
			String minStr = (str1.length() < str2.length())? str1:str2;
			int len = minStr.length();//决定了比较的轮数
			for(int i = 0;i < len;i++){ //i:0
				
				for(int x = 0,y = len - i;y <= len;x++,y++){
					if(maxStr.contains(minStr.substring(x, y))){
						return minStr.substring(x, y);
					}
					
				}
				
			}
			
		}
		
		return null;
	}
	
	@Test
	public void testGetMaxSameSubString() {
		String str1 = "abcwerthelloyuiodef";
		String str2 = "cvhellobnmiodef";
		String str = getMaxSameString(str1, str2);
		System.out.println(str);
	}

2.3 String、StringBuffer、StringBuilder三者对比

    /*
	 * 一、三个类的对比 
	 * String:不可变的字符序列; 底层使用char[]数组存储 
	 * StringBuffer:可变的字符序列;线程安全的,效率低;底层使用char[]数组存储 
	 * StringBuilder:可变的字符序列; jdk1.5引入,线程不安全的,效率高;底层使用char[]数组存储
	 * 
	 * 注意:在jdk8以后,String\StringBuffer\StringBuilder底层改成byte[]+字符集存储,节省内存空间。
	 * 
	 * 
	 * 1. StringBuffer与StringBuilder的主要区别就是StringBuffer中的方法声明为同步的了。 
	 * 2. String s0 = "";//new char[0]; 
	 * String s1 = "abc";// new char[]{'a','b','c'};
	 * 
	 * s1 += "de";//new char[]{'a','b','c','d','e'};
	 * 
	 * StringBuilder s2 = new StringBuilder();//char arr = new char[16];
	 * StringBuilder s3 = new StringBuilder("abc");//char arr = new char["abc".length() + 16]; 
	 * s2.append("abc");//arr[0] = 'a',arr[1] = 'b',arr[2] = 'c'; 
	 * 
	 * ... 
	 * 有可能底层arr的char[]存储不下了,此时需要扩容!默认扩容为原来容量的2倍+2
	 * 
	 * 启示: 
	 * 1. 开发中如果频繁的对字符串进行修改操作,建议使用StringBuffer/StringBuilder,替换String 
	 * 2.开发中如果不涉及线程安全问题或主动加锁,建议使用StringBuilder,替换StringBuffer 
	 * 3.开发中添加的字符串数据较多,建议使用StringBuilder(int capacity),替换StringBuilder()
	 */
	@Test
	public void test1() {
		String str1 = "hello";
		str1 += "world";// 新建一个内存空间保存helloworld

		StringBuffer str2 = new StringBuffer("hello");
		str2.append("world");// 与创建对象中的char[]数组是同一个
	}
  • 面试题:String、StringBuffer、StringBuilder的异同

  • 对比三者的执行效率:

/*
	 * 对比三者的执行效率
	 *   从高到低:
	 *   StringBuilder > StringBuffer > String
	 */
	@Test
	public void test3() {
		// 初始设置
		long startTime = 0L;
		long endTime = 0L;
		String text = "";
		StringBuffer buffer = new StringBuffer("");
		StringBuilder builder = new StringBuilder("");
		// 开始对比
		startTime = System.currentTimeMillis();
		for (int i = 0; i < 20000; i++) {
			buffer.append(String.valueOf(i));
		}
		endTime = System.currentTimeMillis();
		System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
		
		
		startTime = System.currentTimeMillis();
		for (int i = 0; i < 20000; i++) {
			builder.append(String.valueOf(i));
		}
		endTime = System.currentTimeMillis();
		System.out.println("StringBuilder的执行时间:" + (endTime - startTime));
		
		
		startTime = System.currentTimeMillis();
		for (int i = 0; i < 20000; i++) {
			text = text + i;
		}
		endTime = System.currentTimeMillis();
		System.out.println("String的执行时间:" + (endTime - startTime));

	}

2.4 StringBuilder和StringBuffer的常用方法

/*
	 * 
	 * 二、StringBuffer和StringBuilder中的常用方法
	 * 
	 * StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接 StringBuffer
	 * delete(int start,int end):删除指定位置的内容 
	 * StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str 
	 * StringBuffer insert(int offset,xxx):在指定位置插入xxx 
	 * StringBuffer reverse() :把当前字符序列逆转 
	 * public intindexOf(String str) 
	 * public String substring(int start,int end) 
	 * public int length() 
	 * public char charAt(int n ) 
	 * public void setCharAt(int n ,char ch)
	 * 
	 * 总结: 
	 * 增:append(xxx) 
	 * 删:delete(int start,int end) 
	 * 改:setCharAt(int n ,char ch) / replace(int start, int end, String str) 
	 * 查:charAt(int n ) 
	 * 插:insert(int offset, xxx)
	 * 长度:length() 
	 * 遍历:for + charAt() / toString()
	 * 
	 * 
	 */
	@Test
	public void test2() {
		StringBuffer s1 = new StringBuffer();
		s1.append("abc").append("def").append("123");// 方法链的调用
		System.out.println(s1);

		s1.replace(3, 6, "hello");
		System.out.println(s1);

		s1.insert(3, "123");
		System.out.println(s1);

	}

三、比较器

实现对象的排序,可以考虑两种方法:

  • 实现Comparable接口

  • 实现Comparator接口

3.1 自然排序:Comparable

   1. 像String、包装类、Date等已经实现了Comparable接口,则可以实现同一个类的不同对象的大小的比较。
 * 
 * 2. 默认情况下,String、包装类、Date等类型进行排序的话,默认从小到大的方式排序
 * 
 * 3. 自定义的类,要想实现排序,需要考虑实现Comparable接口,重写compareTo()。
 *    在此方法中,指明如何比较大小。
 *    标准:
 * 		如果当前对象大,返回正数
 * 		如果当前对象小,返回负数
 * 		如果两个对象相等,返回0

练习1:

    @Test
	public void test1(){
		String[] arr = new String[]{"BB","DD","GG","JJ","MM","AA"};
		
		System.out.println(Arrays.toString(arr));
		
		//能给String排序的前提,是String对象可以比较大小
		Arrays.sort(arr);
		
		System.out.println(Arrays.toString(arr));
	}

练习2:

@Test
	public void test2(){
		Goods g1 = new Goods("Lenovo", 7800);
		Goods g2 = new Goods("Huawei", 8800);
		Goods g3 = new Goods("Dell", 5800);
		Goods g4 = new Goods("Xiaomi", 4800);
		Goods g5 = new Goods("HP", 9800);
		
		Goods[] arr = new Goods[]{g1,g2,g3,g4,g5};
		
		for(int i = 0;i < arr.length;i++){
			System.out.println(arr[i]);
		}
		//排序:
		Arrays.sort(arr);
		System.out.println();
		
		for(int i = 0;i < arr.length;i++){
			System.out.println(arr[i]);
		}
	}

其中,Goods定义如下:

package com.atguigu.java1;

public class Goods implements Comparable{//商品
	
	private String name;
	private double price;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public Goods() {
		super();
	}
	public Goods(String name, double price) {
		super();
		this.name = name;
		this.price = price;
	}
	@Override
	public String toString() {
		return "Goods [name=" + name + ", price=" + price + "]";
	}
	
	//按照产品的价格进行排序
	/*
	 * 标准:
	 * 如果当前对象大,返回正数
	 * 如果当前对象小,返回负数
	 * 如果两个对象相等,返回0
	 */
	@Override
	public int compareTo(Object o) {
		System.out.println("compare....");
		if(o instanceof Goods){
			Goods g = (Goods)o;
			
			//方式一:
//			if(this.price > g.price){
//				return 1;
//			}else if(this.price < g.price){
//				return -1;
//			}else{
//				return 0;
//			}
			
			//方式二:
			return -Double.compare(this.price, g.price);
		}
		
		throw new RuntimeException("输入的类型不匹配");
	}
	
	

}

补充练习:针对Goods类,① 按照产品的名称排序 ②先按照价格排序,再按照产品名称排序 ③ ②先按照价格排序,再按照产品名称从高到低排序

3.2 定制排序:Comparator

问题的引入:
 * ① 针对于StringBuffer 或 StringBuilder的多个对象构成的数组,如何实现排序呢?
 * ② 针对于String、Date、包装类,如何实现从大到小的顺序排序呢?
 * 
 * 1. 除了使用自然排序之外,还可以使用定制排序:实现Comparator接口
 * 
 * 2. 步骤:
 *   ① 提供实现Comparator接口的类
 *   ② 重写compare(Object o1,Object o2),指明对象如何比较大小
 *   ③ 实例化Comparator接口的类,并在需要的位置使用即可。

练习1:

@Test
	public void test1(){
		Goods g1 = new Goods("Lenovo", 7800);
		Goods g2 = new Goods("Huawei", 8800);
		Goods g3 = new Goods("Dell", 5800);
		Goods g4 = new Goods("Xiaomi", 4800);
		Goods g5 = new Goods("HP", 9800);
		Goods g6 = new Goods("Hasee", 9800);
		Goods g7 = new Goods("Apple", 9800);
		
		Goods[] arr = new Goods[]{g1,g2,g3,g4,g5,g6,g7};
		
		for(int i = 0;i < arr.length;i++){
			System.out.println(arr[i]);
		}
		
		//创建Comparator接口的匿名实现类的对象
		Comparator comparator = new Comparator(){
			
			//在此方法中指明如何比较两个对象的大小
			//先安排价格排序,再按照产品名称从高到低排序
			@Override
			public int compare(Object o1, Object o2) {
				if(o1 instanceof Goods && o2 instanceof Goods){
					Goods g1 = (Goods)o1;
					Goods g2 = (Goods)o2;
					
					int result = Double.compare(g1.getPrice(), g2.getPrice());
					if(result != 0){
						return result;
					}
					
					return -g1.getName().compareTo(g2.getName());
					
				}
				throw new RuntimeException("输入的类型不匹配");
			}
			
		};
		
		//排序:
		Arrays.sort(arr,comparator);
		System.out.println();
		
		for(int i = 0;i < arr.length;i++){
			System.out.println(arr[i]);
		}
	}

补充练习:创建String类型的数组,按照字符串从大到小的顺序排序。

@Test
	public void test2(){
		String[] arr = new String[]{"BB","DD","GG","JJ","MM","AA"};
		
		System.out.println(Arrays.toString(arr));
		
		//能给String排序的前提,是String对象可以比较大小
		Arrays.sort(arr,new Comparator(){

			@Override
			public int compare(Object o1, Object o2) {
				if(o1 instanceof String && o2 instanceof String){
					String s1 = (String)o1;
					String s2 = (String)o2;
					return -s1.compareTo(s2);
				}
				throw new RuntimeException("输入的类型不匹配");
			}
			
		});
		
		System.out.println(Arrays.toString(arr));
	}

3.3 体会Comparable和Comparator的区别?

  • Comparable:理解为一劳永逸的方式。

  • Comparator:理解为一种临时的方式。

四、jdk8之前的日期时间的API

4.1 System.currentTimeMillis()

@Test
	public void test1(){
		//通常用来计算时间差。
		long time = System.currentTimeMillis();
		System.out.println(time);//1584087639264
	}

4.2 两个Date类

/*
	 * java.util.Date
	 * 1. 两个构造器:Date() / Date(long millitime)
	 * 2. 两个方法:toString() / getTime()
	 * 
	 * 子类:java.sql.Date
	 * 
	 */
	@Test
	public void test2(){
		//空参的构造器:创建对应当前时间的Date对象
		Date d1 = new Date();
		System.out.println(d1);//Fri Mar 13 16:25:15 GMT+08:00 2020
		
		//getTime():返回此date对象对应的时间戳
		long time = d1.getTime();//1584087969232
		System.out.println(time);
		System.out.println(System.currentTimeMillis());
		
		//创建指定时间戳对应的Date对象
		Date d2 = new Date(15840879232L);
		System.out.println(d2);//Fri Jul 03 16:14:39 GMT+08:00 1970
	}
	
	@Test
	public void test3(){
		java.sql.Date date1 = new java.sql.Date(15840879232L);
		System.out.println(date1);//1970-07-03
		
		System.out.println(date1.getTime());//15840879232
	
	}
	
	//练习:有一个java.util.Date的对象,如何转换为同时间的java.sql.Date类的对象
	@Test
	public void test4(){
//		Date date1 = new Date(23235222423234L);
//		//ClassCastException
//		java.sql.Date date2 = (java.sql.Date) date1;
//		System.out.println(date2);
		
		Date date1 = new Date(23235222423234L);
		java.sql.Date date2 = new java.sql.Date(date1.getTime());
	}

4.3 SimpleDateFormat类

/*
	 * SimpleDateFormat:使用此类实现格式化和解析操作
	 * 
	 * 格式化:日期--->字符串
	 * 解析:字符串--->日期
	 * 
	 * 比如:"1995-03-01"转换为对应的日期对象
	 */
	@Test
	public void test5() throws ParseException{
		SimpleDateFormat sdf = new SimpleDateFormat();
		Date date1 = new Date();
		//格式化过程:
		String strDate = sdf.format(date1);
		System.out.println(strDate);//20-3-13 下午4:45
		
		//解析过程:
		Date date2 = sdf.parse("20-3-13 下午4:45");
		System.out.println(date2);//Fri Mar 13 16:45:00 GMT+08:00 2020
		
		//使用SimpleDateFormat带参的构造器
//		SimpleDateFormat sdf1 = new SimpleDateFormat("EEE, MMM d, ''yy");
		SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd HH:mm:ss");
		String strDate1 = sdf1.format(date1);
		System.out.println(strDate1);//2020-03-13 16:51:42
		
		Date date3 = sdf1.parse("2020年03月13 20:51:42");
		System.out.println(date3);//Fri Mar 13 20:51:42 GMT+08:00 2020
	}

4.4 Calendar类

/*
	 * 4. Calendar日历类:抽象类
	 * 
	 * 
	 */
	@Test
	public void test6(){
		//返回Calendar子类的一个对象
		Calendar calendar = Calendar.getInstance();
		System.out.println(calendar);
		
		//get()
		System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
		System.out.println(calendar.get(Calendar.DAY_OF_WEEK));
		System.out.println(calendar.get(Calendar.DAY_OF_YEAR));
		
		//set()
		calendar.set(Calendar.DAY_OF_MONTH, 23);
		System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
		//add()
		calendar.add(Calendar.DAY_OF_MONTH, -2);
		System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
		//getTime():获取当前日历对象对应的日期Date对象
		Date date = calendar.getTime();
		System.out.println(date);//Sat Mar 21 17:03:56 GMT+08:00 2020

		
		//setTime(Date d):使用指定的日期Date对象重置Calendar对象
		calendar.setTime(new Date());
		System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
	}
  • 日期时间API的发展
    • 第一代:Date
    • 第二代:Calendar
    • 第三代:java8新的日期时间的api
  • 原有的api的问题
    • 可变性:像日期和时间这样的类应该是不可变的。
    • 偏移性:Date中的年份是从1900开始的,而月份都从0开始。
    • 格式化:格式化只对Date有用,Calendar则不行。
    • 此外,它们也不是线程安全的;不能处理闰秒等。
    @Test
	public void test1() {
		String str1 = "hello";
		String str2 = str1.replace('h', 'm');
		System.out.println(str1);
		System.out.println(str2);

		// Calendar的可变性
		Calendar calendar = Calendar.getInstance();
		System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
		calendar.set(Calendar.DAY_OF_MONTH, 23);
		System.out.println(calendar.get(Calendar.DAY_OF_MONTH));

		// 偏移性:Date中的年份是从1900开始的,而月份都从0开始
		Date date = new Date(2020 - 1900, 3 - 1, 14);
		System.out.println(date);// 2020-03-14
	}

4.5 LocalDate\LocalTime\LocalDateTime

/*
	 * 1. LocalDate,LocalTime,LocalDateTime 类似于Calendar
	 */
	@Test
	public void test2() {
		// now():获取当前时间的对象
		LocalDate localDate = LocalDate.now();
		LocalTime localTime = LocalTime.now();
		LocalDateTime localDateTime = LocalDateTime.now();

		System.out.println(localDate);// 2020-03-14
		System.out.println(localTime);// 10:23:29.084
		System.out.println(localDateTime);// 2020-03-14T10:23:29.084
		// of():获取指定时间的对象
		LocalDateTime localDateTime1 = LocalDateTime.of(2020, 3, 14, 11, 24, 34);
		System.out.println(localDateTime1);// 2020-03-14T11:24:34

		// getXxx():
		int dayOfYear = localDateTime.getDayOfYear();
		System.out.println(dayOfYear);
		// withXxx():体现了不可变性
		LocalDateTime localDateTime2 = localDateTime.withDayOfMonth(24);
		System.out.println(localDateTime.getDayOfMonth());
		System.out.println(localDateTime2.getDayOfMonth());

		// plusXxx():
		LocalDateTime localDateTime3 = localDateTime.plusDays(3);
		System.out.println(localDateTime.getDayOfMonth());
		System.out.println(localDateTime3.getDayOfMonth());

	}

4.6 Instant

/*
	 * Instant:瞬时点 类似于Date类
	 */
	@Test
	public void test3() {
		// now():获取当前时间的instant的实例
		Instant instant = Instant.now();
		System.out.println(instant);
		//
		OffsetDateTime dateTime = instant.atOffset(ZoneOffset.ofHours(8));
		System.out.println(dateTime);

		// toEpochMilli():获取时间戳
		long epochMilli = instant.toEpochMilli();
		System.out.println(epochMilli);
		System.out.println(new java.util.Date().getTime());

		// 获取指定毫秒数的instant实例
		Instant instant1 = Instant.ofEpochMilli(234325435234L);
		System.out.println(instant1);
	}

4.7 DateTimeFormatter

/*
	 * DateTimeFormatter用于格式化和解析操作
	 * 
	 * 类似于SimpleDateFormat
	 * 
	 */
	@Test
	public void test4() {
		// 方式一:预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
		DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
		// 格式化:日期-->字符串
		LocalDateTime localDateTime = LocalDateTime.now();
		String str1 = formatter.format(localDateTime);
		System.out.println(localDateTime);
		System.out.println(str1);// 2019-02-18T15:42:18.797

		// 解析:字符串 -->日期
		TemporalAccessor parse = formatter.parse("2019-02-18T15:42:18.797");
		System.out.println(parse);

		// 方式二:
		// 本地化相关的格式。如:ofLocalizedDateTime()
		// FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT
		// :适用于LocalDateTime
		DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
		// 格式化
		String str2 = formatter1.format(localDateTime);
		System.out.println(str2);// 2019年2月18日 下午03时47分16秒

		// 本地化相关的格式。如:ofLocalizedDate()
		// FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM /
		// FormatStyle.SHORT : 适用于LocalDate
		DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
		// 格式化
		String str3 = formatter2.format(LocalDate.now());
		System.out.println(str3);// 2020年3月14日 星期六
		
		//方式三:自定义的方式(关注、重点)
		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss");
		//格式化
		String strDateTime = dateTimeFormatter.format(LocalDateTime.now());
		System.out.println(strDateTime);
		//解析
		TemporalAccessor accessor = dateTimeFormatter.parse("2020/03/14 10:45:24");
		System.out.println(accessor);
	}

四、其他api (了解)

4.1 System

  • currentTimeMillis()
  • exit(0):退出程序
  • gc():强制调用垃圾回收器,回收垃圾

4.2 Math

java.lang.Math提供了一系列静态方法用于科学计算。其方法的参数和返回值类型一般为double型。
abs     绝对值
acos,asin,atan,cos,sin,tan  三角函数
sqrt     平方根
pow(double a,doble b)     a的b次幂
log    自然对数
exp    e为底指数
max(double a,double b)
min(double a,double b)
random()      返回0.0到1.0的随机数
long round(double a)     double型数据a转换为long型(四舍五入)
toDegrees(double angrad)     弧度—>角度
toRadians(double angdeg)     角度—>弧度

4.3 BigInteger和BigDecimal

  • BigInteger:可以表示任何精度的整数
  • BigDecimal:可以表示任何精度的浮点型值
@Test
	public void testBigInteger() {
	    BigInteger bi = new BigInteger("12433241123");
	    BigDecimal bd = new BigDecimal("12435.351");
	    BigDecimal bd2 = new BigDecimal("11");
	    System.out.println(bi);
	    // System.out.println(bd.divide(bd2));
	    System.out.println(bd.divide(bd2, BigDecimal.ROUND_HALF_UP));
	    System.out.println(bd.divide(bd2, 15, BigDecimal.ROUND_HALF_UP));
	}

五、练习题

练习1: 将字符串”2020-03-15”转换为java.sql.Date对象

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date = sdf.parse("2020-03-15");
java.sql.Date d1 = new java.sql.Date(date.getTime());

练习2:

public class Test1 {
	private static void change(String s, StringBuffer sb) {
		s = "aaaa";
		sb.setLength(5);
		sb.append("aaaa");
	}

	public static void main(String[] args) {
		String s = "bbbb";
		StringBuffer sb = new StringBuffer("bbbb");
		change(s, sb);
		System.out.println(s + sb);//bbbbaaaa
	}
}

练习3:

public class Test2 {
	public static void main(String[] args) {
		StringBuffer a = new StringBuffer("A");
		StringBuffer b = new StringBuffer("B");
		operate(a, b);
		System.out.println(a + "," + b);//ABx,B
	}

	public static void operate(StringBuffer x, StringBuffer y) {
		x.append(y);//a:AB
		y = x;//y:AB
		y.append('x');//ABx
	}
}

练习4:

class TEXT {
	public int num;
	public String str;

	public TEXT(int num, String str) {
		this.num = num;
		this.str = str;
	}
}

public class Test3 {
	public static void f1(TEXT tIn, int intIn, Integer integerIn, String strIn) {
		tIn.num = 200;
		tIn.str = "bcd";
		intIn = 200;
		integerIn = 200;
		strIn = "bcd";
	}

	public static void main(String[] args) {
		TEXT tIn = new TEXT(100, "abc");
		int intIn = 100;
		Integer integerIn = 100;
		String strIn = "abc";
		f1(tIn, intIn, integerIn, strIn);
		System.out.println(tIn.num + tIn.str + intIn + integerIn + strIn);
		//200,bcd,100,100,abc
	}
}

练习5:

public class Test4 {
	public static void main(String[] args) throws Exception {
		String str = "中国";
		//在ISO8859-1中,一个字符使用一个字节来存储。
		System.out.println(str.getBytes("ISO8859-1").length);//2
		System.out.println(str.getBytes("GBK").length);//4
		System.out.println(str.getBytes("UTF-8").length);//6
		System.out.println(new String(str.getBytes("ISO8859-1"), "ISO8859-1"));//乱码
		System.out.println(new String(str.getBytes("GBK"), "GBK"));//中国
		System.out.println(new String(str.getBytes("UTF-8"), "UTF-8"));//中国
	}
}

六、小结

  • String\StringBuffer\StringBuilder

  • String的相关知识点见昨天的复习

  • 【面试题】区分String、StringBuffer、StringBuilder

    • 关于StringBuffer、StringBuilder的源码
    • StringBuffer\StringBuilder中常用方法:增、删、改、查、插、长度、反转
  • 比较器:Comparable、Comparator接口

    • Java中的对象只要涉及到比较大小或排序,就会考虑这两个接口之一。
    • 自然排序:让需要排序或比较大小的对象所在的类去实现Comparable接口
      • “一劳永逸”
      • 在要重写的compareTo(Object obj)中指明如何判断对象的大小。
    • 定制排序:在需要使用的场景中,通常会有相应的方法,需要传入comparator。即指明按照此comparator对象中的方式进行多个对象的排序或比较大小。
      • “临时的,灵活的”
      • 比如:Arrays.sort(T[] arr,comparator),TreeSet(comparator),TreeMap(comparator)
      • 需要重写的方法是compare(Object o1,Object o2),就按照此方法进行多个对象比较大小的判断
  • JDK8之前日期时间的API

    • System.currentTimeMillis()
    • java.util.Date 及子类java.sql.Date
      • java.util.Date 两个构造器,两个方法
    • 涉及格式化和解析的SimpleDateFormat
      • 格式化:format,日期—> 字符串
      • 解析:parse , 字符串—> 日期
    • 日历类:Calendar
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是 Java 常用的 100 个内置方法: 1. public static void main(String[] args):程序的主方法,是程序的入口。 2. System.out.println():输出数据到控制台。 3. Scanner scanner = new Scanner(System.in):从控制台读取用户输入。 4. Integer.parseInt():将字符串转换成整数。 5. Double.parseDouble():将字符串转换成双精度浮点数。 6. String.format():格式化字符串。 7. String.equals():比较两个字符串是否相等。 8. String.substring():获取子字符串。 9. String.indexOf():查找指定字符或子字符串的位置。 10. String.replace():替换字符串中的指定字符或子字符串。 11. String.split():根据指定字符或子字符串分割字符串。 12. String.toCharArray():将字符串转换成字符数组。 13. String.valueOf():将其他型的数据转换成字符串。 14. Arrays.sort():对数组进行排序。 15. Arrays.asList():将数组转换成集合。 16. Collections.sort():对集合进行排序。 17. Collections.reverse():反转集合中的元素顺序。 18. Collections.shuffle():随机打乱集合中的元素顺序。 19. Math.abs():求绝对值。 20. Math.max():求两个数中的最大值。 21. Math.min():求两个数中的最小值。 22. Math.pow():求幂次方。 23. Math.sqrt():求平方根。 24. Math.round():四舍五入。 25. Math.random():生成一个随机数。 26. StringBuilder.append():将字符串添加到 StringBuilder 对象中。 27. StringBuilder.insert():在 StringBuilder 对象的指定位置插入字符串。 28. StringBuilder.delete():删除 StringBuilder 对象中的字符。 29. StringBuilder.reverse():反转 StringBuilder 对象中的字符。 30. File.exists():判断文件或目录是否存在。 31. File.isFile():判断路径是否为文件。 32. File.isDirectory():判断路径是否为目录。 33. File.getName():获取文件或目录的名称。 34. File.getAbsolutePath():获取文件或目录的绝对路径。 35. File.getParent():获取文件或目录的父级目录。 36. File.length():获取文件的大小。 37. File.delete():删除文件或目录。 38. FileInputStream.read():从文件中读取一个字节。 39. FileInputStream.read(byte[] b):从文件中读取一组字节。 40. FileInputStream.available():获取文件中还剩下的字节数。 41. FileOutputStream.write(int b):向文件中写入一个字节。 42. FileOutputStream.write(byte[] b):向文件中写入一组字节。 43. FileOutputStream.flush():刷新输出流,将缓冲区中的数据写入文件。 44. FileInputStream.close():关闭输入流。 45. FileOutputStream.close():关闭输出流。 46. BufferedReader.readLine():从文件中读取一行数据。 47. BufferedWriter.write(String s):向文件中写入一行数据。 48. BufferedWriter.flush():刷新输出流,将缓冲区中的数据写入文件。 49. BufferedReader.close():关闭输入流。 50. BufferedWriter.close():关闭输出流。 51. Date.toString():将日期对象转换成字符串。 52. SimpleDateFormat.format():将日期格式化成指定的字符串格式。 53. Calendar.getInstance():获取 Calendar 的实例。 54. Calendar.get():获取 Calendar 对象中指定字段的值。 55. Calendar.set():设置 Calendar 对象中指定字段的值。 56. Calendar.add():为 Calendar 对象的指定字段添加或减去指定的时间量。 57. Arrays.copyOf():复制数组。 58. Arrays.fill():将数组中的元素全部设置为指定的值。 59. Arrays.binarySearch():在有序数组中查找指定的元素。 60. ArrayList.add():将元素添加到 ArrayList 集合中。 61. ArrayList.remove():从 ArrayList 集合中删除指定的元素。 62. ArrayList.get():获取 ArrayList 集合中指定索引位置的元素。 63. ArrayList.set():将 ArrayList 集合中指定索引位置的元素替换成指定元素。 64. ArrayList.contains():判断 ArrayList 集合中是否包含指定的元素。 65. ArrayList.isEmpty():判断 ArrayList 集合是否为空。 66. LinkedList.add():将元素添加到 LinkedList 集合中。 67. LinkedList.remove():从 LinkedList 集合中删除指定的元素。 68. LinkedList.get():获取 LinkedList 集合中指定索引位置的元素。 69. LinkedList.set():将 LinkedList 集合中指定索引位置的元素替换成指定元素。 70. LinkedList.contains():判断 LinkedList 集合中是否包含指定的元素。 71. LinkedList.isEmpty():判断 LinkedList 集合是否为空。 72. HashMap.put():将键值对添加到 HashMap 中。 73. HashMap.get():获取指定键的值。 74. HashMap.remove():从 HashMap 中删除指定键的键值对。 75. HashMap.containsKey():判断 HashMap 中是否包含指定的键。 76. HashMap.containsValue():判断 HashMap 中是否包含指定的值。 77. HashMap.keySet():获取 HashMap 中所有的键。 78. HashMap.values():获取 HashMap 中所有的值。 79. HashSet.add():将元素添加到 HashSet 集合中。 80. HashSet.remove():从 HashSet 集合中删除指定的元素。 81. HashSet.contains():判断 HashSet 集合中是否包含指定的元素。 82. HashSet.isEmpty():判断 HashSet 集合是否为空。 83. TreeSet.add():将元素添加到 TreeSet 集合中。 84. TreeSet.remove():从 TreeSet 集合中删除指定的元素。 85. TreeSet.contains():判断 TreeSet 集合中是否包含指定的元素。 86. TreeSet.isEmpty():判断 TreeSet 集合是否为空。 87. Iterator.hasNext():判断迭代器是否还有下一个元素。 88. Iterator.next():获取迭代器的下一个元素。 89. Iterator.remove():从迭代器所在的集合中删除元素。 90. Comparable.compareTo():比较两个对象的大小。 91. Comparator.compare():比较两个对象的大小。 92. Thread.start():启动线程。 93. Thread.sleep():让线程休眠指定的时间。 94. Thread.join():等待线程执行完毕。 95. Thread.yield():让出当前线程的 CPU 时间。 96. Thread.currentThread():获取当前线程对象。 97. Runnable.run():执行线程的任务。 98. ExecutorService.submit():将任务提交给线程池执行。 99. Future.get():获取线程池中某个任务的执行结果。 100. System.currentTimeMillis():获取当前的系统时间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值