1.Object类
- Object是所有java类的父类,它所属的包是java.lang.Object。
- 如果在类的声明的时候,没有显示的extends去继承谁,默认继承Object。
- Object类的作用就是提供一些公用的属性和方法。
常用的方法:
(1)equals(Object obj):比较两个对象的地址值是否相等。
(2)getClass():返回Object运行时类。
(3)hashCode():返回该对象的hash值。
(4)toString():打印的时对象在包名和堆里的地址值。
下面会在代码中举例equals和toString,其余的方法以后再讲。 - 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类
-
String类被final修饰,所以不能被继承。
-
String字符串都是常量。
-
字符串代表不可变的常量。
- 当对字符串重新赋值时,需要重新指定一块新的区域进行赋值,不能直接在原有的值的基础上进行赋值。
- 当现有的字符串进行连接操作的时候,需要重新指定一块新的区域进行赋值。
-
创建字符串的两种方式
第一种方式:通过字面量的方式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
- 当创建s1时,先在字符串常量池检查有没有"abc"这个字符串,发现没有,所以在字符串常量池创建一个。并把地址直接赋值给s1。
- 当创建s2时,在常量池里找到了"abc"这个字符串,直接把地址值赋值给s2。
- 当重新给s2赋值时,会在常量池新建一个字符串"adc",把新地址重新赋值给s2。
第二段代码👇。
String s3 = "abc";
System.out.println(s1 == s3);//true
s3 += "ddd";
System.out.println(s1 == s3);//false
- 创建s3时,在常量池里找到了"abc"这个字符串,直接把地址值赋值给s3。
- 当重新给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
- java提供了8种基本数据类型,每个基本数据类型对应一个包装类,使基本数据类型的变量就可以有类的特征。
- 作用:就是做基本数据类型、包装类、String进行类型转换。
- 装箱和拆箱(自动) 面试
- 装箱:基本数据类型转成包装类。
- 拆箱:包装类转成基本数据类型。
基本数据类型 <–>包装类
基本数据类型转成包装类这个过程叫做装箱,反过来叫拆箱。
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);