String的学习

一、创建字符串两种方式的比较

1、String a = “abc”
2、String b = new String(“abc”)
通常将内存分为:方法区(包含常量池)、堆(对象)、栈(变量)
String a = “abc” 变量a存放在栈中,值"abc"存放在常量池,a中保存着"abc"的地址;
String b = new String(“abc”) 对象a存放在堆,值"abc"存放在常量池,a中保存着"abc"的地址

public static void main(String[] args) {
    String a = "abc";
    String d = "abc";
    String b = new String("abc");
    String c = new String("abc");
    System.out.println(a == b);                    // false
    System.out.println(a.equals(b));            // true
    System.out.println(c == b);                   // false
    System.out.println(a == d);                  // true
}

所以:(1)两个对象用判定返回false,但是equals比较的是value值,值相同时返回true
(2)对象和变量用
判定返回也是false
(3)两个变量如果值相同,那么保存的地址相同,所以==判定为true
以上这些可以类比实体类对象的属性,见下方代码

public static void main(String[] args) {
    Person person1 = new Person("zhang",20);
    Person person2 = new Person("zhang",20);
    System.out.println(person1.name == person2.name);             //true
    person1.name = "ming";
    System.out.println(person2.name);                                       //zhang
}

两个对象的name属性都是String类型的变量,都指向"zhang"常量的地址。
所以==比较的是地址,equals比较的是内容。

二、String类型的拼接存储

关于String类型的拼接见下方test

@Test
public void test() {
    String s1 = "abc";
    String s2 = "def";
    String s3 = "abcdef";
    String s4 = s1 + "def";
    String s5 = "abc" + s2;
    String s6 = s1 + s2;
    String s7 = "abc" + "def";
    String s8 = s6.intern();
    System.out.println(s3 == s7);             //true
    System.out.println(s3 == s4);             //false
    System.out.println(s3 == s5);             //false
    System.out.println(s3 == s6);             //false
    System.out.println(s3 == s8);             //true
    System.out.println("***********************");
    System.out.println(s5 == s4);             //false
    System.out.println(s5 == s6);             //false
    System.out.println(s5 == s8);             //false
}

所以常量与常量的拼接在常量池中,新的变量仍保存对应常量池地址,只要拼接部分含有,结果就在堆中,相当于new的对象,String a = 对象.intern(),则a保存对象内容对应的常量池地址

三、一道面试题

public class StringFirst {
    String str = "good";
    String str2 = new String("book");
    char[] array = {'n','e','s','t'};
    void change(String str1, String str2, char[] arr) {
        str1 = "fffff";
        str2 = "ddddd";
        arr[0] = 'b';
    }

    @Test
    public void test() {
        StringFirst first = new StringFirst();
        first.change(first.str, first.str2, first.array);
        System.out.println(first.str);                       //good
        System.out.println(first.str2);                      //book
        System.out.println(first.array);                     //best
    }
}

传参时,基本数据类型传递数据值,引用数据类型传递数据地址

四、String类型的方法

执行方法时,原字符串不改变,返回的结果保存在新的字符串中

@Test
public void function() {
    String s1 = "  abDDef  ";
    String s2 = s1.substring(2);
    String s3 = s1.toLowerCase();
    String s4 = s1.trim();
    System.out.println(s2);          //abDDef
    System.out.println(s3);          //  abddef
    System.out.println(s4);          //abDDef
    System.out.println(s1);          //  abDDef
}

五、String、StringBuffer、StringBuilder的区别

1、String是不可变序列,StringBuffer、StringBuider是可变序列,StringBuffer、StringBuilder默认申请16个字符空间,当容量不够时底层实现扩容(新建长度更大的字符数组,将内容复制到新的数组中)
2、StringBuffer线程安全效率低,StringBuilder线程不安全效率高
3、三者底层都是char[]数组存储
三者执行效率比较

@Test
public void function() {
    long startTime;
    long endTime;
    String str = "";
    StringBuffer str2 = new StringBuffer("");
    StringBuilder str3 = new StringBuilder("");
    startTime = System.currentTimeMillis();
    for (int i = 0; i < 20000; i++) {
        str += String.valueOf(i);      
    }
    endTime = System.currentTimeMillis();
    System.out.println(endTime - startTime);       //执行结果155

    startTime = System.currentTimeMillis();
    for (int i = 0; i < 20000; i++) {
        str2.append(String.valueOf(i));
    }
    endTime = System.currentTimeMillis();
    System.out.println(endTime - startTime);       //执行结果2

    startTime = System.currentTimeMillis();
    for (int i = 0; i < 20000; i++) {
        str3.append(String.valueOf(i));
    }
    endTime = System.currentTimeMillis();
    System.out.println(endTime - startTime);       //执行结果1
}

4、String转成StringBuffer或StringBuilder调用StringBuffer或StringBuilder的构造器;StringBuffer或StringBuilder转成String,调用String的构造器或者调用StringBuffer或StringBuilder的toString()

六、java.util.Date 与 java.sql.Date

@Test
public void function() {
    //java.util.Date 与 java.sql.Date的两个常用方法
    Date date = new Date();
    System.out.println(date.toString());     //Fri Aug 14 10:40:26 CST 2020
    System.out.println(date.getTime());      //1597372826362(时间戳)
    System.out.println(date);                //Fri Aug 14 10:40:26 CST 2020
    java.sql.Date date2 = new java.sql.Date(1597372826362L);
    System.out.println(date2.getTime());     //1597372826362
    System.out.println(date2.toString());    //2020-08-14
    System.out.println(date2);               //2020-08-14

    //java.sql.Date 是 java.util.Date的子类
    Date date3 = date2;
    System.out.println(date3);               //2020-08-14
    Date date4 = new Date();
    java.sql.Date date5 = new java.sql.Date(date4.getTime());
    System.out.println(date5);               //2020-08-14
}

