憩四而冠然
Object
- 被称为超类、基类,是所有类的直接或者间接父类,位于继承树的最顶层。
- 任何类,如果没有写extends继承某类,都默认直接及成果Object类,否则为间接继承/可存储任何对象
通过JDK寻找Object类查看具体方法
方法摘要
- clone():创建并返回此对象的一个副本
- equals(Object obj):指示其他某个对象是否与此对象相等
- gerClass():返回Object运行时类(和反射有关系)
- hashCode():返回对象的哈希码值(根据对象的内存地址计算得出哈希值)
- toString():返回该对象的字符串表示
Object类中所定义的方法,是所有对象都具备的方法。(继承)
因为所有类都继承了Object类,所以可以用其存储任何对象。
- 作为参数,可以接受任何对象
- 作为返回值,可以返回任何对象
getClass()
public final Class<?> getClass(){}
返回引用中存储的实际对象类型。
应用:用于判断两个引用中实际存储对象的类型是否一致。
结果:
s1和s2属于同一个类型
hashCode()
public int hashCode(){}
返回对象的哈希码值
哈希值是指根据堆中对象的地址,或者字符串或者数字使用哈希算法计算出来的int类型的数值。
相同对象返回相同的哈希码。
public class Test {
public static void main(String[] args) {
Student s1 = new Student("aaa",20);
Student s2 = new Student("bbb",22);
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
Student s3 = s1; //将s1的地址赋予给了s3,所以两者hashCode相同
System.out.println(s3.hashCode());
}
}
结果:
460141958
1163157884
460141958
toString()
public String toString(){}
返回对象的字符串形式。
可以根据程序需求覆盖该方法/重写(当从父类继承过来的方法满足不了需求,就可以对该方法进行重写)。
如下图所示,结合toString源码:(使用Structure能快速找到Object里面的方法)
但是这个结果对我没有意义,我想要得到s1/s2的name和age,就对Student中的toString方法进行重写(注意和Object源码中toString方法的修饰符、返回值、函数名一样)。如下图所示:
当然也可以Alt+Ins,选择toString(),就会自动生成重写的方法,如下图所示
equal()
public boolean equals(Object obj){}
默认比较obj这个对象和this,这两对象的堆中地址是否相同。
public class Test {
public static void main(String[] args) {
Student s1 = new Student("aaa",20);
Student s2 = new Student("bbb",22);
System.out.println(s1.equals(s2));
Student s4 = new Student("小明",17);
Student s5 = new Student("小明",17);
System.out.println(s4.equals(s5));
}
}
结果:
false
false
同样,也可以进行覆盖。
equals()方法覆盖步骤
- 比较两个引用是否指向同一个对象
- 判断obj是否为null
- 判断两个引用指向的实际对象类型是否一致(gerClass(); instanceof)
- 强制类型转换
- 依次比较各个属性值是否相同
根据上述步骤,在Student类中对equals()方法进行重写:
@Override
public boolean equals(Object obj) {
//1.判断两个对象是否是同一个引用
if(this == obj){
return true;
}
//2.判断obj是否为空
if(obj == null){
return false;
}
//3.判断是否是同一个类型
//if(this.getClass() == obj.getClass())
//instanceof可以判断对象是否是某种类型
if(obj instanceof Student){
//4.强制类型转换
Student s = (Student) obj;
//5.比较属性
if(this.name.equals(s.getName()) && this.age==s.getAge()){
return true;
}
}
return false;
}
用改写的方法重新运行之后,结果中的第二个false就是true。
finalize()
当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列。
垃圾对象:没有有效引用指向此对象,为垃圾对象。
垃圾回收:由GC销毁垃圾对象,释放数据存储空间。
自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
手动回收机制:使用System.gc();通知JVM执行垃圾回收。
重写finalize();方法时,通过输入"finalize"+Enter就可以快速生成重写方法,如下图所示:
然后将中间部分的代码删掉,进行改写,如下所示:
@Override
protected void finalize() throws Throwable {
System.out.println(this.name+"对象被回收了");
}
测试:
public class Test2 {
public static void main(String[] args) {
Student s1 = new Student("aaa",20);
Student s2 = new Student("bbb",20);
Student s3 = new Student("ccc",20);
Student s4 = new Student("ddd",20);
Student s5 = new Student("eee",20);
//回收垃圾
System.gc();
System.out.println("回收垃圾");
}
}
结果:
回收垃圾
没有出现重写的finalize()方法的输出,所以s1-s5不是垃圾。
然后将上面代码进行改写:
public class Test2 {
public static void main(String[] args) {
new Student("aaa",20);
new Student("bbb",20);
new Student("ccc",20);
new Student("ddd",20);
new Student("eee",20);
//回收垃圾
System.gc();
System.out.println("回收垃圾");
}
}
结果:
回收垃圾
bbb对象被回收了
eee对象被回收了
ddd对象被回收了
ccc对象被回收了
aaa对象被回收了
就执行了finalize()方法。
包装类
一般来说,八种基本数据类型只能使用运算符进行操作,为了让基本数据类型拥有更强大的功能,就为其设计了引用类型。这些引用类型就可以称为基本数据类型对应的包装类。
所有的数据都可以使用Object类来接收。
栈中存放的是引用的地址,其指向的对象存放在堆中。
包装类的默认值是null。
举例:
类型转换与装箱、拆箱
装箱:把栈中基本类型转换成堆中的引用类型/拆箱相反
JDK1.5之前装箱过程如下:
除了上面的Interger,还有一种方法可以进行装箱:
Integer integer2 = Integer.valueOf(num1);
JDK1.5之前拆箱过程如下:
JDK1.5之后,提供自动装箱和拆箱:
//自动装箱
int age = 30;
Integer integer4 = age;
//自动拆箱
int age2 = integer4;
其实背后是计算机主动帮我们填充代码,如下图所示:
基本类型和字符串转换
8种包装类提供不同类型的转换方式:
- Number父类中提供的6个共性方法。
- parseXXX()静态方法
- valueOf()静态方法
注意:需要保证类型兼容,否则抛出NumberFormatException异常
将基本类型转换成字符串:
public class ClassTransform {
public static void main(String[] args) {
//基本类型转换成字符串
int n1 = 100;
//①:使用+号
String s1 = n1+"";
//②使用Integer中的toString()方法
String s2 = Integer.toString(n1);
System.out.println(s1);
System.out.println(s2);
}
}
结果:
100
100
拓展:toString还有一种重载方法
其中radix是几进制的意思
public class ClassTransform {
public static void main(String[] args) {
//基本类型转换成字符串
int n1 = 255;
//①:使用+号
String s1 = n1+"";
//②使用Integer中的toString()方法
String s2 = Integer.toString(n1,16);//以16进制返回255
System.out.println(s1);
System.out.println(s2);
}
}
结果:
255
ff
补充:
另外注意:
public class ClassTransform {
public static void main(String[] args) {
//boolean 字符串形式转换成基本类型(boolean)时,"true"-->true;非"true"-->false
String str2 = "true";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);
String str3 = "treu";
boolean b2 = Boolean.parseBoolean(str3);
System.out.println(b2);
}
}
结果:
true
false
Integer缓冲区
public class ClassTransform {
public static void main(String[] args) {
//面试题
Integer integer1 = new Integer(100); //Integer1和Integer2都是引用类型,存放于堆中
Integer integer2 = new Integer(100);
System.out.println(integer1 == integer2); //比较的是栈中两个地址是否一样,所以不一样
Integer integer3 = 100; //结合前面的笔记,这里是JDK1.5之后电脑帮助填充代码的自动装箱
Integer integer4 = 100;
System.out.println(integer3 == integer4);
Integer integer5 = 200; //同为自动装箱,结果不同 结合前面的笔记,自动装箱实际上调用的是Integer.valueOf();
Integer integer6 = 200;
System.out.println(integer5 == integer6);
}
}
结果:
false
true
false
为何结果不同:
打开Integer.valueOf();方法的源
Ctrl+左键点击low和high
意思就是说,创建了一个cache[]数组,当i值位于-128~127之间,就输出数组值。
Integer3和Integer4:
100属于数组区间,所以如下图所示
Integer5和Integer6:
因为200不在数组区间内,依据源码,会在堆中开辟/new一块新的区域,所以值不同。
总结
- Java预先创建了256个常用的整数包装类型对象(刚刚的数组-128~127)
- 在实际应用当中,对已创建的对象进行复用。
String类
String概述
-
字符串是常量,创建之后不可以进行改变(但是可以改值)。
-
字符串字面值存储在字符串池中,当要用字符串时,就会去串池寻找,方便共享
-
String s = "hello";//产生一个对象,在字符串池中存储
public class String {
public static void main(String[] args) {
java.lang.String name = "hello"; //"hello"存储在字符串池当中
name = "zhangsan";//将"zhangsan"赋值给name,给字符串赋值时,没有修改数据,而是重新开辟了一块空间,原来的"hello"对象变成了垃圾对象,触发垃圾回收器就会把其进行回收。
java.lang.String name2 = "zhangsan";
}
}
-
String s = new String("hello");//产生两个对象,堆、池中各存储一个,但是栈中存储的是堆中的对象的地址 可能会浪费空间
public class demo {
//面试题
public static void main(String[] args) {
String str = new String("java");
String str2 = new String("java");
System.out.println(str == str2);
System.out.println(str.equals(str2));//equals()比较的是数值
}
}
结果:
false
true
原理如下图所示:
String常用方法
-
public int length(); 返回字符串长度
-
public char charAt(int index); 根据下标获取字符
-
public boolean contains(String str); 判断当前字符串是否包含str
应用举例:
public class demo {
public static void main(String[] args) {
String content = "java 是世界上最好的编程语言";
System.out.println(content.length()); //空格也算一个字符
System.out.println(content.charAt(0));
System.out.println(content.charAt(content.length()-1));
System.out.println(content.contains("java"));
System.out.println(content.contains("php"));
}
}
结果:
16
j
言
true
false
-
public char[] toCharArray(); 将字符串转换成数组
-
public int indexOf(String str); 查找str在字符串中首次出现的下标索引,不存在就返回-1。
-
public int lastIndexOf(String str); 查找str在字符串中最后一次出现的下标索引
应用举例:
import java.util.Arrays;
public class demo {
public static void main(String[] args) {
String content = "java 是世界上最好的编程语言,java真厉害";
System.out.println(Arrays.toString(content.toCharArray()));//为了防止content.toCharArray();打印出数组的地址,就用Arrays.toString将数组变成字符串。
System.out.println(content.indexOf("java"));
System.out.println(content.indexOf("java真香"));
System.out.println(content.indexOf("java",6));
System.out.println(content.lastIndexOf("java"));
}
}
结果:
[j, a, v, a, , 是, 世, 界, 上, 最, 好, 的, 编, 程, 语, 言, ,, j, a, v, a, 真, 厉, 害]
0
-1
17
17
-
public String trim(); 去掉字符串前后的空格
-
public String toUpperCase(); 将小写转成大写
-
public boolean endWith(String str); 判断字符串是否以str结尾
应用举例:
import java.util.Arrays;
import java.util.Locale;
public class demo {
public static void main(String[] args) {
String content = " java 是世界上最好的编程语言,java真厉害 ";
System.out.println(content.trim());
System.out.println(content.toUpperCase()); //结果仍有空格,因为String的不可变性
System.out.println(content.toLowerCase());
System.out.println(content.endsWith("真厉害"));
System.out.println(content.startsWith(" "));
}
}
结果:
java 是世界上最好的编程语言,java真厉害
JAVA 是世界上最好的编程语言,JAVA真厉害
java 是世界上最好的编程语言,java真厉害
false
true
-
public String replace(char oldChar,char newChar); 将就字符串替换成新字符串
-
public String[] split(String str); 将String[]用str拆分
应用举例:
import java.util.Arrays;
import java.util.Locale;
public class demo {
public static void main(String[] args) {
String content = " java,是世界上最好的 ,编程语言,java真厉害 ";
System.out.println(content.replace(" ","+"));
String say = "java is,the best programming language";
System.out.println(say.split(","));//split()的返回值是一个String[]/字符串数组
String[] say2 = say.split(" ");
System.out.println(say2); //数组还是不能直接sout
System.out.println(say2.length); //输出结果是newcontent被切成的块数
for (String s : say2) { //用增强for循环打印数组元素
System.out.println(s);
}
System.out.println();
String[] say3 = say.split("[ ,]"); //[+空格+,+] 可以选择空格或者逗号进行分割
System.out.println(say3.length);
for (String s : say3) {
System.out.println(s);
}
}
}
结果:
++java,是世界上最好的+,编程语言,java真厉害+++
[Ljava.lang.String;@1b6d3586
[Ljava.lang.String;@4554617c
5
java
is,the
best
programming
language
6
java
is
the
best
programming
language
补充:假如字符串中连续出现多个相同字符/多个空格,可进行如下操作
import java.util.Arrays;
import java.util.Locale;
public class demo {
public static void main(String[] args) {
String say = "java is,,the best programming language";
String[] say2 = say.split("[ ,]+"); //+的意思是:[]中的字符可以出现1个或多个
System.out.println(say2.length); //输出结果是newcontent被切成的块数
for (String s : say2) { //用增强for循环打印数组元素
System.out.println(s);
}
}
}
结果:
6
java
is
the
best
programming
language
补充:
import java.util.Arrays;
import java.util.Locale;
public class demo {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "Hello";
System.out.println(s1.equals(s2));
System.out.println(s1.equalsIgnoreCase(s2)); //忽略字母大小写的比较
String s3 = "abc"; //a:97
String s4 = "xyz"; //x:120
System.out.println(s3.compareTo(s4));
String s5 = "abc"; //b:98
String s6 = "axy"; //x:120
System.out.println(s5.compareTo(s6)); //第一个字符相等就比较第二个
String s7 = "abc";
String s8 = "abcdef";
System.out.println(s7.compareTo(s8)); //当一个字符串是另一个字符串的开头,比较的就是长度
}
}
结果:
false
true
-23
-22
-3
String案例演示
public class StringCase {
public static void main(String[] args) {
String str = new String("this is a text");
//①将str中的单词单独获取出来
System.out.println("========①将str中的单词单独获取出来========");
String[] newstr = str.split(" ");
for (String s : newstr) {
System.out.println(s);
}
//②将str中的text替换成practice
System.out.println("========②将str中的text替换成practice========");
System.out.println(str.replace("text","practice"));
//③在text掐面插入一个easy
System.out.println("========③在text掐面插入一个easy========");
System.out.println(str.replace("text","easy text")); //思路
//④将每个单词的首字母改成大写
System.out.println("========④将每个单词的首字母改成大写========");
for (String s : newstr) {
char first = s.charAt(0); //遍历根据①获得的newstr数组,将每一项的首字母赋值给字符first
char upperfirst = Character.toUpperCase(first); //将小写字母变成大写字母,可以使用char的包装类Character,因为里面有具体的方法。然后将其赋值给upperfirst
String lastversion = upperfirst+s.substring(1);//substring(i);是将字符串从下标为i处截取出来 注意不能使用String new,因为new是一个方法,不能重名
System.out.print(lastversion+" ");
}
}
}
结果:
========①将str中的单词单独获取出来========
this
is
a
text
========②将str中的text替换成practice========
this is a practice
========③在text掐面插入一个easy========
this is a easy text
========④将每个单词的首字母改成大写========
This Is A Text
StringBuffer和StringBuilder
- StringBuffer:可变长字符串,可以理解成是String的一个增强类,相当于一个缓冲区/Buffer,开辟一块缓冲区,在里面进行操作,效率比字符串要高、比字符串更节省内存。 运行效率满,线程安全
- StringBuilder:功能和和StringBuffer相同,但是运行效率快,线程不安全
StringBuilder功能和StringBuffer功能完全一样,单线程情况下就使用StringBuilder(可以将下面的StringBuffer换成StringBuilder)
public class StringCase {
//StringBuffer/StringBuilder 相比于 String ①效率高②节省内存
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
//① append(); 追加
sb.append("java世界第一");
System.out.println(sb.toString()); //打印的时候要用toString把他从StringBuffer类型变回String类型
sb.append("java真香");
System.out.println(sb.toString());
sb.append("java不错");
System.out.println(sb.toString());
//② insert(); 指定位置添加
sb.insert(0,"我在最前面");
System.out.println(sb.toString());
//③ replace(); 指定位置替换
sb.replace(0,4,"hello"); //含头不含尾
System.out.println(sb.toString());
//④ delete(); 指定位置删除
sb.delete(0,6);
System.out.println(sb.toString());
//清空
sb.delete(0,sb.length());
System.out.println(sb.toString());
System.out.println(sb.length());
}
}
结果:
java世界第一
java世界第一java真香
java世界第一java真香java不错
我在最前面java世界第一java真香java不错
hello面java世界第一java真香java不错
java世界第一java真香java不错
0
举例验证StringBuilder比String效率快:
public class demo06 {
//验证StringBuilder效率比String
public static void main(String[] args) {
//开始时间
long start = System.currentTimeMillis();
String string ="";
for (int i = 0; i < 99999; i++) {
string+=i; //字符串的拼接
}
long end = System.currentTimeMillis();
System.out.println("String所用时间:"+(end-start));
//换成StringBuilder
StringBuilder sb = new StringBuilder();
long start2 = System.currentTimeMillis();
for (int i = 0; i < 99999; i++) {
sb.append(i);
}
long end2 = System.currentTimeMillis();
System.out.println("StringBuilder所用时间:"+(end2-start2));
}
}
结果:
String所用时间:25285
StringBuilder所用时间:2
String用时25s,明显StringBuilder快很多
BigDecimal的使用
public class TestDecimal {
public static void main(String[] args) {
double d1 = 1.0; //double和float类型的存储值是一个近似值
double d2 = 0.9;
System.out.println(d1-d2);
//面试题
double result = (1.4-0.5)/0.9;
System.out.println(result);
}
}
结果:
0.09999999999999998
0.9999999999999999
在需要精确运算时,使用BigDecimal类。
BigDecimal位于java.math包中,作用是精确计算浮点数。
创建方式:
BigDecimal bd = new BigDecimal("1.0");
方法演示:
import java.math.BigDecimal;
public class TestDecimal {
public static void main(String[] args) {
BigDecimal bd1 = new BigDecimal("1.0"); //字符串是最准确的
BigDecimal bd2 = new BigDecimal("0.9");
//减法
BigDecimal r1 = bd1.subtract(bd2); //字符串减法不能使用运算符,需要使用subtract();
System.out.println(r1);
//加法
BigDecimal r2 = bd1.add(bd2);
System.out.println(r2);
//乘法
BigDecimal r3 = bd1.multiply(bd2);
System.out.println(r3);
//除法
BigDecimal r4 = new BigDecimal("1.4").subtract(new BigDecimal("0.5")).divide(new BigDecimal("0.9"));
System.out.println(r4);
/**BigDecimal r5 = new BigDecimal("10").divide(new BigDecimal("3"));
System.out.println(r5); //除不尽,还不告诉程序保留几位小数,所以报异常*/
//改写一下
BigDecimal r6 = new BigDecimal("10").divide(new BigDecimal("3"),2,BigDecimal.ROUND_HALF_UP);//四舍五入
System.out.println(r6);
}
}
结果:
0.1
1.9
0.90
1
3.33
Date类
Date表示特定的瞬间,精确到毫秒。Date类中的大部分方法都已经被Calendar中的方法取代。
秒>毫秒>微秒>纳秒 (1000)
public class Date {
public static void main(String[] args) {
//①创建Date对象
java.util.Date date1 = new java.util.Date(); //使用Date不能输出时间,需要使用继承了java.util类的Date
System.out.println(date1);
java.util.Date date2 = new java.util.Date(date1.getTime()-60*60*24*1000); //getTime();获得的是从1970.1.1到现在为止的毫秒数
System.out.println(date2);
//after();方法
boolean b1 = date1.after(date2);
System.out.println(b1);
//before();方法
boolean b2 = date1.before(date2);
System.out.println(b2);
//compareTo(); 时间相减
int d3 = date1.compareTo(date2);
System.out.println(d3);
//equals(); 是否相等
boolean d4 = date1.equals(date2);
System.out.println(d4);
}
}
结果:
Fri Apr 29 15:31:34 CST 2022
Thu Apr 28 15:31:34 CST 2022
true
false
1
false
Calendar类
改动较大,用的时候查看API
SimpleDateFormat类
- 以与语言环境有关的方式来格式化和解析日期。
- 格式化:日期→文本
- 解析: 文本→日期
- 常用的时间模式字母:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.SimpleTimeZone;
public class Calendar {
public static void main(String[] args) throws Exception{
//1.创建SimpleDateFormat对象 y年m月
SimpleDateFormat sdf = new SimpleDateFormat("yyy/MM/dd/HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyy/MM/dd/");
//2.创建Date
Date date = new Date();
//格式化date 把日期转成字符串
String string = sdf.format(date);
String string2 = sdf2.format(date);
System.out.println(string);
System.out.println(string2);
//解析 把字符串转成日期
Date date2 = sdf.parse("1997/10/12/21:21:21"); //格式可能和上面定义的sdf格式不同,所以把异常抛出去
System.out.println(date2);
}
}
结果:
2022/04/29/20:20:59
2022/04/29/
Sun Oct 12 21:21:21 CST 1997
System类
主要用于获取系统的属性数据和其他操作,构造方法私有,所以也就不用创建对象(System.out)
举例:
arraycopy():
import java.util.Arrays;
public class SystemClass {
public static void main(String[] args) {
//arraycopy 数组复制
//System.arraycopy(src,srcPos,dest,destPos,length);
//src:源数组 srcPos:从哪个位置开始复制 dest:目标数组 destPos:目标数组的位置 length:复制的长度
int[] arr = {20,18,15,8,35,26,45,90};
int[] dest = new int[8];
int[] dest2 = new int[8];
System.arraycopy(arr,0,dest,0,arr.length);
for (int i : dest) {
System.out.print(i+"\t");
}
System.out.println();
System.arraycopy(arr,4,dest2,0,4);
for (int i : dest2) {
System.out.print(i+"\t");
}
}
}
结果:
20 18 15 8 35 26 45 90
35 26 45 90 0 0 0 0
Arrays.copyOf();也可以实现复制,查看源码,如下图所示:
也是使用的System.arraycopy,因为他比较快。
currentTimeMillis:
import java.util.Arrays;
public class SystemClass {
public static void main(String[] args) {
System.out.println(System.currentTimeMillis());
long start = System.currentTimeMillis();
for (int i = 0; i < 99999; i++) {
for (int j = 0; j < 99999; j++) {
int result = i+j;
}
}
long end = System.currentTimeMillis();
System.out.println("所用时间:"+(end-start));
}
}
结果:
1651238142692
所用时间:3
System.gc():
先创建一个测试类gc
public class gc {
private String name;
private int age;
//添加属性之后添加构造方法
public gc(String name, int age) {
this.name = name;
this.age = age;
}
//然后添加get set
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;
}
//然后添加一个toString() 也是Alt+Ins
@Override
public String toString() {
return "gc{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写finalize()方法 直接打finalize然后回车就可以出来了
@Override
protected void finalize() throws Throwable {
System.out.println("回收了:"+name+" "+age);
}
}
然后测试:
import java.util.Arrays;
public class SystemClass {
public static void main(String[] args) {
gc s1 = new gc("aaa",19);
gc s2 = new gc("bbb",19);
gc s3 = new gc("ccc",19);
System.gc(); //告诉垃圾回收器回收,但是现在s1~s2正在被使用,无法回收
new gc("aaa",19);
new gc("bbb",19);
new gc("ccc",19);
System.gc(); //现在就回收了
}
}
结果:
回收了:aaa 19
回收了:bbb 19
回收了:ccc 19
System.exit():
import java.util.Arrays;
public class SystemClass {
public static void main(String[] args) {
System.exit(0);
System.out.println("程序结束了"); //程序已经退出了虚拟机,所以无法输出。
}
}
结果: