Java学习 day14_String

String

String概述

  • 在Java语言中,所有类似“ABC”这样用双引号引起来的字符串,都是String类的对象
  • String类位于java.lang包下,是Java语言的核心类
  • String类提供了字符串表示、比较、查找、截取、大小写转换等各种针对字符串的操作

构造方法(constructor): 多数情况下不用构造方法创建字符串,而是直接赋值

  • 使用String尤其要注意导包问题,导错包会直接导致不能运行main方法
//创建空字符串对象,需要注意的是null != ""
public String()
//把字节数组中的元素转换成字符串,字节数组中可以是字符,也可以是ASCII码值
public String(byte[] bytes)
//同上,不过指定了开始下标和长度
public String(byte[] bytes,int offset,int length)
//同字节数组
public String(char[] value)
//同上,不过指定了开始下标和长度
public String(char[] value,int offset,int count)
//套娃
public String(String original)

String对象的最大特征

引例

键盘输入接收一个字符串s,并用一个temp字符串引用指向它

现在修改原先字符串s(拼接一个字符串),比较s和temp

public class Demo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        String temp = str;
        System.out.println(temp == str); // true
        str = str + " is a random word";
        System.out.println(temp == str); // false,因为会创建新的对象
    }
}

  • 字符串是常量,它的值在创建之后不能更改,也就是说String对象不可变

    • String对象不可变指的是对象的状态不可变,而不是引用中的地址不可变

    • 原因是String中的字符串都是由字符数组装着的,而该数组是final修饰的

字符串常量池

Java当中所有双引号引起来的字符串都是字符串对象

  • 每一个字符串字面值都作为一个对象存储在堆上的字符串常量池中
    • 字面值常量编译时期,就能确定其取值,编译时期加入常量池
    • 当后续再使用字面值创建相同内容的字符串对象时,直接将该对象返回给引用
    • 如果使用new关键字创建相同内容字符串对象,对象不共享,**但是字符数组仍然共享 **
      在这里插入图片描述
      在这里插入图片描述

字符串是JVM堆内存中最多的对象,字符串不可变后,就可以共享,节省了大量的堆内存空间

不可变后还变得更安全(多线程,网络传输中可以体现)

不可变后效率提升(字符串不可变不需要频繁计算hashCode()值,所以String是Map中最常见的key)

小试牛刀

  • 看程序说结果

    • String s = "hello";
      s += "world";
      System.out.println(s); //hello world
      
  • 下面两种赋值方式有什么区别?

    • String s1 = "我是猪"; //直接创建了常量池,然后常量池指向一个final修饰的char类型数组
      String s = new String("我是猪");//创建String对象,然后也指向和上面同一个数组
      
  • 看程序说结果

    • String s1 = new String("hello");
      String s2 = new String("hello");
      System.out.println(s1 == s2); //false
      System.out.println(s1.equals(s2));//true
      
      String s3 = new String("hello");
      String s4 = "hello";
      System.out.println(s3 == s4); //false
      System.out.println(s3.equals(s4));//true
      
      String s5 = "hello";
      String s6 = "hello";
      System.out.println(s5 == s6); // true,因为都在常量池中
      System.out.println(s5.equals(s6)); // true
      
  • 看程序说结果

    • String s1 = "hello";
      String s2 = "world";
      String s3 = "helloworld";
      System.out.println(s3==(s1+s2));//false,s1和s2是两个变量拼接,拼接的结果在堆上,而s3在常量池中,两个都是常量拼接结果才会在常量池中
      //s1和s2编译时还不能确定它们中的值是什么,但如果你拼接“hello”和“world”,编译时就能确定取值
      System.out.println(s3.equals(s1+s2)); // true
      
      System.out.println(s3==("hello"+"world")); //true
      System.out.println(s3.equals("hello"+"world"));
      

使用加号对字符串进行拼接操作,会有下述两种结果

  • 直接在常量池中创建新的拼接对象
  • 在堆上创建新的拼接对象

