可以通过继承 Thread 类或实现 Runnable 接口来创建线程。 class MyThread extends Thread {
public void run() {
// 线程执行的代码
}
}
MyThread thread = new MyThread();
thread.start(); // 启动线程
class MyRunnable implements Runnable {
public void run() {
// 线程执行的代码
}
}
Thread thread = new Thread(new MyRunnable());
//thread作为代理,将实现接口的类传入
thread.start(); // 启动线程
Thread thread = new Thread(new Runnable() {
public void run() {
// 线程执行的代码
}
});
thread.start(); // 启动线程
Thread thread = new Thread(() -> {
// 线程执行的代码
});
thread.start(); // 启动线程
新建状态:线程对象被创建但还没有调用 start() 方法。
就绪状态:线程调用 start() 方法后,等待 CPU 时间片执行。
运行状态:线程正在执行中。
阻塞状态:线程可能在等待某个条件满足,例如锁。
终止状态:线程执行完毕或出现异常导致终止。
start():启动线程。
run():定义线程执行的代码,在 start() 方法中自动调用。
sleep(long millis):使当前线程睡眠指定的毫秒数。
join():等待线程终止。
isAlive():判断线程是否处于活动状态。
interrupt():中断线程。
yield():暂停当前正在执行的线程。
在多线程环境下,可能会遇到线程安全的问题,可以使用同步机制来保证数据的一致性和正确性。例如使用 synchronized 关键字、Lock 接口等来实现线程同步。
同步方法:将 synchronized 关键字应用于方法上,表示整个方法是同步的。 public synchronized void method() {
// 线程安全的代码
}
//在同步方法中,对象锁(即互斥锁)默认是当前实例对象(this)。
同步代码块:将 synchronized 关键字应用于代码块上,只对被 synchronized 修饰的代码块进行同步。 public void method() {
// 非线程安全的代码
synchronized (obj) {
// 线程安全的代码
}
// 非线程安全的代码
}
在同步代码块中,对象锁可以是任意对象。通常建议使用私有对象或 this 关键字作为锁对象。
静态同步方法:对于静态方法,可以使用 synchronized 修饰来实现同步。 public static synchronized void method() {
// 线程安全的代码
}
//静态同步方法的锁对象是当前类的 Class 对象。
1如果是静态成员变量,则可以创建多个类,共享/操作这个变量
2如果是普通变量,则创建一个对象,创建多个线程,多个线程共同操作这个一个对象的变量
必须掌握-简单-但是好用
枚举是一种特殊的类,用于表示一组预定义的常量。可以通过使用关键字 enum 来定义一个枚举。 enum MyEnum {
VALUE1,
VALUE2,
VALUE3
}
//不同常量用逗号隔开
最后一个用分号;
枚举可以包含常量和方法。每个枚举常量都是枚举类型的一个实例,并且可以通过枚举类型名称和点操作符来访问
常量访问:MyEnum myValue = MyEnum.VALUE1;
方法访问:MyEnum.VALUE2.doSomething();
枚举可以具有自定义的构造函数,并且可以在枚举常量中使用。 enum MyEnum {
VALUE1("First value"),
VALUE2("Second value"),
VALUE3("Third value");
private String description;
private MyEnum(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
以使用增强的 for 循环遍历枚举中的所有常量,也可以使用 values() 方法获取包含所有枚举常量的数组。 方式1:for (MyEnum enumValue : MyEnum.values()) {
System.out.println(enumValue);
}
方式2:MyEnum[] enumValues = MyEnum.values();
以使用 == 运算符来比较两个枚举常量是否相等,也可以使用 equals() 方法进行比较。
枚举在很多场景下非常有用,例如表示一组相关的常量、状态机、选项列表等。
枚举是一种特殊的类,用于定义一组固定的常量。
枚举常量在声明时被实例化,并且只能是预定义的几个值
枚举常量是枚举类的实例,通过在枚举类中列出常量来定义。
枚举常量默认是 public static final 的,并且使用大写字母命名。
枚举可以拥有自己的方法,可以在枚举常量上进行调用。
枚举方法可以定义在枚举类内部,也可以定义在枚举常量内部。
枚举的构造方法只能是私有的,因为枚举常量在声明时已经实例化。
枚举的构造方法默认是私有的,可以显式声明为 private。
枚举类型可以使用 == 进行比较,因为枚举常量是单例对象。
枚举类型也可以使用 equals() 方法进行比较
枚举可以实现一个或多个接口,从而拥有接口定义的方法。
枚举常量必须实现接口方法,或者在枚举类内部提供默认实现。
在Java 8之前,switch语句只支持整数类型、字符类型和字符串类型。
从Java 8开始,switch语句也可以用于枚举类型
泛型
集合
IO
编译时异常(checked)
在代码中进行显式处理或者声明的异常
javac.exe java文件
IOException(输入/输出异常):在输入/输出操作失败时抛出,例如文件读写操作、网络连接异常等。--FileNotFoundException
SQLException(SQL异常):在数据库访问发生错误时抛出,例如连接数据库失败、执行SQL语句错误等。
ClassNotFoundException(类未找到异常):在尝试加载某个类时找不到对应的类文件时抛出。
NoSuchMethodException(方法未找到异常):在尝试反射调用一个不存在的方法时抛出。
运行时异常类型(unchecked)
编程错误导致的
的异常
java.exe java文件
NullPointerException(空指针异常):当使用空引用调用方法或访问属性时抛出。
ArrayIndexOutOfBoundsException(数组下标越界异常):当尝试访问数组中不存在的索引时抛出。
IllegalArgumentException(非法参数异常):当方法接收到一个不合法的参数时抛出,例如传递了一个无效的枚举值。
ArithmeticException(算术异常):在算术运算过程中出现异常,例如除数为零。
ClassCastException(类转换异常):在进行类型转换时,如果转换的目标类型与实际对象的类型不兼容,则会抛出此异常。
IllegalAccessException(非法访问异常):当试图访问类、方法或字段的时候,如果没有足够的访问权限,则会抛出此异常。
NumberFormatException(数字格式异常):当使用错误格式的字符串转换成数字类型时,会抛出此异常。例如,使用Integer.parseInt()方法将一个非数字字符串转换为整数时就可能抛出该异常。
补充:为什么不需要显式地在方法签名中声明或处理的异常?
它将异常封装成RuntimeException并抛出,会导致程序的执行被这中断,并且异常信息会输出到控制台。这种方式被称为非受检异常(Unchecked Exception),即不需要显式地在方法签名中声明或处理的异常。
try-catch-finally结构可以嵌套
使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配。 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的try-catch结构(在没有写finally的情况)。继续执行其后的代码
catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错
常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()
在try结构中声明的变量,再出了try结构以后,就不能再被调用
体会1:使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。
* 体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理。
finally是可选的,如果选择一定会执行,即使catch中又出现异常了,try中有return语句,catch中有return语句等情况也一定会执行。
像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中
throws
异常的处理方式
声明方法可能要抛出的
各种异常类
throws的方式只是将异常抛给了方法的调用者。 并没有真正将异常处理掉
"throws + 异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。,一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常 类型时,就会被抛出。异常代码后续的代码,就不再执行!
如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中有异常,必须使用try-catch-finally方式处理
1看抛出异常的类型 2看抛出异常的位置,一般抛出异常后,后面的代码不执行
3抛的以产被catch抓住,要么封装成新的异常继续抛,要么直接解决异常
"抛":程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象, 并将此对象抛出,一旦抛出对象以后,其后的代码就不再执行。
① 系统自动生成的异常对象
② 手动的生成一个异常对象,并抛出(throw)
"抓":可以理解为异常的处理方式:① try-catch-finally ② throws
try:作用:如果给定的文件路径不是一个文件(而是目录、不存在等),则抛出 IllegalAccessException 异常。
catch:作用:try 块中,可能会抛出多个异常类型,将捕获到的异常 e 封装为 RuntimeException 异常,并重新抛出。
try块内部抛出的异常被catch块捕获后,使用throw语句将异常再次抛出并封装为RuntimeException。这样做的目的是将具体的异常类型转换为通用的RuntimeException类型,使得异常能够向上层调用栈传播,而不需要在每一层方法中添加throws声明。这会导致程序的执行被中断,并且异常信息会输出到控制台。这种方式被称为非受检异常
总结:1知道try里面可以放什么,catch作用,可以写什么,finally作用,throw,throws位置,用法。
2解决异常:使用try-catch-final进行解决,如果是在try中抛出,catch可以捕获,然后解决,如果不解决就要继续往上抛,抛的是运行异常可以继续抛也可以不继续抛【直接中断程序】,抛的是编译异常必须向上抛,直到方法调用者解决。
匿名内部类是一种定义在方法内部或代码块内部的没有名字的内部类。它是一种简化代码的方式,常用于创建临时的、只需要使用一次的类或接口实现。
匿名内部类可以作为一个表达式来定义,并直接实例化对象。通常用于实现接口或继承自类。
MyInterface obj = new MyInterface() {
// 实现接口的方法
};
// 定义一个接口
interface OnClickListener {
void onClick();
}
// 使用匿名内部类实现接口,并创建对象
OnClickListener listener = new OnClickListener() {
@Override
public void onClick() {
System.out.println("按钮被点击了");
}
};
listener.onClick(); // 调用接口方法
可以使用匿名内部类来继承一个类,并创建继承类的对象。
MyClass obj = new MyClass() {
// 覆盖父类的方法
};
// 定义一个父类
class Animal {
void eat() {
System.out.println("动物在进食");
}
}
// 使用匿名内部类继承父类,并创建对象
Animal animal = new Animal() {
@Override
void eat() {
System.out.println("狗在啃骨头");
}
};
animal.eat(); // 调用继承类的方法
匿名内部类可以访问定义在其外部环境中的变量,包括方法内的局部变量和方法的参数。但是,该变量必须被声明为 final 或实际上是 final 的(即不可修改)。 int x = 10; // 外部变量
MyInterface obj = new MyInterface() {
public void method() {
System.out.println(x); // 访问外部变量
}
};
局部内部类有名字,可以有多个对象实例化;而匿名内部类没有名字,只能用于创建一个对象实例。 匿名内部类的使用场景通常是当你只需要在某个方法内部使用某个类或接口的实现,并且不希望在其他地方重复使用这个类或接口时。
匿名内部类不能被继承和重用,因此只适合于简单的、只使用一次的情况。
使用匿名内部类时,需要注意外部变量是否满足 final 或实际上是 final 的要求。
总结起来,匿名内部类是一种用于简化代码的方式,用于创建临时的、只需要使用一次的类或接口实现。它可以实现接口、继承类,并且可以访问外部变量。然而,由于其特殊性,使用时需要注意匿名内部类的适用场景和限制条件。