Java基础五:常用类,枚举,注解

字符串相关类

String
  • String是一个final类,是不可变的字符序列
  • 字符串是常量,值在创建之后就不能改变
  • 在底层中,String对象的字符内容是存储在一个字符数组value[]中的
  • 内存解析:
    注释

对上图的注释:
1.方法区不会存储相同的常量值
2.对字符串字面值的任何更改,都会直接创建新的字符串值,而不是在原来的字符串上进行增删改

  • String对象的创建
//本质上是给底层的char[]赋值
String s = "hello";
String s1 = new String();
String s2 = new String(String original);
String s3 = new String(char[] a);
String s4 = new String(char[] a, int startIndex, int count);//截取一部分
  • 关于默认为空和和传入为空字符串的内存解析
    在这里插入图片描述
  • 关于字面量值直接创建和new方法创建的内存解析
    在这里插入图片描述
    在这里插入图片描述
  • 字符串对象是如何创建、存储的
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

关于字符串存储内存解析的小结:
1.常量与常量的拼接结果在常量池,常量池不会存储相同的内容
2.只要其中有一个结果是变量,结果就在堆中
3.如果拼接的结果调用intern()方法,返回值就在常量池中

  • 练习
    在这里插入图片描述

解析:首先明确,String比较特殊,是final修饰的,是不可变的。change方法中,str将引用地址赋给形参,形参也指向常量池中的"good",str = "test ok"这句,在常量池中创建了"test ok",并把形参指向"test ok",属性str的指向"good"并未改变。
char[]可变,把引用地址赋给形参,所以形参的改变直接引起实参的改变,{'t', 'e', 's', 't'}变为{'b', 'e', 's', 't'}
参考链接


