java第五弹 装箱和拆箱 常用类:Object类、String类、日期类

1.Object类

  1. Object是所有java类的父类,它所属的包是java.lang.Object。
  2. 如果在类的声明的时候,没有显示的extends去继承谁,默认继承Object。
  3. Object类的作用就是提供一些公用的属性和方法。
    常用的方法:
    (1)equals(Object obj):比较两个对象的地址值是否相等。
    (2)getClass():返回Object运行时类。
    (3)hashCode():返回该对象的hash值。
    (4)toString():打印的时对象在包名和堆里的地址值。
    下面会在代码中举例equals和toString,其余的方法以后再讲。
  4. Object只有一个无参的构造方法。

有一个很重要的面试题 :==和equals的区别。

equals()

我们先来说一下"==",它是一个比较运算符。

(1)可以使用在基本数据类型和引用数据类型。

(2)如果比较基本数据类型的话,比较的是两个变量的值是否相等。

(3)如果比较引用数据类型的话,比较的是两个对象的地址值是否相等,即两个对象是否指向同一个对象实例。

Person类👇

package com.hpe.java;

public class Person {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

Test👇

int a = 10;
int b = 20;
double d = 10.0;
System.out.println(a == b);//false
System.out.println(a == d);//true

Person p = new Person();
Person p1 = new Person();
Person p2 = p;
System.out.println(p == p1);//false
System.out.println(p == p2);//true

再来说一下equals()。

(1)equals()是一个方法

(2)它只能对引用数据类型进行比较。

Person p3 = new Person("张三", 18);
Person p4 = new Person("张三", 18);
System.out.println(p3 == p4);//false
System.out.println(p3.equals(p4));//false

(3)我们来分析一下Object中equals的源码👇。

public boolean equals(Object obj) {
	return (this == obj);
}

Object的equals方法里使用的其实也是"==",所以它比较的也是两个对象的地址值是否相等,即两个对象是否指向同一个对象实例。

(4)String\Date\File\包装类都重写了equals方法,重写以后不再比较地址值,而是比较两个对象的"实体内容"是否相等。

String str = new String("张三");
String str1 = new String("张三");
System.out.println(str.equals(str1));//true

我们来分析一下String类中重写的equals方法的源码👇。

public boolean equals(Object anObject) {
    //==比较的是地址值,如果地址值相等,那实体内容肯定相等。
	if (this == anObject) {
		return true;
	}
    //如果anObject是String的实例
	if (anObject instanceof String) {
        //把anObject转成String类
		String anotherString = (String)anObject;
        //获取当前对象字符串长度,可以看成this.length
		int n = value.length;
        //如果长度相等
		if (n == anotherString.value.length) {
            //把this放到数组里
			char v1[] = value;
            //把anObject放到数组里
			char v2[] = anotherString.value;
			int i = 0;
            //依次比较各个字符
			while (n-- != 0) {
				if (v1[i] != v2[i])
                    //如果有不相等的,直接返回false
					return false;
					i++;
			}
			return true;
		}
	}
	return false;
}

(5)通常情况下,我们自己定义的类是没有重写equals方法的,如果你比较两个对象的"实体内容"是否相等,那么就需要重写equals方法。

一般情况下可以在类里自动生成,我们在Person类里模拟重写一个,也可以达到相同的作用👇。

重写之后比较的是每一个属性值是否相等。

@Override
public boolean equals(Object obj) {
	//如果obj为空,返回false
	if (obj == null) {
		return false;
	}
    //如果地址值相等,直接返回true
	if (this == obj) {
		return true;
	}
	//如果obj是Person的实例
	if (obj instanceof Person) {
        //obj转成Person类
		Person person = (Person) obj;
        //比较每一个属性值
		if(this.age == person.age && this.name.equals(person.name)){
			return true;
		}else{
			return false;
		}
	}else{
		return false;
	}
}

再来测试一下👇。

Person p3 = new Person("张三", 18);
Person p4 = new Person("张三", 18);
System.out.println(p3.equals(p4));//重写之后打印true,因为两个对象的属性值相等

我们再来看一下自动生成的equals方法👇。

@Override
public boolean equals(Object o) {
	if (this == o) return true;
    //判断o是否是Person对象
	if (o == null || getClass() != o.getClass()) return false;
	Person person = (Person) o;
	// Objects.equals比较的是两个值是否相等,对两个对象的比较加了一个判断,防止空指针异常
	return age == person.age && Objects.equals(name, person.name);
}

比较字符串使用了Objects的equals方法,我们来看一下它的源码👇。

//对两个对象的比较加了一层判断,防止空指针异常
public static boolean equals(Object a, Object b) { 
    //如果a的地址值等于b的地址值,那么值肯定相等。
    //如果a的地址值不等于b的地址值,那么就判断后面。
    //如果a不为空并且a的值等于b的值,那么返回true
	return (a == b) || (a != null && a.equals(b));
}

toString()

(1)当我们创建了一个对象,直接输出一个对象的引用,实际上就是调用了对象的toString()。

Person p5 = new Person("李四", 20);
System.out.println(p5);//com.hpe.java.Person@677327b6
System.out.println(p5.toString());//com.hpe.java.Person@677327b6

(2)我们来分析一下Object中toStrong()的源码👇。

public String toString() {
	return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

(3)String\Date\File\包装类都重写了toString方法,重写后返回的是当前对象的实体内容。

String str2 = new String("张三");
System.out.println(str2);//张三
System.out.println(str2.toString());//张三

(4)如果自己定义的类需要返回实体内容,那么就需要重写toString方法(可以自动生成)。

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

测试一下👇

Person p5 = new Person("李四", 20);
System.out.println(p5);//Person{name='李四', age=20}
System.out.println(p5.toString());//Person{name='李四', age=20}

2.String类

  1. String类被final修饰,所以不能被继承。
    在这里插入图片描述

  2. String字符串都是常量。

  3. 字符串代表不可变的常量。

    1. 当对字符串重新赋值时,需要重新指定一块新的区域进行赋值,不能直接在原有的值的基础上进行赋值。
    2. 当现有的字符串进行连接操作的时候,需要重新指定一块新的区域进行赋值。
  4. 创建字符串的两种方式
    第一种方式:通过字面量的方式String s =“aaa”;
    第二种方式:通过new的方式创建 String s = new String("aaa);

String的确是引用类型,但是它很特殊, JDK1.7 及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。 JDK1.8开始,取消了Java方法区,取而代之的是位于直接内存的元空间(metaSpace)。 但无论存放在哪里,它存储的基本原理还是不变的。

我们下面通过几段代码来解释。

先来看第一段代码👇。

String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2);//true
s2 = "adc";
System.out.println(s1 == s2);//false

在这里插入图片描述

  1. 当创建s1时,先在字符串常量池检查有没有"abc"这个字符串,发现没有,所以在字符串常量池创建一个。并把地址直接赋值给s1。
  2. 当创建s2时,在常量池里找到了"abc"这个字符串,直接把地址值赋值给s2。
  3. 当重新给s2赋值时,会在常量池新建一个字符串"adc",把新地址重新赋值给s2。

第二段代码👇。

String s3 = "abc";
System.out.println(s1 == s3);//true
s3 += "ddd";
System.out.println(s1 == s3);//false
  1. 创建s3时,在常量池里找到了"abc"这个字符串,直接把地址值赋值给s3。
  2. 当重新给s3赋值时,会在常量池查找"abcddd"这个字符串,没有找到,所以需要重新创建一个。

第三段代码👇。

//第一种方式:通过字面量的方式
String s1 = "javaEE";
String s2 = "javaEE";
//第二种方式:通过构造方法
String s3 = new String("javaEE");
String s4 = new String("javaEE");

System.out.println(s1 == s2);//t
System.out.println(s1.equals(s3));//t
System.out.println(s1 == s3);//f
System.out.println(s1 == s4);//f
System.out.println(s3 == s4);//f
System.out.println(s3.equals(s4));//t

在这里插入图片描述

这里有一个面试题:

String str = new String("str");在内存中创建了几个对象?
两个,一个是堆里的,另一个是字符串常量池里的。

第四段代码👇。

Person p = new Person("zhangsan", 12);
Person p1 = new Person("zhangsan", 12);

System.out.println(p.getName().equals(p1.getName()));//true
System.out.println(p.getName() == p1.getName());//true

String类重写了equals方法,重写之后比较的是内容。p和p1的name相同,指向常量池中同一个常量。

第五段代码👇。

String s1 = "Hello";
String s2 = "java";
String s3 = "Hellojava";
String s4 = "Hello" + "java";
String s5 = s1 + "java";
String s6 = "Hello" + s2;
String s7 = s1 + s2;

System.out.println(s3 == s4);//t	两个字面量连接相当于拼接
System.out.println(s3 == s5);//f	s5相当于new了
System.out.println(s3 == s6);//f
System.out.println(s3 == s7);//f
System.out.println(s5 == s6);//f
System.out.println(s5 == s7);//f
System.out.println(s6 == s7);//f    




结论:
1.常量与常量拼接,结果在常量池。
2.如果其中一个是变量,结果就在堆里,相当于new。

String简单常用方法。

String str = "asdfghjklpoiuytrewqzxcvbnms";

//1.length():返回字符串长度
System.out.println(str.length());

//2.charAt(int index):指定下标,返回该下标字符,字符串下标从0开始
System.out.println(str.charAt(1));

//3.equals(Object object):比较两个字符串的实体内容是否相等
//String类重写了equals方法,重写之后比较的是内容

//4.int indexOf(String s):从下标0开始,字符首次出现的位置,找不到返回-1
System.out.println(str.indexOf("s"));

//5.int indexOf(String s, int startpoint):从某个下标开始,字符首次出现的位置
System.out.println(str.indexOf("s",2));

//6.int lastIndexOf(String s):返回最后一次出现的位置
System.out.println(str.lastIndexOf("s"));

//7.int lastIndexOf(String s, int startpoint):返回最后一次出现的位置
System.out.println(str.lastIndexOf("s",2));

//8.boolean startWith(String s):判断字符串是否以s开头
System.out.println(str.startsWith("a"));

//9.boolean endsWith(String s):判断字符串是否以s结尾
System.out.println(str.endsWith("s"));

//10.String toUpperCase():转成大写
System.out.println(str.toUpperCase(Locale.ROOT));

//11.String toLowerCase():转成小写
System.out.println(str.toLowerCase(Locale.ROOT));

//12.boolean isEmpty()判断是否为空字符串
String str1 = "";
System.out.println(str1.isEmpty());

//13.boolean contains(String anotherString):是否包含anotherString
String str2 = "abcdeAAAfg";
System.out.println(str2.contains("AAA"));

String复杂常用方法

String str = "abcdefghijklmnopqrstuvwxyz";

//1.String subString(int startpoint):从startpoint开始截取字符串(包含头不包含尾)
System.out.println(str.substring(3));//defghijklmnopqrstuvwxyz

//2.String subString(int startpoint,int endspoint):
// 从startpoint开始截取字符串,到 endspoint结束(包含头不包含尾)
System.out.println(str.substring(3,5));//de

//3.String replace(char oldChar,char newChar):替换字符串
String s = str.replace("abc","zzz");
System.out.println(s);

//4.String trim():去掉字符串左右的空格
String str1 = "   aaa  bbb   ";
System.out.println(str1);
System.out.println(str1.trim());//aaa  bbb

//5.String concat(String str):拼接字符串
System.out.println(str + str1);
System.out.println(str.concat(str1));

//6.String[] split(String str):根据字符对当前字符串进行拆分,返回一个string数组
String str2 = "aa-bb-ccc-ddd";
String[] strs = str2.split("-");
for (int i = 0; i < strs.length; i++) {
	System.out.println(strs[i]);
}

StringBuffer,StringBuilder,String的区别

String:不可变字符序列,如果要修改字符串的值,不是在原有的字符串值的基础上去改,而是重新分配一块内存区域。

StringBuffer:可变字符序列,如果要修改字符串的值,是在原有的字符串值的基础上去改,线程安全,效率低。

StringBuilder:可变字符序列,如果要修改字符串的值,是在原有的字符串值的基础上去改,线程不安全,效率高。

三者效率从高到低:StringBuilder > StringBuffer > String

String效率肯定是最低的,因为不是在原有的字符串值的基础上去改,而是重新分配一块内存区域。

StringBuffer:可变字符序列、线程安全、效率低
StringBuilder:可变字符序列、线程不安全、效率高

StringBuffer比较常用,下面通过StringBuffer说明一下常用方法。

//StringBuffer三种创建方式
StringBuffer sb = new StringBuffer("aaa");
StringBuffer sb1 = new StringBuffer(12);
StringBuffer sb2 = new StringBuffer();
System.out.println(sb.toString());
//1.append(str):追加字符串str
sb.append("bbb");
System.out.println(sb);//aaabbb
sb.append("ccc").append("ddd");//aaabbbcccddd

//2.insert(index,str):在指定位置添加str
sb.insert(1, "zhangsan");
System.out.println(sb);//azhangsanaabbbcccddd

//3.delete(start,ends):删除字符串(包含头不包含尾)
sb.delete(1, 3);
System.out.println(sb);//aangsanaabbbcccddd

//4.deleteCharAt(int index):删除指定位置字符
//charAt(index):根据索引index查询对应字符串
//indexOf(string):查找第一次出现string的索引
//lastIndexOf():查找最后一次出现string的索引

//5.setCharAt(index,char):给指定位置的字符重新赋值
sb.setCharAt(1, 'e');
System.out.println(sb);//aengsanaabbbcccddd

3.包装类

基本数据类型 封装类
boolean Boolean
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double

  1. java提供了8种基本数据类型,每个基本数据类型对应一个包装类,使基本数据类型的变量就可以有类的特征。
  2. 作用:就是做基本数据类型、包装类、String进行类型转换。
  3. 装箱和拆箱(自动) 面试
    • 装箱:基本数据类型转成包装类。
    • 拆箱:包装类转成基本数据类型。

基本数据类型 <–>包装类

基本数据类型转成包装类这个过程叫做装箱,反过来叫拆箱。

int num1 = 10;
//因为num1是基本数据类型,不能用类的方法
//System.out.println(num1.toString());//报错
//数字转成Integer包装类
Integer in1 = new Integer(num1);
System.out.println(in1.toString());//相当于System.out.println(in1.toString());

//字符串转成Integer包装类,前提字符串必须是数字
Integer in2 = new Integer("111"
System.out.println(in2);
                          
                          
boolean a = true;
//布尔基本数据类型成包装类
//特殊:只有值为true或者"true"时,包装类才为ture,其余为false
Boolean b = new Boolean(a);
System.out.println(b);
Boolean b_ = new Boolean("true");
System.out.println(b_);//true

Boolean b1 = new Boolean("aaa");
System.out.println(b1);//false
                          
//手动拆箱:包装类转成基本数据类型  通过调用包装类xxxValue()方法
Integer i2 = new Integer(12);
int num2 = i2.intValue();

jdk5.0新特性:自动装箱和自动拆箱

int num1 = 10;
//基本数据类型转成包装类 --- 自动装箱
Integer i1 = num1;

//包装类转成基本数据类型 --- 自动拆箱
Integer i2 = 30;
int num2 = 30;

基本数据类型、包装类 -->String类型(开发常用)

//把整数转成String类型
int num = 10;
//方式1:加空字符串
String str = num + "";
//方式2:转成谁就去谁里面找方法,转成String就去String里面找方法
//调用String的valueOf(xxxx)方法
int num1 = 20;
String str1 = String.valueOf(num1);
System.out.println(str1);

String类型–>包装类、基本数据类型

//调用包装类parseXxx(String s)方法。
String str = "123";//字符串必须是数字
//把String转成Integer,然后通过自动拆箱转成int
//转成谁就去谁里面找方法,转成String就去String里面找方法
//先把String转成Integer,然后Integer自动拆箱转成int
int num = Integer.parseInt(str);
System.out.println(num);

double d = Double.parseDouble(str);
System.out.println(d);

4.日期类

4.1.Date类

所属包:java.util.Date;

java.sql.Date;对应的是数据库的日期类型,它是java.util.Date;的子类。

//获取当前系统时间
Date date = new Date();
System.out.println(date);//Tue Feb 23 17:19:00 CST 2021

//SimpleDateFormat可用来实现日期格式化
//format:根据定义的时间格式,把日期对象转成一个字符串
SimpleDateFormat sdf = new SimpleDateFormat();//默认类型21-2-23 下午5:21
String date1 = sdf.format(date);
System.out.println(date1);//默认类型21-2-23 下午5:21


//可以自定义时间格式
//yyyy-MM-dd HH:mm:ss  年-月-日 时:分:秒
//月份和分钟区分,月份要写成MM,分钟写成mm
//小时写成HH时表示24小时制,写成hh时表示12小时制
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date2 = sdf1.format(date);
System.out.println(date2);//2021-02-23 17:25:19


//把日期字符串转成一个date
//把时间类型的字符串转成date对象
try {
	//因为不知道你输入的字符串是否是时间格式的,所以要加异常处理
	Date date4 = sdf1.parse("2021-02-05 12:07:03");
	System.out.println(date4);//Fri Feb 05 12:07:03 CST 2021
} catch (ParseException e) {
	e.printStackTrace();
}

4.2.Calendar类

//实例化
//使用Calendar.getInstance()方法
//调用它的子类GregorianCalendar的构造器。

Calendar calendar = Calendar.getInstance();//创建了一个日历对象
//get()方法
//获取年
int year = calendar.get(Calendar.YEAR);

//获取月(0-11)
int month = calendar.get(Calendar.MONTH) + 1;

//获取日
int day = calendar.get(Calendar.DAY_OF_MONTH);//获取这个月的第几天(几号)
//int day1 = calendar.get(Calendar.DAY_OF_WEEK);

//获取时
int hour = calendar.get(Calendar.HOUR_OF_DAY);

//获取分
int minute = calendar.get(Calendar.MINUTE);

//获取秒
int second = calendar.get(Calendar.SECOND);

//获取星期
System.out.println(year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);
//2021-2-23 17:35:13

//set():设置
//获取本月天数,把本月的天数改为8
calendar.set(Calendar.DAY_OF_MONTH, 8);
//获取本月天数
int day1 = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(day1);//8

//add():在原有天数的基础上增加或减少
calendar.add(Calendar.DAY_OF_MONTH, -2);
day1 = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(day1);//6

4.3.LocalDate类

此类也是开发最经常用的。

jdk8.0新增的时间类 用的最多的:LocalDate、LocalTime、LocalDateTime。

//now():获取当前日期,时间,日期+时间
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();

System.out.println(localDate);//2021-02-23
System.out.println(localTime);//17:41:38.841
System.out.println(localDateTime);//2021-02-23T17:41:38.841


//getXxx():获取相关属性
System.out.println(localDateTime.getDayOfMonth());//获取当月的第几天	23
System.out.println(localDateTime.getDayOfWeek());//获取周几		TUESDAY
System.out.println(localDateTime.getMonth());//月份	FEBRUARY
System.out.println(localDateTime.getMinute());//当前小时的第几分钟	42


//DateTimeFormatter日期格式化,相当于SimpleDateFormat
//DateTimeFormatter适用于LocalDate、LocalTime
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
//格式化
//日期类转化成String
String str = dateTimeFormatter.format(localDateTime);
System.out.println(str);//2021-02-23 05:42:29

//把一个时间类型的字符串转成时间格式
TemporalAccessor temporalAccessor = dateTimeFormatter.parse("2021-02-05 12:53:29");
System.out.println(temporalAccessor);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值