经过测试我们发现

  • 当参与字符串拼接的两个字符串中,至少有一个是以引用变量的形式出现时
  • 必然会在堆上创建新的字符串对象
    • 原因是变量参与了运算,无法在编译时期确定其值,就不能在编译时期加入常量池
  • 只有参与字符串拼接运算的两个字符串,都是字符串字面值常量的时候
  • 此时不会在堆上创建新的字符串对象,而是在常量池中直接拼接创建对象
  • 如果已存在,则不创建新的对象

Clone()的例子中,String也是引用类型,但是其对象不需要深度克隆,因为只要对象改变了,就会创建新的对象,所以不需要我们手动创建新的对象


String API

String是开发中最常见的需要操作的对象,没有之一

String天天见,所以我们要对String的操作至少有个脸熟,大概知道String类能做什么

以下方法不要求都背住,但是应该能够了解有这些方法,并可以在实际开发中随着使用而熟记

String类的判断功能

//用来比较字符串的内容,注意区分大小写
boolean equals(Object obj)
    
//忽略字符串大小写比较字符串内容,常见用于比较网址URL
boolean equalsIgnoreCase(String str)
    
//判断当前字符串对象是否包含,目标字符串的字符序列,常见用于确定是否有盗链行为
boolean contains(String str)
    
//判断当前字符串对象,是否已目标字符串的字符序列开头
boolean startsWith(String str)
    
//判断当前字符串,是否以目标字符串对象的字符序列结尾,常用于确定文件后缀名格式
boolean endsWith(String str)
    
//判断一个字符串,是不是空字符串
boolean isEmpty()

String类的获取功能

// 获取当前字符串对象中,包含的字符个数
int length()  
    
//获取字符串对象代表字符序列中,指定位置的字符
char charAt(int index) 
    
//在当前字符串对象中查找指定的字符,如果找到就返回字符,首次出现的位置,如果没找到返回-1
//也可以填字符
int indexOf(int ch) 
    
//指定从当前字符串对象的指定位置开始,查找首次出现的指定字符的位置,(如果没找到返回-1)
//可以填入字符
int indexOf(int ch,int fromIndex) 
    
//查找当前字符串中,目标字符串首次出现的位置(如果包含),找不到,返回-1
//这里的位置是指目标字符串的第一个字符,在当前字符串对象中的位置
int indexOf(String str)

//指定,从当前字符串对象的指定位置开始,查找首次出现的指定字符串的位置(如果没找到返回-1)
//这里的位置是指目标字符串的第一个字符,在当前字符串对象中的位置
int indexOf(String str,int fromIndex)//返回字符串,该字符串只包含当前字符串中,从指定位置开始(包含指定位置字符)到结束的那部分字符串
String substring(int start) 
    
//返回字符串,只包含当前字符串中,从start位置开始(包含),到end(不包含)指定的位置的字符串
String substring(int start,int end) 

String类的转换功能

//获取一个用来表示字符串对象字符序列的,字节数组
byte[] getBytes()
    
//获取的是用来表示字符串对象字符序列的,字符数组
char[] toCharArray() 

//使用指定字符集,将字符编码成字节序列,并将结果存储到一个新的 byte 数组中
getBytes(String charsetName) 

//将字符从此字符串复制到目标字符数组
getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
    
//把字符数组转换成字符串
static String valueOf(char[] chs)

//把各种基本数据类型和对象转换成字符串
static String valueOf(int i/double...)


//把字符串全部转化为小写
String toLowerCase() 
    
//把字符串全部转换为大写
String toUpperCase()

//字符串拼接,作用等价于 + 实现的字符串拼接
String concat(String str) 