String常用方法
  • int length():返回字符串长度
  • char charAt(int index):返回索引处的字符
  • boolean isEmpty():判断是否是空字符串
  • String toLowerCase():将所有字符转换为小写
  • String toUpperCase():将所有字符转换为大写
  • String trim():返回字符串的副本,忽略首尾空白(不改变原本字符串)
  • boolean equals(Object obj):比较字符串内容是否相同
  • boolean equalsIgnoreCase(String anotherString):忽略大小写比较内容是否相同
  • String concat(String str):将指定字符串连接到此字符串的结尾,相当于“+”
  • int compareTo(String anotherString):比较两个字符串的大小
  • String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串
  • String substring(int beginIndex, int endIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到endIndex(不包含)的一个子字符串
  • boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
  • boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
  • boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的字符串是否以指定的前缀开始
  • boolean contains(CharSequence s):测试字符串是否包含指定的char值序列
  • 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):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串
  • String replaceAll(String regex, String replacement):使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串
  • String replaceFirst(String regex, String replacement):使用给定的replacement替换此字符串匹配给定的正则表达式的第一个子字符串
  • boolean matches(String regex):告知此字符串是否匹配给定的正则表达式
  • ```String[] split(String regex)``:根据给定正则表达式的匹配拆分此字符串
  • String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中

  • 字符串->基本数据类型、包装类:integer.parseXxx(String s)
  • 基本数据类型->字符串:String.valueOf(xxx x)
  • 字符数组->字符串:String(char[])String(char[],int offset,int length)
  • 字符串->字符数组:string.toCharArray()string.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
  • 字节数组->字符串:String(byte[])String(byte[],int offset,int length)
  • 字符串->字节数组:string.getBytes()string.getBytes(String charsetName)

练习:

  1. 模拟一个trim方法,去除字符串两端的空格。
  2. 将一个字符串进行反转。将字符串中指定部分进行反转。比如“abcdefg”
    反转为”abfedcg”
  3. 获取一个字符串在另一个字符串中出现的次数。
    比如:获取“ ab”在 “abkkcadkabkebfkabkskab” 中出现的次数
  4. 获取两个字符串中最大相同子串。比如:
    str1 = "abcwerthelloyuiodef“;str2 = “cvhellobnm”
    提示:将短的那个串进行长度依次递减的子串与较长的串比较。
  5. 对字符串中字符进行自然顺序排序。
    提示:1)字符串变成字符数组。 2)对数组排序,选择,冒泡,Arrays.sort();。3)将排序后的数组变成字符串。

StringBuffer
  • 是可变的字符序列,没有final声明,可以对字符串内容进行增删改,不会产生新的对象
  • 大多数方法与String相同
  • 作为参数传递时,方法内部可以改变值
    在这里插入图片描述
  • StringBuffer对象必须使用构造器生成,有三个构造器
    • StringBuffer():厨师容量为16的字符串缓冲区
    • StringBuffer(int size):构造指定容量的字符串缓冲区
    • StringBuffer(String str):将内容初始化为指定字符串内容

StringBuffer的常用方法
  • append(xxx):字符串拼接,接在尾部
  • delete(int start, int end):删除指定位置的内容
  • replace(int start, int end, String str):把[start, end)位置替换为str
  • insert(int offset, xxx):在指定位置插入xxx
  • reverse():把当前字符序列逆转

以下自己看吧,不写注释了

  • int indexOf(String str)
  • String substring(int start,int end)
  • int length()
  • char charAt(int n )
  • void setCharAt(int n ,char ch)
  1. appendinsert时,如果原来value数组长度不够,可扩容
  2. StringBuffer()支持方法链操作。比如s是一个 StringBuffer()s.append(xxx)后返回修改后的s,可以继续追加各种操作方法
StringBuilder
  • StringBuilderStringBuffer非常类似,也是可变字符序列,提供的相关方法也一样。区别见下面
StringBuffer可变字符序列、效率低、线程安全
StringBuilder可变字符序列、效率高、线程不安全

StringStringBufferStringBuilder一般选StringBuilder,因为执行效率相当高

例题:

    public static void main(String[] args) {
        String str = null;
        System.out.println(str);//null
//        System.out.println(str.length());//没有长度,会报错,空指针异常

        StringBuffer sb = new StringBuffer();
        sb.append(str);
        System.out.println(sb);//null
        System.out.println(sb.length());//4

//        StringBuffer sb2 = new StringBuffer(null);//会报错,空指针异常

//        StringBuffer sb1 = new StringBuffer(str);//会报错,空指针异常
    }
//因为根据StringBuffer源码,如果str是null,就賦予str = "null" 这个字符串,而不是null了.详见下方链接和源码

StringBufferappend的源码:
在这里插入图片描述

append接收到一个null的话,就会把它转换为"null"

StringBuffer中构造器的源码:
在这里插入图片描述

传入的str是null,还要去调它的length,肯定会报空指针异常

参考链接


日期时间API

JDK 8之前的日期时间API
  • java.lang.System提供的public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差
  • java.util.Date类,表示特定的瞬间,精确到毫秒
    • 构造器:
      • Date()
      • Date(long date):long date用来指定毫秒数以设置时间
    • 常用方法:
      • getTime():返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数
      • toString(): 把此 Date 对象转换为以下形式的String: dow mon dd hh:mm:ss zzz yyyy其中: dow是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat),zzz是时间标准。具体的toString方法可以自己重写

还有一些API,比如SimpleDateFormat、Calendar等,不想记录了,因为JDK 8提供了新的更好用的方法。以后碰到再学习吧


JDK 8提供的新的日期时间API
  • 最常用的API:java.time(基础包)、java.time.format(格式化和解析时间和日期)
  • 常用类:直接说最常用类吧,LocalDateLocalTimeLocalDateTime
方法描述
now()static方法,获取当前的日期、时间、日期+时间
of(xxx…)static方法,设置指定的年、月、日、时、分、秒
get各种年月日时分秒的组合()获取相关值
with各种年月日时分秒的组合(x)设置相关值
plus各种年月日时分秒的组合(x)当前对象添加对应的属性值
minus各种年月日时分秒的组合(x)当前对象减去对应的属性值
//now():获取当前的日期、时间、日期+时间
    LocalDate localDate = LocalDate.now();
    LocalTime localTime = LocalTime.now();
    LocalDateTime localDateTime = LocalDateTime.now();

    //of():设置指定的年、月、日、时、分、秒。没有偏移量
    LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 43);

    //getXxx():获取相关的属性
    System.out.println(localDateTime.getDayOfMonth());
    System.out.println(localDateTime.getDayOfWeek());
    System.out.println(localDateTime.getMonth());
    System.out.println(localDateTime.getMonthValue());
    System.out.println(localDateTime.getMinute());

    //withXxx():设置相关的属性
    LocalDate localDate1 = localDate.withDayOfMonth(22);
    LocalDateTime localDateTime2 = localDateTime.withHour(4);

    LocalDateTime localDateTime3 = localDateTime.plusMonths(3);

    LocalDateTime localDateTime4 = localDateTime.minusDays(6);
  • Instant
方法描述
now()static方法,获取本初子午线对应的标准时间(比北京时间慢8个小时)
ofEpochMilli(long x)通过给定的毫秒数,获取Instant实例
atOffset(ZoneOffset offset)结合即时的偏移来创建一个 OffsetDateTime。{比如,instant.atOffset(ZoneOffset.ofHours(8)),设置了+8的偏移,把子午时间变成北京时间}
toEpochMilli()获取自1970年1月1日0时0分0秒(UTC)开始的毫秒数
    //now():获取本初子午线对应的标准时间
    Instant instant = Instant.now();

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

    //toEpochMilli():获取自1970年1月1日0时0分0秒(UTC)开始的毫秒数  ---> Date类的getTime()
    long milli = instant.toEpochMilli();

    //ofEpochMilli():通过给定的毫秒数,获取Instant实例  -->Date(long millis)
    Instant instant1 = Instant.ofEpochMilli(1550475314878L);

格式化与解析日期时间
//        方式一:预定义的标准格式。如: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.MEDIUM);
    //格式化
    String str3 = formatter2.format(LocalDate.now());
    System.out.println(str3);//2019-2-18


//       重点: 方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
    DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
    //格式化
    String str4 = formatter3.format(LocalDateTime.now());
    System.out.println(str4);//2019-02-18 03:52:09

    //解析
    TemporalAccessor accessor = formatter3.parse("2019-02-18 03:52:09");
    System.out.println(accessor);

其他的就不说了,碰到再学吧


Java比较器

Java实现对象的排序有两种方式:

  1. 自然排序:java.lang.Comparable
  2. 定制排序:java.util.Comparator

String、包装类等,都实现并重写了Comparable接口,可以直接调用。

自然排序
  • 实现Comparable的类必须实现compareTo(Object obj)方法,两个对象即通过compareTo(Object obj)方法的返回值来比较大小。如果当前对象this大于形参对象obj,则返回正整数,如果当前对象this小于形参对象obj,则返回负整数,如果当前对象this等于形参对象obj,则返回零
  • 实现Comparable接口的对象列表(和数组)可以通过Collections.sortArrays.sort进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器
  • 对于类C的每一个e1e2来说,当且仅当e1.compareTo(e2) == 0e1.equals(e2)具有相同的boolean值时,类C的自然排序才叫做与equals一致。建议(虽然不是必需的)最好使自然排序与equals一致。
  • 对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo(obj)方法。在compareTo(obj)方法中指明如何排序
class Goods implements Comparable {
    private String name;
    private double price;
	//按照价格,比较商品的大小 
	@Override
	public int compareTo(Object o) {
		if(o instanceof Goods) {
			Goods other = (Goods) o;
			if (this.price > other.price) {
			return 1;
			} else if (this.price < other.price) {
				return -1; 
			}
			return 0; 
			//这里代表price相等。如果需要的话,可以在此定义新的排序方法,比如按name排序,来替换return 0.
		}
		//方式二:return Double.compare(this.price, other.price);
		throw new RuntimeException("输入的数据类型不一致"); 
	}
	//构造器、getter、setter、toString()方法略 
}

public class ComparableTest{
	public static void main(String[] args) {
		Goods[] all = new Goods[4];
		all[0] = new Goods("《红楼梦》", 100); 
		all[1] = new Goods("《西游记》", 80); 
		all[2] = new Goods("《三国演义》", 140); 
		all[3] = new Goods("《水浒传》", 120);
		Arrays.sort(all);
		System.out.println(Arrays.toString(all)); 
	}
}

定制排序
  • 当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码, 或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那 么可以考虑使用Comparator的对象来排序,强行对多个对象进行整体排序的比较。
  • 重写compare(Object o1,Object o2)方法,比较o1o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2
Goods[] all = new Goods[4];
all[0] = new Goods("War and Peace", 100); 
all[1] = new Goods("Childhood", 80);
all[2] = new Goods("Scarlet and Black", 140); 
all[3] = new Goods("Notre Dame de Paris", 120);

Arrays.sort(all, new Comparator() {
	@Override
	public int compare(Object o1, Object o2) { 
		Goods g1 = (Goods) o1;
		Goods g2 = (Goods) o2;
		return g1.getName().compareTo(g2.getName()); 
	}
});

Comparable与Comparator的对比
  • Comparable接口的方式一旦确定,保证Comparable接口实现类的对象在任何位置都可以比较大小。
  • Comparator接口属于临时性的比较。

BigInteger 和 BigDecimal

  • BigInteger可以表示不可变的任意精度的整数
  • BigDecimal支持不可变的、任意精度的有符号十进制定点数
  • 常用方法
    在这里插入图片描述
    在这里插入图片描述
  • 代码示例
public void test2() {
    BigInteger bi = new BigInteger("1243324112234324324325235245346567657653");
    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, 25, BigDecimal.ROUND_HALF_UP));

}

枚举类

  • 类的对象只有有限个,确定的。当要定义一组常量时,建议使用枚举类
  • 如果枚举类中只有一个对象,则可以作为单例模式的实现方式。
  • 可以使用enum关键字定义枚举类。
  • 使用enum定义的枚举类默认继承了java.lang.Enum类,因此不能再继承其他类
  • 枚举类的构造器只能使用private权限修饰符
  • 枚举类的所有实例必须在枚举类中显式列出(, 分隔 ; 结尾)。列出的实例系统会自动添加public static final修饰
  • 必须在枚举类的第一行声明枚举类对象
public enum SeasonEnum { 
	SPRING("春天","春风又绿江南岸"), 
	SUMMER("夏天","映日荷花别样红"), 
	AUTUMN("秋天","秋水共长天一色"), 
	WINTER("冬天","窗含西岭千秋雪");
	
    private final String seasonName;
    private final String seasonDesc;
    private SeasonEnum(String seasonName, String seasonDesc) {
		this.seasonName = seasonName;
		this.seasonDesc = seasonDesc; 
	}
    public String getSeasonName() {
    	return seasonName;
	}
	public String getSeasonDesc() { 
		return seasonDesc;
	} 
}
  • 可以在switch表达式中使用Enum定义的枚举类的对象作为表达式, case子句可以直接使用枚举值的名字, 无需添加枚举类作为限定
  • Enum类中的常用方法:
    • values()方法:返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值。
    • valueOf(String str):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException
    • toString():返回当前枚举类对象常量的名称
  • 实现接口的枚举类
    • 枚举类可以实现一个或多个接口
    • 若每个枚举值在调用实现的接口方法呈现相同的行为方式,则只要统一实现该方法即可
    • 若需要每个枚举值在调用实现的接口方法呈现出不同的行为方式, 则可以让每个枚举值分别来实现该方法
interface Info{
    void show();
}

//使用enum关键字枚举类
enum Season1 implements Info{
    //1.提供当前枚举类的对象,多个对象之间用","隔开,末尾对象";"结束
    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("大约在冬季");
        }
    };

    //2.声明Season对象的属性:private final修饰
    private final String seasonName;
    private final String seasonDesc;

    //2.私有化类的构造器,并给对象属性赋值

    private Season1(String seasonName,String seasonDesc){
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }

    //4.其他诉求1:获取枚举类对象的属性
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }
//    //4.其他诉求1:提供toString()
//
//    @Override
//    public String toString() {
//        return "Season1{" +
//                "seasonName='" + seasonName + '\'' +
//                ", seasonDesc='" + seasonDesc + '\'' +
//                '}';
//    }


//    @Override
//    public void show() {
//        System.out.println("这是一个季节");
//    }
}

注解(Annotation)

  • Annotation其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理。通过使用 Annotation,
  • 程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息。
  • JDK内置的三个基本注解
    • @Override: 限定重写父类方法, 该注解只能用于方法
    • @Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
    • @SuppressWarnings: 抑制编译器警告

就不多说了,遇到再说吧

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值