Java基础知识(中)
2025/9/17大约 10 分钟
Java基础中
第 7 章:异常的捕获及处理
1. 异常基本
- 加入异常处理后,程序就不会因为异常而中断运行
2. 异常类的继承结构
Throwable
Exception
:一般表示程序中出现问题,可以使用try...catch...
解决,程序中出现的错误都是该类的子类Error
:一般指 JVM 错误,程序中无法处理
- 程序中规定最大错误处理为
Exception
3. throw
和 throws
关键字
throw
:手动抛出异常,常用于自定义异常的排出(用户名不规范....等)
throw new Exception("手动抛出异常...")
throws
:定义在方法后面- 表示此方法不处理方法里面的异常
- 交由调用方法处处理异常
public class User {
// 使用throws
public void print() throws Exception {
int i=0;
int j=10;
// 运算时就不需要异常处理
int x=j/i;
System.out.println("User...");
}
}
public class dome02 {
public static void main(String[] args) {
User user = new User();
// 在这方法调用处进行异常处理
try {
user.print();
} catch (Exception e) {
System.out.println(e);
}
}
}
// 主方法也可以使用throws不管该调用,交给最大“头”处理--JVM
public class dome02 {
// 也使用throws
public static void main(String[] args) throws Exception {
User user = new User();
user.print();
}
}
4. Exception
类和 RuntimeException
类
Exception
:在程序中必须使用try...catch...\throws
进行异常处理RuntimeException
:可以不进行异常处理,出现异常交给 JVM 处理
// parseInt方法是抛出了异常的,但NumberFormatException属于RuntimeException的子类
public static int parseInt(String s) throws NumberFormatException
// 故当我们调用parseInt()方法时就不用再调用处处理异常
public class dome02 {
public static void main(String[] args) {
// 调用parseInt()
int temp= Integer.parseInt("123");
}
}
5. 自定义异常
- 自定义异常选择需要继承的异常类,然后调用
super(msg)
设置提示信息 - 出现异常时,
new throw
自定义异常(msg)
6. 断言(了解)
- 判断运行结果是否正确
assert 表达式:"提示信息"
// 如表达式中是false则会报错,正确则无事发生
public class dome02 {
public static void main(String[] args) {
int[] arr={1,2,3};
assert arr.length==0:"数组长度不为0";
}
}
- 以上代码无法预期运行,详细信息 P232
第 8 章:包及访问控制权限
1. 包的概念及其使用
- 包是在使用多个类或接口时,为了避免重复定义而采用的一种措施
- 带有包名的 java 文件的编译方法:
javac -d . hello.java
/*
-d:表示生成目录,生成的目录以java文件中的包名(package)为准
.:表示在所在文件夹下生成
*/
提示:
- 一个类中只有一个
public class
(必须和文件名一致) - 可以有多个
class
2. 静态导入包
- 如果一个类中的方法全是使用
static
声明的静态方法,则需要import static
导入 - 导入的方法可以直接通过方法名使用,不需要
类.方法名
使用
3. 控制访问权限
private
:本类可访问default
:本包的类可访问protected
:不同包的子类可访问(其他包的类继承了该包的类,调用super
访问)public
:不同包的类可访问
第 9 章:多线程
1. 实现多线程
Java 中实现多线程有两种方法:(无论那种方法都要依靠 Thread
类进行启动)
1. 继承 Thread
类(Runnable
子类),覆写 run
方法,实例化调用 start()
方法(相同名称只能调用一次)
代码示例
public class X extends Thread {、
// 可以自己创建name 也可以调用父类super(name)
private String name;
public X(String name) {
this.name = name;
}
// 线程的主体
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(name +"运行 i="+i);
}
}
}
public class dome02 {
public static void main(String[] args) {
X a = new X("线程A");
X b = new X("线程B");
// 调用start()方法启动线程
a.start();
b.start();
}
}
疑问:为什么不能直接调用 run()
方法而要调用 start()
呢?
- 线程需要底层操作系统的支持,而
start()
方法中声明的关键词native
表示调用本机操作系统函数
2. 实现 Runnable
接口,实现 run()
方法,调用 Thread
中构造方法传入实现类,再调用 start()
方法
Thread
中构造方法:Thread(Runnable target)
, Thread(Runnable target,String name)
代码示例
/*
类似于代理模式:
X:真实主题
Thread:代理主题
*/
public class X implements Runnable {
private String name;
public X(String name) {
this.name = name;
}
// 线程的主体
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(name +"运行 i="+i);
}
}
}
public class dome02 {
public static void main(String[] args) {
X a = new X("线程A");
X b = new X("线程B");
// 实例化Thread对象
Thread threadA = new Thread(a);
Thread threadB = new Thread(b);
// 调用start()方法启动线程
threadA.start();
threadB.start();
}
}
3. 区别
- 资源共享(卖票实例)
- 继承
Thread
:不能资源共享,每个线程票是单独的 - 实现
Runnable
:可以资源共享,每个线程共享票
- 继承
2. Callable
接口(可返回结果的多线程)
- 区别于
Runnable
的不可返回结果
public interface Callable<V> {
public V call() throws Exception;
}
- 实现
Callable
接口,并实现call()
方法(同run
也是方法的主体),需要返回结果 - 实例化实现类,作为参数实例化
FutureTask
(Thread
没有接收Callable
的构造方法) FutureTask
对象作为参数实例化Thread
,调用start()
方法- 调用
FutureTask
对象的get()
方法获取返回结果
代码示例
public class X implements Callable<String> {
private int ticket=5;
// 线程的主体
@Override
public String call() {
for (int i = 0; i < 10; i++) {
if (this.ticket>0){
System.out.println("卖票,ticket="+this.ticket--);
}
}
return "票买完了...";
}
}
public class dome02 {
public static void main(String[] args) throws Exception {
X x = new X();
// 实例化实现类,作为参数实例化FutureTask(Thread没有接收Callable的构造方法)
FutureTask<String> task1 = new FutureTask<>(x);
FutureTask<String> task2 = new FutureTask<>(x);
// FutureTask对象作为参数实例化Thread,调用start()方法
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
thread1.start();
thread2.start();
// 调用FutureTask对象的get()方法获取返回结果
System.out.println("task1:"+task1.get());
System.out.println("task2:"+task2.get());
}
}
3. Thread
的主要方法
提示:Java 程序运行时,至少启动两个线程(一个 main
函数线程,一个垃圾收集线程)
4. 同步
一个线程运行完之后,下一个线程才开启
1. 同步代码块(synchronized
)
代码示例
public class MyThread implements Runnable{
private int ticket=5;
public void run() {
for (int i = 0; i < 100; i++) {
// 同步代码块(synchronized)
// this代表需要同步的线程是this,即为MyThread线程对象
synchronized (this){
if (ticket>0){
try {
Thread.sleep(300);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("卖票:ticket="+ticket--);
}
}
}
}
}
public class dome01 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread);
Thread t2 = new Thread(myThread);
Thread t3 = new Thread(myThread);
t1.start();
t2.start();
t3.start();
}
}
2. 同步方法
代码示例
package test;
public class MyThread implements Runnable{
private int ticket=5;
public void run() {
for (int i = 0; i < 100; i++) {
// 调用方法
sale();
}
}
// 同步方法
public synchronized void sale(){
if (ticket>0){
try {
Thread.sleep(300);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("卖票:ticket="+ticket--);
}
}
}
5. 死锁
具体内容 P272
6. Object
类对线程的支持--唤醒与等待

wait
和sleep
的区别:sleep
是等待规定时间自主醒来,而wait
是需要notify
或notifyAll
唤醒- 调用:直接使用
super
在需要的地方调用(super.wait()
...)
7. 线程的生命周期

第 10 章:泛型
1. 泛型
- 泛型的目的是为了防止对象向下转换时出现的类型问题(没用泛型只有用
Object
接收转换) - 泛型指定必须为包装类(
Integer
...)
2. 指定多个泛型
public class User<K,V> {
private K name;
private V age;
}
3. 泛型的安全警告
- 当一个泛型未指定泛型类型时,则会自动擦除泛型使用
Object
表示,出现警告
4. 通配符
- 用法:当方法传递参数时,必须要使用相同的泛型类型才能传递
- 简单理解:当一个类规定了泛型,然后在实例化时候就必须指定需要的类型,但是下列例子中需要传入的参数是实例化对象,那么方法参数定义怎么去满足已经指定类型的实例化呢?那就是用
[?]
放开接收的权限,让他自己判断
(如用法一中:String
和Object
不是同一种泛型类型则会报错!!!)
代码示例
public class User<T> {
private T name;
public T getName() {return name;}
public void setName(T name) {this.name = name;}
public String toString() {
return "User{" + "name=" + name + '}';
}
}
public class dome01 {
public static void main(String[] args) {
User<String> user = new User<>();
print(user);
}
// 用法一:虽然string是Object的子类依然报错
public static void print(User<Object> user){
System.out.println("user..."+user);
}
// 用法二:不需要指定接收类型,可以运行
public static void print(User user){
System.out.println("user..."+user);
}
// 用法三:通配符
public static void print(User<?> user){
System.out.println("user..."+user);
}
}
- 用通配符接收的泛型对象不能被修改(可以设置为
null
)
代码示例
public class dome01 {
public static void main(String[] args) {
User<String> user = new User<>();
user.setName("zhangsan");
print(user);
// 接收泛型对象后修改,报错
User<?> user1 = new User<String>();
user1.setName("zhangsan");
print(user1);
}
// 通配符
public static void print(User<?> user){
// 接收泛型对象后修改,报错
user.setName("lisi");
System.out.println("user..."+user);
}
}
5. 受限泛型
- 在引用传递的泛型操作中,指定一个泛型对象的范围上限和范围下限
// 设置上限(只能接收上限类或其子类)
声明对象:类名称<? extends 类(上限类)> 对象变量名称
声明类:[访问权限] 类名称<T extends 类(上限类)> {}
// 设置下限(只能接收下限类或其父类)
声明对象:类名称<? super 类(下限类)> 对象变量名称
声明类:[访问权限] 类名称<T super类(下限类)> {}
// 上限实例
// 表示声明参数对象只能是String或其子类
public static void print(User<? extends String> user){
System.out.println("user..."+user);
}
// 表示T只能是只能是String或其子类
public class User<T extends String> {}
6. 泛型与子类的继承限制
- 子类的泛型类型不能用父类进行接收:
User<String>
不能用User<Object>
接收
解释(了解):
- 如果子类泛型变为父类泛型,则表示扩大了子类的内容
- 我们使用泛型接受则表示我们只需要指定的类型,不需要其他的范围,例如:指定了
String
就表示我们只需要String
中的结构,用Object
接收的话则变成了全部的结构,扩大了范围
7. 泛型接口
- 子类实现方法:
// 泛型接口
interface User<T>{}
// 子类实现方法一:
public class Student<T> implements User<T> {
public void print() {
System.out.println("Student...");
}
}
// 子类实现方法二:直接在接口中指定类型
public class Student implements User<String> {
public void print() {
System.out.println("Student...");
}
}
8. 泛型方法
// 不固定返回参数
public <T> T print(T t) {
return t;
}
// 固定返回参数
public <T> void print1(T t) {
System.out.println(t);
return ;
}
// 设置限制
public <T extends String> T print1(T t) {
return t;
}
解释:
<T>
:表示泛型类型的表示符号T
,可以理解为申明泛型方法的关键字
9. 泛型数组
// 传入可变参数,并且返回接受泛型数组
public <T> T[] print(T ...t) {
return t;
}
// 传入泛型数组
public <T> void print1(T[] t) {
return ;
}
10. 泛型的嵌套设置
class User<S>{}
class Student<K,V>{}
// 实例化:将Student对象作为泛型 S 传入User中
User user=new User<Student<String,Integer>> (new Student<String,Integer>("dd",18))
------------指明S的类型为Student<String,Integer>------传入Student的实例化对象