String类的其他功能

  • 替换功能

    • // 在新的字符串中,用新(new)字符,替换旧(old)字符
      String replace(char old,char new)
          
      //在新的字符串中,用新的字符串(new), 替换旧(old)字符串
      String replace(String old,String new)
      
    • 需要注意的是,替换不是在原对象上替换,而是创建了新的对象

  • 去除空格字符

    • //在新的字符串中,去掉开头和结尾的空格字符
      String trim() 
      
  • 比较功能

    • String类的比较功能
      int compareTo(String str)
      int compareToIgnoreCase(String str)
      
    • 详解字符串如何能够比较大小?怎么比较呢?

    • 首先要明确字符串是由字符组成的,比较字符串的大小,首先要知道字符的大小如何比较

      • 单个字符如何比较大小呢?
        • 单个字符按照字典顺序去比较,实际上比较基于Unicode的编码值
        • 处在字典后面的字符编码值要大,就认为这个字符大

      参考一下源码

      public int compareTo(String anotherString) {
          int len1 = value.length;
          int len2 = anotherString.value.length;
          int lim = Math.min(len1, len2);
          char v1[] = value;
          char v2[] = anotherString.value;
      
          int k = 0;
          while (k < lim) {
              char c1 = v1[k];
              char c2 = v2[k];
              if (c1 != c2) {
                  return c1 - c2;
              }
              k++;
          }
          return len1 - len2;
      }
      

  • String类的compareTo()方法在比较时,通过查看源码,不难得出它是这么比较的

    • 从左往右逐个比较对应字符,如果出现某单个字符不相同,那么返回它们的编码值之差
      • 例如"bcd"和"abc"比较,直接在第一位b就能够确定,b的编码值比a大1
      • 所以该方法返回1,大于0的数
      • 认为"bcd"比"abc"大
    • 如果逐个字符都相同,则返回它们的长度之差
      • 例如"abc"和"abcd"比较,abc都是相同的,得不出结果
      • 由于"abcd"比"abc"长1位
      • 所以该方法返回-1,小于0的数
      • 认为"abc"比“abcd”小
    • 只有完全相同的字符串,才会返回0,认为它们相等
      • 比如"abc"和"abc"方法就会返回0
      • 认为它两相等

Comparable接口

关于comparable接口和comparator如何实现的,可以暂时理解为sort方法需要一个规则来进行排序,而你自己写的实现了comparable接口或者comparator的类,继承的方法就是为了重写这个排序规则的

一个类实现了Comparable接口,就可以对这个类的对象(容器或集合)进行排序

称之为自然排序,其中的compareTo方法被称为它的自然比较方法

  • 实现此接口的类,其对象数组(array)或对象容器(collection)

    • 就可以通过**Arrays.sort()Collections.sort()**进行自动排序
  • 对于实现该接口的A类来说,其对象a1.compareTo(a2)方法返回值

    • 小于0,表示a1对象小于a2,在自然排序中处于前面的位置
    • 大于0,表示a1对象大于a2,在自然排序中处于后面的位置
    • 等于0,表示a1对象等于a2
  • 除了compareTo方法,类中还有equals方法判断两个对象是否相等

    • 建议这两个方法同true同0,同false非0,这样从逻辑上更顺畅
      • 比如一个有序集合,compareTo认为不相等,equals方法认为相等,可能导致集合添加元素失败
    • 实际上,所有实现 Comparable 的 Java 核心类都具有与 equals 一致的自然排序
    • 两个方法都用成员变量的取值重写即可

    几个代码示例

    String s = "abc";
          String s11 = "bcd";
          String s22 = "abccc";
          String s33 = "abddd";
          String s44 = "abc";
          String s55 = "ddd";
    
          //以上对象从大到小排序: s5,s1,s3,s2,s,s4
          String[] arr0 = {s, s11, s22, s33, s44, s55};
          System.out.println("排序之前: " + Arrays.toString(arr0));
          Arrays.sort(arr0);
          System.out.println("排序之后: " + Arrays.toString(arr0));
          /*
          	排序之前: [abc, bcd, abccc, abddd, abc, ddd]
      		排序之后: [abc, abc, abccc, abddd, bcd, ddd]
          */
    
    
    
    

Comparator接口

一个类实现了Comparable接口,往往需要同时重写equals方法,这会增加一些思考量

