【学习笔记】Java笔记4:常用类

184 阅读7分钟

1. String

1.1 相关介绍

  • 基本特性:不可变性。如果修改了String对象的内容,那么其实是重新开辟空间并赋上新值

  • 如果是通过字面量的方式赋值,那么赋值后字符串保存在方法区的常量池中。在常量池中,不会保存相同内容的字符串,所以如果两个String对象的内容相同,那么它们指向的是同一个地址

    public class Test {
        public static void main(String[] args) {
            String s1 = "abc";
            String s2 = "abc";
            System.out.println(s1 == s2); // 输出结果为true
        }
    }
    
  • 如果是通过new来创建,则是保存在堆中,但是对象中的value是指向常量池的

    public class Test {
        public static void main(String[] args) {
            String s1 = "abc";
            String s2 = "abc";
            String s3 = new String("abc");
            String s4 = new String("abc");
    
            System.out.println(s1 == s2); // true
            System.out.println(s1 == s3); // false
            System.out.println(s1 == s4); // false
            System.out.println(s3 == s4); // false
        }
    }
    

006-01.png

  • 关于字符串拼接,如果涉及到变量的拼接,则是在堆中开辟新的空间

    public class Test {
        public static void main(String[] args) {
            String s1 = "Hello";
            String s2 = "World";
            final String s3 = "World";
    
            String s4 = "HelloWorld";           // 字面量赋值,直接指向常量池
            String s5 = s1 + "World";           // 涉及到变量的拼接,会在堆中开辟新的空间
            String s6 = "Hello" + s2;           // 同上
            String s7 = s1 + s2;                // 同上
            String s8 = "Hello" + s3;           // s3是final修饰的常量,两个常量的拼接,指向常量池
            String s9 = "Hello" + "World";      // 常量与常量的拼接,指向常量池
            String s10 = (s1 + s2).intern();    // intern()返回的是在常量池中的地址
    
            System.out.println(s4 == s5);       // false
            System.out.println(s4 == s6);       // false
            System.out.println(s4 == s7);       // false
            System.out.println(s4 == s8);       // true
            System.out.println(s4 == s9);       // true
            System.out.println(s4 == s10);      // true
        }
    }
    

1.2 类型准换

  • String转换为基本类型:调用基本类型对应包装类的parseXXX()方法

  • 基本类型转换为String:调用String.valueOf()方法

  • String转换为char[]:调用String对象的toCharArray()方法

  • char[]转换为String:把char[]放进String的构造器中

  • String转换为字节数组:调用String对象的getBytes()方法

  • 字节数组转换为String:把字节数组放进String的构造器中

    public class Test {
        public static void main(String[] args) throws UnsupportedEncodingException {
            byte[] bytes = "Java学习".getBytes("gbk"); // 按gbk字符集编码,默认是utf-8
            String str = new String(bytes, "gbk");    // 按gbk字符集解码
            System.out.println(str);                  // 输出"Java学习"
        }
    }
    

1.3 String、StringBuffer、StringBuilder异同

相同点:

  • 都是用char[]存储

不同点:

  • String:不可变的字符序列
  • StringBuffer:可变的字符序列,线程安全(方法都是synchronized修饰的),效率低。如何实现可变:先创建默认长度字符数组,当追加的字符过多就会扩容,即创建一个新的字符数组大小为原来的2倍加2,再把旧数组的内容复制过去
  • StringBuilder:可变的字符序列,线程不安全,效率高
  • 三者效率:StringBuilder > StringBuffer > String

1.4 例题

  获取两个字符串的一个最大子字符串

/**
 * 获取两个字符串的一个最大子字符串
 * @param str1 字符串1
 * @param str2 字符串2
 * @return     返回两个字符串的一个最大子字符串
 */
