学习视频来自于:秦疆(遇见狂神说)Bilibili地址
他的自学网站:kuangstudy
生活是属于每个人自己的感受,不属于任何别人的看法
超类,基类、跟类,所有类的直接或间接父类,位于继承树的最顶层。
任何类,如果没有书写extends显示继承某个类,都默认直接继承Object,否则为间接继承。
在对象实例化的时候,最终找到的父类就是Object。
Object类提供无参构造方法 ,之所以提供这样的无参构造,是因为在子类对象实例化时都会默认调用父类中的无参构造方法,这样在定义类时即使没有明确定义父类为Object,读者也不会感觉代码的强制性要求。
Object类中所定义的方法,是所有对象都具备的方法。
Object类型可以储存任何对象
* 作为参数,可接收任何对象。
* 作为返回值,可返回任何对象。
public native int hashCode();
// s1和s2对象指向不相同,hashCode不相同
s1.hashCode();
s2.hashCode();
// s1和s3对象指向相同,此时s3的hashCode与s1相同
Student s3 = s1;
public boolean equals(Object obj) {
return (this == obj);
}
public class Person {
private String name;
private int age;
// IDEA重写的快捷键:Alt + Insert
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
// 省略构造器与Getter Setter
}
在我们直接使用输出语句输出对象名的时候,其实通过该对象调用了其toString()方法。
protected native Object clone() throws CloneNotSupportedException;
@Contract(pure = true)
public final native Class<?> getClass();
// 判断s1 和 s2是不是同一个类型
Class class1 = s1.getClass();
Class class2 = s2.getClass();
// getClass返回 class类型
如何获取类的字节码文件对象?
类名.class 说明: JVM将使用类装载器, 将类装入内存(前提是:类还没有装入内存),不做类的初始化工作.返回Class的对象
Class.forName(“类名字符串”) (注:类名字符串是包名+类名) 说明:装入类,并做类的静态初始化,返回Class的对象
实例对象.getClass() 说明:对类进行静态初始化、非静态初始化; 返回引用o运行时真正所指的对象(因为:子对象的引用可能会赋给父对象的引用变量中) 所属的类的Class的对象
public final native void notify();
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0);
}
public boolean equals(Object obj) {
return (this == obj);
}
// 判断两个对象是否相等
sout(s1.equals(s2)); // false
Student s4 = new Student("小明", 17);
Student s5 = new Student("小明", 17);
sout(s4.equals(s5)); // false 堆中地址不同
// 重写 改变其比较内容
/*
步骤 1. 比较两个应用是否指向同一个对象
2. 判断obj是否为null
3. 判断两个引用指向的实际对象类型是否一致
4. 强制类型转换
5. 依次比较各个属性值是否相同
*/
@override
public boolean equals(Object obj){
// 1.
if(this == obj){
return true;
}
// 2.
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;
}
protected void finalize() throws Throwable { }
JDK1.7
添加了一个Objects工具类,它提供了一些方法来操作对象,它由一些静态的实用方法组成,这些方法是null-save(空指针安全的)或null-tolerant(容忍空指针的),用于计算对象的hashcode、返回对象的字符串表示形式、比较两个对象。public static boolean equals(Object a, Object b)
:判断两个对象是否相等。public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
说出一些你常用的方法
常覆写Object类的3个方法:toString(),equals(Object obj),hashCode()
克隆方法或者克隆接口一些问题
克隆对象对应的类需要实现Cloneable接口,否则会报错:java.lang.CloneNotSupportedException
为什么notify(), wait()等函数定义在Object中,而不是Thread中?
Object中的wait(), notify()等函数,和synchronized一样,会对“对象的同步锁”进行操作。
wait()会使“当前线程”等待,因为线程进入等待状态,所以线程应该释放它锁持有的“同步锁”,否则其它线程获取不到该“同步锁”而无法运行!
OK,线程调用wait()之后,会释放它锁持有的“同步锁”;而且,根据前面的介绍,我们知道:等待线程可以被notify()或notifyAll()唤醒。现在,请思考一个问题:notify()是依据什么唤醒等待线程的?或者说,wait()等待线程和notify()之间是通过什么关联起来的?答案是:依据“对象的同步锁”。
负责唤醒等待线程的那个线程(我们称为“唤醒线程”),它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个),并且调用notify()或notifyAll()方法之后,才能唤醒等待线程。虽然,等待线程被唤醒;但是,它不能立刻执行,因为唤醒线程还持有“该对象的同步锁”。必须等到唤醒线程释放了“对象的同步锁”之后,等待线程才能获取到“对象的同步锁”进而继续运行。
总之,notify(), wait()依赖于“同步锁”,而“同步锁”是对象锁持有,并且每个对象有且仅有一个!这就是为什么notify(), wait()等函数定义在Object类,而不是Thread类中的原因。
Math类都是static修饰,直接使用
为什么说Random生成的随机数是伪随机数?
只要两个Random对象的种子相同,而且方法的调用顺序也相同,产生的随机数相同。
生成0~n之间的数
①(int)Math.random()*(n+1)
②Random r = new Random();
r.nextInt(m)表示生成[0,m-1]之间的随机数,也就是说random.nextInt(m+1),将生成[0,m]之间的随机整数。
r.nextInt(n+1)
生成n~m之间的随机数
①n+(int)(Math.random()*(m+1-n));
②Random r = new Random();
r.nextInt(m+1-n)+n;
// 用于做数据库的id
String uuid = UUID.randomUUID().toString();
// 效果:39eb10ce-e8be-49f5-a44b-bfd0aa8c8135
Java文件类以抽象的方式代表文件名和目录路径名。
该类主要用于文件和目录的创建、文件的查找和文件的删除等。
File对象代表磁盘中实际存在的文件和目录。
File(File parent, String child);
File(String pathname);
File(String parent, String child);
File(URI uri)
public boolean mkdir()
创建此抽象路径名指定的目录。
public boolean mkdirs()
创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。
public File[] listFiles()
返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件。
public boolean renameTo(File dest)
重新命名此抽象路径名表示的文件。
public boolean delete()
删除此抽象路径名表示的文件或目录。
Java提供了两个类型系统,基本类型与引用类型,使用基本类型在于效率,然而很多情况,会创建对象使用,因为对象可以做更多的功能。
如果想要我们的基本类型像对象一样操作,就可以使用基本类型对应的包装类,如下:
基本类型 | 对应的包装类(位于java.lang包中) |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
// 装箱, 基本类型 → 引用类型
// 基本类型
int num1 = 18;
// 使用Integer类创建对象
Integer integer1 = new Integer(num1);
Integer integer2 = Integer.valueOf(num1);
// 拆箱, 引用类型 → 基本类型
Integer integer3 = new Integer(100);
int num2 = integer3.intValue();
JDK 1.5
开始,基本类型与包装类的装箱、拆箱动作可以自动完成。例如: int age = 30;
// 自动装箱
Integer integer4 = age;
// 自动拆箱
int age2 = integer4;
// 1. 基本类型转成字符串
int n1 = 100;
// 1.1 使用+号(推荐)
String s1 = n1 + "";
// 1.2 使用Integer中的toString()方法
String s2 = Integer.toString(n1);
// 1.3 x为进制要求
String s2 = Integer.toString(n1, x);
// 2. 字符串转成基本类型
String str = "150";
// 2.1使用Integer.parseXXX();(推荐)
int n2 = Integer.parseInt(str);
// 2.2包装类型的构造器
Integer i = new Integer("2");
// 2.3返回保存指定的 String 的值的 Integer 对象
Integer integer2 = Integer.valueOf(num1);
// boolean 字符串形式转成基本类型,"true" ---> true 非“true ———> false
String str2 = "true";
boolean b1 = Boolean.parseBoolean(str2);
除了Character类之外,其他所有包装类都具有parseXxx静态方法可以将字符串参数转换为对应的基本类型:
public static byte parseByte(String s)
:将字符串参数转换为对应的byte基本类型。public static short parseShort(String s)
:将字符串参数转换为对应的short基本类型。public static int parseInt(String s)
:将字符串参数转换为对应的int基本类型。public static long parseLong(String s)
:将字符串参数转换为对应的long基本类型。public static float parseFloat(String s)
:将字符串参数转换为对应的float基本类型。public static double parseDouble(String s)
:将字符串参数转换为对应的double基本类型。public static boolean parseBoolean(String s)
:将字符串参数转换为对应的boolean基本类型。注意:需保证类型兼容,否则抛出NumberFormatException异常。
Integer integer3 = new Integer(100);// 自动装箱
// 相当于调用 Integer.valueOf(100);
Integer integer4 = new Integer(100);
sout(integer3 == integer4); // true
Integer integer5 = new Integer(200);// 自动装箱
Integer integer6 = new Integer(200);
sout(integer5 == integer6); // false
// 因为缓存区数组 [-128, 127] 在这之内地址一样
表示特定的瞬间,精确到毫秒值
将日期时间类Date转换为自定义日期时间格式(格式化)
构造方法
常用的格式规则为:
标识字母(区分大小写) | 含义 |
---|---|
y | 年 |
M | 月 |
d | 日 |
H | 时 |
m | 分 |
s | 秒 |
// 创建日期对象
Date date = new Date();
// 创建日期格式化解析对象
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 调用格式化方法
String time = format.format(date);
// 打印结果
System.out.println(time);// 结果:2022-05-10 09:46:15
解析
// 创建日期格式化解析对象
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 自定义时间
String str = "2020-05-10 09:46:15";
// 调用解析方法,返回date对象,抛出ParseException异常
Date date = format.parse(str);
// 打印结果
System.out.println(date);// 结果:Sun May 10 09:46:15 CST 2020
1.获取当前时间对应的毫秒值
2.获取自己出生日期对应的毫秒值
3.两个时间相减(当前时间– 出生日期)
public static void function() throws Exception {
System.out.println("请输入出生日期 格式 YYYY-MM-dd");
// 获取出生日期,键盘输入
String birthdayString = new Scanner(System.in).next();
// 将字符串日期,转成Date对象
// 创建SimpleDateFormat对象,写日期模式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 调用方法parse,字符串转成日期对象
Date birthdayDate = sdf.parse(birthdayString);
// 获取今天的日期对象
Date todayDate = new Date();
// 将两个日期转成毫秒值,Date类的方法getTime
long birthdaySecond = birthdayDate.getTime();
long todaySecond = todayDate.getTime();
long secone = todaySecond-birthdaySecond;
if (secone < 0){
System.out.println("还没出生呢");
} else {
System.out.println(secone/1000/60/60/24);
}
}
该类是一个抽象类,不可以实例化
它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等
日历类,用于获取或者操作日历字段(年月日)
日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。
字段值 | 含义 |
---|---|
YEAR | 年 |
MONTH | 月(从0开始,可以+1使用) |
DAY_OF_MONTH | 月中的天(几号) |
HOUR | 时(12小时制) |
HOUR_OF_DAY | 时(24小时制) |
MINUTE | 分 |
SECOND | 秒 |
DAY_OF_WEEK | 周中的天(周几,周日为1,可以-1使用) |
get/set
// 获取日历类对象
Calendar time = Calendar.getInstance();
// 获取年
int year = time.get(Calendar.YEAR);
// 获取月
int month = time.get(Calendar.MONTH);
// 获取日
int day = time.get(Calendar.DAY_OF_MONTH);
// 获取时
int hour = time.get(Calendar.HOUR_OF_DAY);
// 获取分
int minute = time.get(Calendar.MINUTE);
// 获取秒
int second = time.get(Calendar.SECOND);
// 打印结果:2022-4-10 10:3:59
System.out.println(year+"-"+month+"-"+day+"\t"+hour+":"+minute+":"+second);
// 更改时间
time.set(Calendar.YEAR,2003);
// 打印结果:2003-4-10 10:6:25
}
}
add
add方法可以对指定日历字段的值进行加减操作,如果第二个参数为正数则加上偏移量,如果为负数则减去偏移量。代码如:
import java.util.Calendar;
public class Demo08CalendarMethod {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
System.out.print(year + "年" + month + "月" + dayOfMonth + "日"); // 2018年1月17日
// 使用add方法
cal.add(Calendar.DAY_OF_MONTH, 2); // 加2天
cal.add(Calendar.YEAR, -3); // 减3年
System.out.print(year + "年" + month + "月" + dayOfMonth + "日"); // 2015年1月18日;
}
}
getTime
Calendar中的getTime方法并不是获取毫秒时刻,而是拿到对应的Date对象。
import java.util.Calendar;
import java.util.Date;
public class Demo09CalendarMethod {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
Date date = cal.getTime();
System.out.println(date); // Tue Jan 16 16:03:09 CST 2018
}
}
注意:
西方星期的开始为周日,中国为周一。
在Calendar类中,月份的表示是以0-11代表1-12月。
日期是有大小关系的,时间靠后,时间越大。
表示的是字符串,字符串是常量(值定义了之后,不可修改)
字符串可以看出是多个字符的连接
判断功能
获取功能
转换功能
其他功能
/*
* 字符串做连接操作
* 如果是两个变量进行连接,先开辟空间,再连接
* 如果是两个常量进行连接,先连接,获取连接结构值。然后在常量池里面查找有没有这个结果值,如果有,直接给地址值;没有,开辟空间
*/
public class StringTest02 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
String s3 = "helloworld";
System.out.println(s3 == s1+s2); //false
System.out.println(s3.equals(s1+s2)); //true
System.out.println(s3 == "hello"+"world"); //true
System.out.println(s3.equals("hello"+"world")); //true
}
}
// 1. length(); 返回字符串长度
// 2. charAt(int index); 返回某个位置的字符
// 3. contains(String str); 判断是否包含某个字符串
String content = "java是最好的语言, java no1";
sout(content.length()); // 10
sout(content.charAt(content.length() - 1)); // 言
sout(content.contains("java")); // true
// 4. toCharArray(); 返回字符串对应数组
// 5. indexOf(); 返回子字符串首次出现的位置
// 6. lastIndexOf(); 返回字符串最后一次出现的位置
sout(content.toCharArray());
sout(content.indexOf"java")); // 0
sout(content.indexOf("java", 4)); // 从索引4开始找 返回12
sout(content.lastIndexOf("java")); // 12
// 7. trim(); //去掉字符串前后空格
// 8. toUpperCase(); toLowerCase(); 转换大小写
// 9. endWith(str); startWith(str); 判断是否以str 结尾、开头
String ct = " hello world ";
sout(ct.trim()); // "hello world"
sout(ct.toUpperCase()); // HELLO WORLD
sout(ct.toLowerCase()); // hello world
sout(ct.endWith("world")); // true
sout(ct.startWith("hello")) // true
// 10. replace(char old, char new); 用心的字符或字符串替换旧的字符或字符串
// 11. split(); 对字符串拆分
sout(content.replace("java", "php")); // php是最好的语言, php no1
String say = "java is the best language";
String[] arr = arr.say.split(" "); // "[ ,]+" 表示空格 逗号切分 +号表示切分可以多个 比如多个空格
sout(arr.length); // 5
for(String string : arr){
sout(string);
}
// 打印出
//java
//is
//the
//best
//language
// 补充两个equals/compareTo();比较大小
String s1 = "hello";
String s2 = "HELLO";
sout(s1.equalsIgnoreCase(s2));// 忽略大小写比较true
// compareTo(); 两字符不同时比较字符字典序的ascii码
// 字符相同时比较长度 返回差值
StringBuffer:多线程数据量多使用,线程安全
StringBuider:单线程数据量较多使用,线程不安全
效率都比String高且节省内存
// StringBuffer 和 StringBuilder 用法一致
StringBuffer sb = new StringBuffer();
// 1. append(); 追加
sb.append("java no1");
// 2. insert(); 添加、插入
sb.insert(0, "在第一个位置插入");
// 3.replace(); 替换
sb.replace(0, 9, str); // 左闭右开
// 4. delete(); 删除
sb.delete(0, 5); // 左闭右开
// 5. 清空
sb.delete(0, sb.length());
String、StringBuilder和StringBuffer的区别?
位于
java.math.BigDecimal
,不可变的、任意精度的有符号十进制数。(精确的十进制小数)
用于金融行业浮点数计算
// 参数一
BigDecimal b1 = new BigDecimal(1.0);
// 参数er
BigDecimal b2 = new BigDecimal(0.9);
// 结果
BigDecimal sum = null;
// 加
sum = b1.add(b2);
System.out.println("1.0 + 0.9 = " + sum);
// 减
sum = b1.subtract(b2);
System.out.println("1.0 - 0.9 = " + sum);
// 乘
sum = b1.multiply(b2);
System.out.println("1.0 * 0.9 = " + sum);
// 除 除不尽时 x填保留位数 后面为四舍五入之意
sum = b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);
System.out.println("1.0 / 0.9 = " + sum);
位于
java.math.BigInteger
,不可变的任意精度的整数。
System类代表当前Java程序的运行平台,程序不能创建System类的对象, System类提供了一些类变量 和类方法,允许直接通过System类来调用这些类变量和类方法。
负责字符串的匹配处理(一般用于校验字符串格式)
x:x字符,a表a字符
\\:反斜线字符
\n:换行符
\r:回车符
[abc]:表示a、b、c中的一个字符
[^abc]:表示除了a、b、c之外的任意一个字符
[a-zA-Z]:表示a~z或A~Z中的一个字符
[0-9]:表示数字
.:表示任意字符
\.:表示'.'字符
\d:表示数字字符,[0-9]
\w:表示单词字符,[a-zA-Z_0-9]
^:表示行的开头
$:表示行的结尾
\b:表示单词的边界
?:表示0次或者1次
*:表示0次或者多次
+:表示1次或者多次
{n}:表示n次
{n,}:表示至少n次
{n,m}:n~m次
编码表:由现实世界的字符和对应的数值组成的一张表
tips:所有编码表都兼容ASCII码表