并且也不是什么时候都能够去随心所欲的修改源码,或者实现一个接口

假如仅仅只是做一次比较,那么用匿名内部类或者lambda表达式

去使用带Comparator比较器的sort方法(Arrays和Conlections中都有该方法)会比较好

  • Comparator接口中的compare方法表示一种排序规则,方法会返回一个int值
    • 该sort方法逐个比较容器中的每两个对象
      • 方法返回负数表示排序中,处在前面的位置
      • 方法返回正数表示排序中,处在后面的位置
    • 最终的效果和Comparable接口一样,但是这种方式需要直接改实体类代码,更灵活
  • Comparator接口中看起来有两个抽象方法compare和equals
    • 但实际上只需要实现compare就可以了,因为任何类都有默认的equals实现
    • 它仍然是一个功能接口,可以使用lambda表达式

直接创建一个工具类,然后把工具类对象传入sort中

public class Demo2 {
    public static void main(String[] args) {
        Cat c = new Cat(1, 500, "小白", 2000);
        Cat c1 = new Cat(3, 3000, "小黄yyds", 3000);
        Cat c2 = new Cat(4, 7500, "小黑hxd", 2000);
        Cat c3 = new Cat(5, 1000, "小红dd", 3000);
        Cat c4 = new Cat(3, 4000, "小绿", 5988);
        Cat c5 = new Cat(2, 5000, "大黄mm", 2345);
        Cat c6 = new Cat(6, 2000, "大白", 3245);
        Cat c7 = new Cat(6, 2000, "大白", 3245);
        Cat c8 = new Cat(17, 1000, "大绿绿了", 3000);
        Cat c9 = new Cat(17, 300, "Tom的舔狗", 6547);
        Cat c10 = new Cat(17, 800, "大绿绿了", 2000);
        Cat c11 = new Cat(17, 300, "Tom的舔狗的舔狗", 1000);
        Cat c12 = new Cat(17, 300, "大绿绿了", 6547);
        Cat c13 = new Cat(17, 300, "Tom的舔狗的舔狗", 6547);
        Cat c14 = new Cat(17, 300, "Tom的舔狗的舔狗的舔狗", 6547);

        Cat[] arr = {c, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14};

        //普通的做法,朴素的做法,直接手写实现子类
        System.out.println("排序前:" +Arrays.toString(arr));
        //该方法不能传入null
        Arrays.sort(arr, new Ruler());
        System.out.println("排序后:" +Arrays.toString(arr));
       
    }
}

class Cat {
    int age;
    double price;
    String name;
    double weight;

    public Cat() {
    }

    public Cat(int age, double price, String name, double weight) {
        this.age = age;
        this.price = price;
        this.name = name;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "age=" + age +
                ", price=" + price +
                ", name='" + name + '\'' +
                ", weight=" + weight +
                '}' + '\n';
    }
}

//朴素的方法获取接口的实现类对象
class Ruler implements Comparator<Cat> {

    @Override
    public int compare(Cat o1, Cat o2) {
        //重写的规则是
        //按照价格的从高到低排序

        return ((int) ((o2.price - o1.price) * (100)));
    }

    //@Override
    //public int compare(Object o1, Object o2) {
    //    //重写的规则是什么?
    //    //按照价格的从高到低排序
    //    return 0;
    //}
}

匿名对象法

 //高级一点的做法: 使用匿名内部类
        System.out.println("排序前:" + Arrays.toString(arr));
        Arrays.sort(arr, new Comparator<Cat>() {
            @Override
            public int compare(Cat o1, Cat o2) {
                //排序规则: 按年龄的从大到小排序
                return o2.age - o1.age;
            }
        });
        System.out.println("排序后:" + Arrays.toString(arr));