另外,SimpleDateFormat类可以实现格式化和解析日期

@Test
public void function() throws ParseException {
    //实例化SimpleDateFormat对象的格式
    SimpleDateFormat sim = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    Date date = new Date();
    //格式化日期返回字符串
    String str = sim.format(date);
    System.out.println(str);                 //输出2020-08-14 06:19:55
    //参数是要解析的日期对应的字符串,格式要与对象格式一致,返回日期类型
    Date date2 = sim.parse("2020-08-14 18:19:20");
    System.out.println(date2);               //输出Fri Aug 14 18:19:20 CST 2020
}

七、字符串的编码与解码

@Test
public void function() throws UnsupportedEncodingException {
    //字符串的编码
    /**
     * gbk编码中一个汉字占两个字节,utf-8中一个汉字占3个字节
     */
    String str = "abc123中国";
    byte[] bytes = str.getBytes();     //使用默认的字符集编码utf-8
    System.out.println(Arrays.toString(bytes));    //[97, 98, 99, 49, 50, 51, -28, -72, -83, -27, -101, -67]
    byte[] bytes2 = str.getBytes("gbk");
    System.out.println(Arrays.toString(bytes2));   //[97, 98, 99, 49, 50, 51, -42, -48, -71, -6]
    //字符串的解码
    String str2 = new String(bytes);
    System.out.println(str2);               //abc123中国
    String str3 = new String(bytes2);
    System.out.println(str3);               //abc123�й�,出现乱码是因为编码使用gbk,解码使用utf-8
    str3 = new String(bytes2,"gbk");
    System.out.println(str3);               //abc123中国
}

八、Comparable接口和Comparator接口

Arrays.sort() 方法可以实现对String以及基本数据类型数组的排序,是因为String等实现了Comparable接口,所以自定义的实体类可以实现Comparable接口,从而也能排序

//String类因为实现了Comparable接口所以可以使用Arrays.sort()排序
@Test
public void function() {
    String[] strs = new String[]{"DD","AA","FF","MM","BB","CC"};
    Arrays.sort(strs);
    System.out.println(Arrays.toString(strs));
}
//创建的实体类PhoneShop对象实现Comparable接口排序
//先按照name从小到大,再按照price从大到小排序
@Test
public void test() {
    PhoneShop phone1 = new PhoneShop("lianxiang", 50.00);
    PhoneShop phone2 = new PhoneShop("huawei", 39);
    PhoneShop phone3 = new PhoneShop("xiaomi", 60.03);
    PhoneShop phone4 = new PhoneShop("microsoft", 100);
    PhoneShop phone5 = new PhoneShop("huawei", 55.29);
    PhoneShop phone6 = new PhoneShop("sanxing", 66.33);
    PhoneShop phone7 = new PhoneShop("huawei", 93.09);
    PhoneShop[] shops = new PhoneShop[]{phone1, phone2, phone3, phone4, phone5, phone6, phone7};
    //Arrays.sort()实现排序,要求参数Object对象实现Comparable接口
    Arrays.sort(shops);
    /**
     * 1、Arrays.toString()实现将对象数组中的对象.toString()之后的内容拼接[],形成字符串
     * 2、toString()是 Object类的方法,默认显示对象的类名,一般可以在实体类中重写内容
     */
    System.out.println(Arrays.toString(shops));
}
//通过Comparator接口自定义排序
//先按照price从小到大,再按照name从小到大排序
@Test
public void test2() {
    PhoneShop phone1 = new PhoneShop("lianxiang", 80.00);
    PhoneShop phone2 = new PhoneShop("huawei", 39);
    PhoneShop phone3 = new PhoneShop("xiaomi", 60.03);
    PhoneShop phone4 = new PhoneShop("microsoft", 100);
    PhoneShop phone5 = new PhoneShop("huawei", 55.29);
    PhoneShop phone6 = new PhoneShop("sanxing", 60.03);
    PhoneShop phone7 = new PhoneShop("huawei", 93.09);
    PhoneShop[] shops = new PhoneShop[]{phone1, phone2, phone3, phone4, phone5, phone6, phone7};
    Arrays.sort(shops, new Comparator<PhoneShop>() {    //匿名类实现重写compare
        @Override
        public int compare(PhoneShop o1, PhoneShop o2) {
            if (o1.getPrice() == o2.getPrice()) {
                return o1.getName().compareTo(o2.getName());
            } else {
                return Double.compare(o1.getPrice(), o2.getPrice());
            }
        }
    });
    System.out.println(Arrays.toString(shops));
}

test3的输出是:
//[PhoneShop{name='huawei', price=39.0}, PhoneShop{name='huawei', price=55.29}, PhoneShop{name='sanxing', price=60.03},
// PhoneShop{name='xiaomi', price=60.03}, PhoneShop{name='lianxiang', price=80.0}, PhoneShop{name='huawei', price=93.09}, 
// PhoneShop{name='microsoft', price=100.0}]

实体类PhoneShop的两个重要重写方法:
@Override
public String toString() {
    return "PhoneShop{" +
            "name='" + name + '\'' +
            ", price=" + price +
            '}';
}

@Override
public int compareTo(Object o) {
    if (o instanceof PhoneShop) {
        PhoneShop shop = (PhoneShop)o;
        if (this.name.equals(shop.getName())) {
            return Double.compare(shop.getPrice(),this.price);
        } else {
            return this.name.compareTo(shop.getName());
        }
    }
    throw new RuntimeException("类型不是购物类型");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值