public String findMaxSameString(String str1, String str2) {
    if (str1 == null || str2 == null || str1.equals("") || str2.equals("")) {
        return null;
    }
    String maxStr;
    String minStr;
    if (str1.length() >= str2.length()) {
        maxStr = str1;
        minStr = str2;
    } else {
        maxStr = str2;
        minStr = str1;
    }
    int length = minStr.length();
    for (int flag = length; flag > 0; flag--) {
        for (int start = 0, end = flag - 1; end < length; start++, end++) {
            String temp = minStr.substring(start, end + 1);
            if (maxStr.contains(temp)) {
                return temp;
            }
        }
    }
    return null;
}

2. 时间类相关

2.1 java.util.Date

构造器解释
Date()创建一个当前**时间戳(从1970年1月1日0时0分到现在的毫秒数)**的Date对象
Date(long date)创建一个指定时间戳的Date对象
方法解释
toString()显示对应时间
getTime()获取对应时间戳

(注:java.sql.Date对应数据库中的date类型

2.2 java.text.SimpleDateFormat

  用于对日期Date类的格式化和解析。

public class Test {
    public static void main(String[] args) {
        // 创建特定格式的SimpleDateFormat
        // 格式化:日期-->字符串
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        String result = sdf.format(date);
        System.out.println(result);

        // 解析:字符串-->日期
        String str = "2019-09-08";
        try {
            Date parse = sdf.parse(str);
            System.out.println(parse);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

  常用字母代表的意思如下图所示(JDK 1.6 API) 006-02.png

2.3 java.util.Calendar

  日历类,是一个抽象类。

public class Test {
    public static void main(String[] args) {
        // 方法1:通过其子类实例化
        Calendar calendar = new GregorianCalendar();

        // 方法2:通过静态方法实例化
        Calendar calendar2 = Calendar.getInstance();

        // get()方法
        System.out.println(calendar.get(Calendar.DAY_OF_MONTH));  // 输出8

        // set()方法
        calendar.set(Calendar.DAY_OF_MONTH, 10);
        System.out.println(calendar.get(Calendar.DAY_OF_MONTH));  // 输出10

        // add()方法
        calendar.add(Calendar.DAY_OF_MONTH, 5);
        System.out.println(calendar.get(Calendar.DAY_OF_MONTH));  // 输出15
        
        // 转换为Date对象
        Date time = calendar.getTime();
        System.out.println(time);

        // 使用Date对象为Calendar类设置时间
        Date date = new Date();
        calendar.setTime(date);
        System.out.println(calendar.get(Calendar.DAY_OF_MONTH));  // 输出8
    }
}

2.4 LocalDate、LocalTime、LocalDateTime

  Java 8 引入的关于时间的类。

public class Test {
    public static void main(String[] args) {
        // 三个类的方法都类似
        // now()方法创建,分别获取日期、时间、日期和时间
        LocalDate localDate = LocalDate.now();
        LocalTime localTime = LocalTime.now();
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDate);
        System.out.println(localTime);
        System.out.println(localDateTime);

        // of()方法创建
        LocalDateTime localDateTime2 = LocalDateTime.of(2019, 9, 8, 15, 8);
        System.out.println(localDateTime2);

        // getXXX()
        System.out.println(localDateTime.getDayOfWeek());

        // withXXX()设置相关属性,注意会返回一个新的对象,旧对象内容不变
        LocalDateTime newLocalDateTime = localDateTime.withDayOfMonth(20);
        System.out.println(newLocalDateTime);

        // plusXXX()给属性增加值
        LocalDateTime newLocalDateTime2 = localDateTime.plusDays(5);
        System.out.println(newLocalDateTime2);

        // minus()给属性减少值
        LocalDateTime newLocalDateTime3 = localDateTime.minusDays(3);
        System.out.println(newLocalDateTime3);
    }
}

2.5 java.time.Instant

public class Test {
    public static void main(String[] args) {
        // now()创建的Instant对象比东八区慢8小时
        Instant instant = Instant.now();
        System.out.println(instant);

        // 添加时间偏移量
        OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);

        // 获取时间戳
        long millis = instant.toEpochMilli();
        System.out.println(millis);

        // 根据时间戳创建Instant对象
        Instant instant2 = Instant.ofEpochMilli(millis);
        System.out.println(instant2);
    }
}

2.6 DateTimeFormatter

public class Test {
    public static void main(String[] args) {
        // 方式一:预定义的标准格式
        DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        // 格式化:日期-->字符串
        LocalDateTime localDateTime = LocalDateTime.now();
        String str = formatter.format(localDateTime);
        System.out.println(str);
        // 解析:字符串-->日期
        TemporalAccessor parse = formatter.parse(str);
        System.out.println(parse);

        // 方式二:本地化相关格式
        // FormatStyle.LONG, FormatStyle.MEDIUM, FormatStyle.SHORT 适合LocalDateTime
        DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
        String str2 = formatter2.format(localDateTime);
        System.out.println(str2);

        // FormatStyle.FULL, FormatStyle.LONG, FormatStyle.MEDIUM, FormatStyle.SHORT 适合LocalDate
        LocalDate localDate = LocalDate.now();
        DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
        String str3 = formatter3.format(localDate);
        System.out.println(str3);

        // 方法三:自定义格式,常用
        DateTimeFormatter formatter4 = DateTimeFormatter.ofPattern("yyyy-MM-dd kk:mm:ss");
        System.out.println(formatter4.format(LocalDateTime.now()));
    }
}

3. 比较器

  用于对对象进行比较。

3.1 实现Comparable

1、编写一个People类实现Comparable接口,重写compareTo(obj)方法。如果当前对象大于比较对象obj,返回正整数,等于返回0,小于则返回负整数。

public class People implements Comparable<People> {
    private int age;
    private float height;

    @Override
    public int compareTo(People o) {
        if (this.age > o.age) {
            return 1;
        } else if (this.age == o.age) {
            return 0;
        }
        return -1;
    }

    public People(int age, float height) {
        this.age = age;
        this.height = height;
    }

    @Override
    public String toString() {
        return "People{" +
                "age=" + age +
                ", height=" + height +
                '}';
    }
}

2、编写测试类,使用Arrays.sort()或Collections.sort()进行排序

public class Test {
    public static void main(String[] args) {
        People[] peoples = new People[3];
        peoples[0] = new People(18, 1.7F);
        peoples[1] = new People(20, 1.8F);
        peoples[2] = new People(14, 1.5F);
        // 数组排序
        Arrays.sort(peoples);
        System.out.println(Arrays.toString(peoples));
        // 输出[People{age=14, height=1.5}, People{age=18, height=1.7}, People{age=20, height=1.8}]

        List<People> list = new ArrayList<>();
        list.add(new People(30, 1.9F));
        list.add(new People(35, 1.6F));
        list.add(new People(25, 1.7F));
        // 集合排序
        Collections.sort(list);
        System.out.println(list);
        // 输出[People{age=25, height=1.7}, People{age=30, height=1.9}, People{age=35, height=1.6}]
    }
}

3.2 使用Comparator实现类

1、编写普通的People类

public class People {
    private int age;
    private float height;

    public int getAge() {
        return age;
    }

    public People(int age, float height) {
        this.age = age;
        this.height = height;
    }

    @Override
    public String toString() {
        return "People{" +
                "age=" + age +
                ", height=" + height +
                '}';
    }
}

2、编写测试类,使用Comparator匿名实现类来排序

public class Test {
    public static void main(String[] args) {
        People[] peoples = new People[3];
        peoples[0] = new People(18, 1.7F);
        peoples[1] = new People(20, 1.8F);
        peoples[2] = new People(14, 1.5F);
        // 数组排序
        Arrays.sort(peoples, new Comparator<People>() {
            @Override
            public int compare(People o1, People o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        System.out.println(Arrays.toString(peoples));
        // 输出[People{age=14, height=1.5}, People{age=18, height=1.7}, People{age=20, height=1.8}]

        List<People> list = new ArrayList<>();
        list.add(new People(30, 1.9F));
        list.add(new People(35, 1.6F));
        list.add(new People(25, 1.7F));
        // 集合排序
        Collections.sort(list, new Comparator<People>() {
            @Override
            public int compare(People o1, People o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        System.out.println(list);
        // 输出[People{age=25, height=1.7}, People{age=30, height=1.9}, People{age=35, height=1.6}]
    }
}

4. 枚举类

4.1 自定义枚举类

1、Java 5 之前制作枚举类的步骤如下:

public class Season {
    // 1.使用final修饰属性
    private final String seasonName;
    private final String seasonDetail;

    // 2.私有化构造器
    private Season(String seasonName, String seasonDetail) {
        this.seasonName = seasonName;
        this.seasonDetail = seasonDetail;
    }

    // 3.提供当前枚举类的多个常量对象
    public static final Season SPRING = new Season("春天", "春暖花开");
    public static final Season SUMMER = new Season("夏天", "烈日炎炎");
    public static final Season AUTUMN = new Season("秋天", "秋高气爽");
    public static final Season WINTER = new Season("冬天", "冰天雪地");

    // 4.提供获取属性方法
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDetail() {
        return seasonDetail;
    }

    @Override
    public String toString() {
        return "Season{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDetail='" + seasonDetail + '\'' +
                '}';
    }
}

2、测试效果如下:

public class Test {
    public static void main(String[] args) {
        Season spring = Season.SPRING;
        System.out.println(spring);
        // 输出Season{seasonName='春天', seasonDetail='春暖花开'}
    }
}

4.2 使用enum关键字

1、Java 5 引入enum关键字,使用该关键字定义枚举类

// 使用该关键字定义的枚举类继承于java.lang.Enum
public enum Season {
    // 提供当前枚举类的对象,放在最开头
    SPRING("春天", "春暖花开"),
    SUMMER("夏天", "烈日炎炎"),
    AUTUMN("秋天", "秋高气爽"),
    WINTER("冬天", "冰天雪地");

    private final String SeasonName;
    private final String SeasonDetail;

    Season(String seasonName, String seasonDetail) {
        SeasonName = seasonName;
        SeasonDetail = seasonDetail;
    }
}

2、测试效果以及Enum类的常用方法如下

public class Test {
    public static void main(String[] args) {
        Season spring = Season.SPRING;
        System.out.println(spring);         // 输出SPRING

        // Enum的values()方法
        Season[] values = Season.values();  // 返回该枚举类的所有对象
        for (Season s : values) {
            System.out.println(s);
        }
        // Enum的valueOf()方法
        Season winter = Season.valueOf("WINTER"); // 根据对象名获取枚举类的特定对象
        System.out.println(winter);
    }
}

3、实现某接口时的情况

  比如有如下接口时,如果枚举类实现了该接口,那么可在类中重写方法,也可在对象中重写方法

public interface Info {
    void show();
}
public enum Season implements Info {
    // 在对象中重写方法,则每个对象输出内容不同
    SPRING("春天", "春暖花开") {
        @Override
        public void show() {
            System.out.println("这是春天");
        }
    },
    SUMMER("夏天", "烈日炎炎") {
        @Override
        public void show() {
            System.out.println("这是夏天");
        }
    },
    AUTUMN("秋天", "秋高气爽") {
        @Override
        public void show() {
            System.out.println("这是秋天");
        }
    },
    WINTER("冬天", "冰天雪地") {
        @Override
        public void show() {
            System.out.println("这是冬天");
        }
    };

    private final String SeasonName;
    private final String SeasonDetail;

    Season(String seasonName, String seasonDetail) {
        SeasonName = seasonName;
        SeasonDetail = seasonDetail;
    }

//    如果在类中重写接口的方法,那么每个对象都输出相同内容
//    @Override
//    public void show() {
//        System.out.println("这是一个季节");
//    }
}
public class Test {
    public static void main(String[] args) {
        Season spring = Season.SPRING;
        spring.show(); // 这是春天

        Season winter = Season.valueOf("WINTER");
        winter.show(); // 这是冬天
    }
}