lambda表达式

 //高端的写法: lambda表达式
        //System.out.println("排序前:" + Arrays.toString(arr));
        /*Arrays.sort(arr, (cat1, cat2) -> {
            //排序的规则: 重量大的在前面
            return ((int) ((cat2.weight - cat1.weight) * 100));
        });*/
        
        //lambada表达式简化一下
        //Arrays.sort(arr, (cat1, cat2) -> ((int) ((cat2.weight - cat1.weight) * 100)));
        //System.out.println("排序后:" + Arrays.toString(arr));

        System.out.println("排序前:" + Arrays.toString(arr));
        Arrays.sort(arr, Demo2::myCompare);
        System.out.println("排序后:" + Arrays.toString(arr));
public static int myCompare(Cat c1, Cat c2) {
        //具体的比较规则
        //首先按照猫的年龄排序,年龄大的在前面
        //如果年龄是一样的,价格低的在前面
        //如果价格也一样的,谁重谁就在前面
        //如果上面的都一样的,谁的名字长谁就在前面
        if (c1.age != c2.age) {
            //年龄大的在前面
            return c2.age - c1.age;
        }
        if (c1.price != c2.price) {
            //价格低的在前面
            return ((int) ((c1.price - c2.price) * 100));
        }
        if (c1.weight != c2.weight) {
            //重量大的在前面
            return ((int) ((c2.weight - c1.weight) * 100));
        }
        return c2.name.length() - c1.name.length();
    }

可变字符串

String对象是不可变的字符串对象,如果用String直接 “ + ” 拼接频繁创建对象,会有效率问题

可以用以下代码进行测试

String s = "";
for (int i = 0; i < 100000; i++) {
    s += "str";
}
System.out.println(s);
// 出结果很慢,要很久才能出来

不难得出结论

  • 进行字符串拼接时,如果是简单几次拼接,直接用String无伤大雅,并不会有多大的效率问题
  • 但是如果频繁多次修改某个字符串仍然使用String,不仅效率堪忧而且过于浪费空间
  • 为了解决这一问题,Java提供了可变的字符串来解决这个问题

当需要对字符串频繁修改时,需要使用StringBufferStringBuilder 类。

  • 和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改
    • 并且不产生新的未使用对象,不会产生效率问题和空间浪费问题
  • StringBuffer是线程安全的,StringBuilder是线程不安全的
    • StringBuilder的效率会比StringBuffer效率更高,单线程的程序推荐使用StringBuilder
    • 在多线程的程序中,应该优先考虑使用StringBuffer,安全性要更重要
    • 它们的效率都比String高很多
  • 例子:
public class Test{
  public static void main(String args[]){
    StringBuffer sb = new StringBuffer("王道在线论坛官网:");
    sb.append("www");
    sb.append(".cskaoyan");
    sb.append(".com");
    System.out.println(sb); 
  }
}

以上实例编译运行结果如下:

王道在线论坛官网:www.cskaoyan.com

StringBuffer

首先是学习构造方法

// public StringBuffer()  无参构造方法
// public StringBuffer(int capacity)  指定容量的字符串缓冲区对象
// public StringBuffer(String str)  指定字符串内容的字符串缓冲区对象

总结StringBuffer可变长字符串的原理

  • StringBuilder 或 StringBuffer的初始化分配的空间大小取决于调用的构造方法:
    • 无参构造默认大小为 16
    • 调用int单参数构造方法,初始化大小为指定的int值
    • 调用 String 类型的构造方法,初始化大小为:字符串的长度 + 16,比如初始化字符是hello,那长度为21,count=5;
  • 扩容机制每次扩容大小为:原数组大小 * 2 + 2
  • 源码中的count代表已经存在的字符串的长度,即当前缓冲区已存在字符串的长度

StringBuffer常见方法

  • 获取功能
// public int capacity() 返回当前容量,数组的长度,理论值
// public int length() 返回长度(字符的个数),实际值    
  • 添加功能
// public StringBuffer append(String s) 将指定的字符串(其他类型有重载方法)追加到此字符序列的尾部
//在指定位置把任意类型的数据插入到字符串缓冲区里面
// public StringBuffer insert(int offset,String str) 
  • 删除功能
// public StringBuffer deleteCharAt(int index):删除指定位置的字符
// public StringBuffer delete(int start,int end):删除从指定位置开始指定位置结束的内容
  • 替换功能
// 使用给定String中的字符替换词序列的子字符串中的字符
// public StringBuffer replace(int start,int end,String str)
  • 反转功能
// public StringBuffer reverse():将此字符序列用其反转形式取代,返回对象本身
  • 截取功能
// public String substring(int start):返回一个新的String,开头到结束
// public String substring(int start,int end):返回一个新的String,指定区间

StringBuffer对象用char类型value数组存放字符串,但是value数组没有用final修饰


Java日期类

java.util包下提供了 Date 类来封装当前的日期和时间,这个类中绝大多数方法已经过时了

但是作为Java日期类的基本类,仍然有学习的必要

  • Date类表示一个特定的瞬间时间,精确到毫秒

  • 构造方法:目前仍没有过时的只有两个

    • //该构造函数使用当前日期和时间来初始化对象	
      Date()
      
    • //第二个构造函数接收一个参数,该参数是从1970年1月1日起的毫秒数
      Date(long millisec)
      
    • 无参构造方法调用底层的native方法System.currentTimeMillis()方法

      • 该方法会根据操作系统来获取当前的时间戳
    • 时间戳:从格林威治时间(GMT)1970 年 1 月 1 日 00:00:00 到现在的毫秒数

    public class Demo {
     public static void main(String[] args) {
         //1,Date类的无参构造
         Date d = new Date();
         //Thu Jun 24 16:34:27 CST 2021 中国标准时间 = 北京时间
         System.out.println(d);
    
         //2,long构造方法
         Date d2 = new Date(1218196800000L);
         System.out.println(d2);
    
         用自1970年1月1日00:00:00 GMT以后time毫秒数设置时间和日期。
         //void setTime(long time)
    
         返回自1970年1月1日00:00:00 GMT以来此Date对象表示的毫秒数。
         //long getTime( )
         long time = d.getTime();
         System.out.println(time);
    
         d2.setTime(1249732800000L);
         System.out.println(d2);
    
         //创建一个Date对象,然后传入参数0
       
         Date d3 = new Date(0L);
         System.out.println(d3);
     }}
    
    
    
    

  • 成员方法:了解两个即可

    • //用自1970年1月1日00:00:00 GMT以后time毫秒数设置时间和日期。
      void setTime(long time)
      
    • //返回自1970年1月1日00:00:00 GMT以来此Date对象表示的毫秒数。
      long getTime( )
      
  • 中国处在东八区,格林威治时间1970 年 1 月 1 日 00:00:00是中国的1970 年 1 月 1 日 08:00:00

显然这种日期格式和我们生活中的日期格式,相去甚远

为了以更贴近生活中的方式去描述时间,实现直接把一个字符串转换成Date的需求

因此考虑使用别的日期类实现需求

DateFormat是日期和时间格式化子类的抽象类,它能够以自定义的格式解析或者格式化日期和时间

由于其是一个抽象类,所以使用其子类SimpleDateFormat实现日期和字符串的相互转换。

  • SimpleDateFormat的构造方法

    • //以传入的字符串格式进行解析或者格式化日期
      public SimpleDateFormat(String pattern)
      
    • pattern的书写格式

      • y:表示年,例如yyyy,表示千年年份
      • M:表示月份,例如MM,表示月份(最多12,两位数)
      • d:表示月份中的天数,例如dd,表示天数(最多31,两位数)
      • H:表示一天中的小时数,例如HH,表示小时数(最多24,两位数)
      • m:表示小时中的分钟数,例如mm,表示分钟数(最大59,两位数)
      • s:表示分钟里的秒数,例如ss,表示秒数(最大59,两位数)
    • 该对象仅仅只是描述日期的格式,并不代表时间

    • 想要表示时间,仍然要使用Date对象

  • SimpleDateFormat的成员方法

    • //将传入的Date对象按照pattern格式,格式化成一个字符串
      public final String format(Date date)  
      
    • //将传入的字符串按照pattern格式,解析成一个Date对象
      public Date parse(String source)
      
    • parse方法会抛出一个编译时异常ParseException,需要显式处理

      • 当传入的字符串和解析的格式不同,就会抛出该异常
    • format方法不会抛出编译时异常,不需要显式处理

      • 当pattern格式不正确,会抛出异常,非法参数异常

public class DatePattern {
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();

        String time = sdf.format(date);
        System.out.println(time);

        date.setTime(1624599926691L);
        System.out.println(sdf.format(date));

        String time1 = "2021-08-23 23:45:23";
        Date d = sdf.parse(time1);
        System.out.println(d);
    }
}

作业

编写一个Cat类
成员变量:int age,String name,double price
按以下要求进行自然排序:
1,直接实现Comparable接口,按照年龄的从小到大对Cat数组进行自然排序
2,利用Comparator接口,用 匿名内部类和lambda分别对Cat数组进行自然排序
1,按照price的大到小排序
2,name的长短排序,name越长对象越大
3,综合age,name,price进行排序,要求用lambda表达式指向一个方法。
排序的规则是age越小对象越小,age相同比较name长短,name越短对象越小,name长度也相等,比较price,price越大对象越小

// 1,直接实现Comparable接口,按照年龄的从小到大对Cat数组进行自然排序
public class Demo01 {
    public static void main(String[] args) {

        Cat c1 = new Cat(10, "大白", 2932.7);
        Cat c2 = new Cat(3, "二花", 6000);
        Cat c3 = new Cat(5, "Tom", 4000);
        Cat c4 = new Cat(18, "Jerry", 200);
        Cat c5 = new Cat(100, "66", 8000);
        Cat c6 = new Cat(1, "77", 10);
        Cat[] cats = new Cat[]{c1, c2, c3, c4, c5, c6};
        System.out.println("未排序前:" + Arrays.toString(cats));
        Arrays.sort(cats);
        System.out.println("按照年龄从小到大排序:" + Arrays.toString(cats));
    }
}
class Cat implements Comparable{
    int age;
    String name;
    double price;


    @Override
    public int compareTo(Object o) {
        Cat cat = (Cat) o;
        return this.age - cat.age;
    }

    public Cat(int age, String name, double price) {
        this.age = age;
        this.name = name;
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Cat cat = (Cat) o;
        return age == cat.age &&
                Double.compare(cat.price, price) == 0 &&
                Objects.equals(name, cat.name);
    }

    @Override
    public String toString() {
        return this.age + "";
    }
}
// 2,利用Comparator接口,用 匿名内部类和lambda分别对Cat数组进行自然排序
//.   1,按照price的大到小排序(匿名内部类)
public class Demo01_version2 {
    public static void main(String[] args) {
        Cat1 c1 = new Cat1(10, "大白", 2932.7);
        Cat1 c2 = new Cat1(3, "二花", 6000);
        Cat1 c3 = new Cat1(5, "Tom", 4000);
        Cat1 c4 = new Cat1(18, "Jerry", 200);
        Cat1 c5 = new Cat1(100, "66", 8000);
        Cat1 c6 = new Cat1(1, "77", 10);
        Cat1[] cats = new Cat1[]{c1, c2, c3, c4, c5, c6};
        System.out.println("原Cat数组:" + Arrays.toString(cats));
        Arrays.sort(cats, new Comparator<Cat1>() {
            @Override
            public int compare(Cat1 o1, Cat1 o2) {
                return (int)(o2.price - o1.price)*10;
            }
        });

class Cat1{
    int age;
    String name;
    double price;

    public Cat1(int age, String name, double price) {
        this.age = age;
        this.name = name;
        this.price = price;
    }

    public Cat1() {
    }
    @Override
    public String toString() {
        return this.price + "";
    }
}
// name的长短排序,name越长对象越大
public class Demo01_version2 {
    public static void main(String[] args) {
        Cat1 c1 = new Cat1(10, "Jess", 2932.7);
        Cat1 c2 = new Cat1(3, "lalalala", 6000);
        Cat1 c3 = new Cat1(5, "Tom", 4000);
        Cat1 c4 = new Cat1(18, "Jerry", 200);
        Cat1 c5 = new Cat1(100, "Brand", 8000);
        Cat1 c6 = new Cat1(1, "Maylinda", 10);
        Cat1[] cats = new Cat1[]{c1, c2, c3, c4, c5, c6};
        System.out.println("原Cat数组:" + Arrays.toString(cats));
          Arrays.sort(cats, (cat1, cat2)-> cat1.name.length() - cat2.name.length());
          System.out.println(Arrays.toString(cats));
    }
}

class Cat1{
    int age;
    String name;
    double price;

    public Cat1(int age, String name, double price) {
        this.age = age;
        this.name = name;
        this.price = price;
    }
    public Cat1() {
    }
    @Override
    public String toString() {
        return this.name;
    }
}
/**
3,综合age,name,price进行排序,要求用lambda表达式指向一个方法。
排序的规则是age越小对象越小,age相同比较name长短,name越短对象越小,name长度也相等,比较price,price越大对象越小
*/
public class Demo01_version2 {
    public static void main(String[] args) {
        Cat1 c1 = new Cat1(10, "Jess", 2932.7);
        Cat1 c2 = new Cat1(3, "lalalala", 8000);
        Cat1 c3 = new Cat1(5, "Tom", 4000);
        Cat1 c4 = new Cat1(18, "Jerry", 200);
        Cat1 c5 = new Cat1(3, "Brand", 8000);
        Cat1 c6 = new Cat1(1, "Maylinda", 10);
        Cat1[] cats = new Cat1[]{c1, c2, c3, c4, c5, c6};
        System.out.println("原Cat数组:" + Arrays.toString(cats));


          Arrays.sort(cats, Demo01_version2::compare);
        System.out.println(Arrays.toString(cats));
    }

    public static int compare(Cat1 c1, Cat1 c2){
        if(c1.age != c2.age) return c1.age - c2.age;
        else{
            if (c2.price != c1.price) return (int)(c2.price - c1.price)*10;
            else return c1.name.length() - c2.name.length();
        }
    }
}
class Cat1{
    int age;
    String name;
    double price;

    public Cat1(int age, String name, double price) {
        this.age = age;
        this.name = name;
        this.price = price;
    }

    public Cat1() {
    }

    @Override
    public String toString() {
        return "Cat{ " + age +
                ", '" + name + '\'' +
                ", " + price +
                '}';
    }
}


统计大串中小串出现的次数

举例:
在字符串” woaijavawozhenaijavawozhendeaijavawozhendehenaijavaxinbuxinwoaijavagun”中
java出现了5次

public class Demo02 {
    public static void main(String[] args) {
        String str = "woaijavawozhenaijavawozhendeaijavawozhendehenaijavaxinbuxinwoaijavagun";
       // char[] chars = str.toCharArray();
        String substr = "java";
        System.out.println(getCount(str,substr));
    }

    public static int getCount(String str, String subStr){
        int count = 0;
        int index = 0;
        // 这个indexof的方法,是从index位置开始找substr
        while((index = str.indexOf(subStr, index)) != -1){
            count++;
            index += 4;
        }
        return count;
    }
}


制作一个工具类,算一下你来到这个世界多少天?

package homework;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo03 {
    public static void main(String[] args) throws ParseException {
        String birth = "1997/02/21";
        System.out.println("您已经活了" + CalculateDays.days(birth) + "天");
    }
}

class CalculateDays{
    public CalculateDays(){
    }

    public static int days(String birth) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        Date birthDate = sdf.parse(birth);
        Date todayDate = new Date();
        long birthday = birthDate.getTime();
        long today = todayDate.getTime();
        return (int)((today - birthday)/(1000*60*60*24));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值