异常
一般分为两大类:
1. 一般不可处理的,ERROR
2. 可以处理的,Exception
异常抛出到上一层
throw newNullIndexOutBoundsException(“数组越界”);
throw new NullPointException(“空指针异常”);
自定义异常
如果让一个类成为异常类,必须要继承异常体系,因为只有称为异常体系的子类才有资格具有可抛性。
Class FuShuIndexException extends Exception
{
FuShuIndexException(){
}
}
If(index<0){
thrownew FushuIndexException();
}
异常的分类:
1.编译时被检测异常:只要是Exception和其子类都是,除了特殊子类 RuntimeException体系
2.编译时不检测出异常(运行时):就是Exception中的RuntimeException和其子类
Throws 和 throw的区别
Throws 使用在函数上
Throw使用在函数内
Throws 抛出的是异常类,可以抛出多个,用逗号隔开
Throw抛出的是异常对象
classFuShuExceptionextends Exception
{
FuShuException(){
}
FuShuException(String meg){
super(meg);
}
}
publicclass YiChang {
publicstaticvoid main(String[] args)throws FuShuException {
int [] arry =newint [3];
method(arry,-1);
}
publicstaticint method(int []a,int index) throws FuShuException{
if(a==null)
{
thrownew NullPointerException("空指针异常");
}
if(index >= a.length)
{
thrownewArrayIndexOutOfBoundsException("数组越界异常");
}
if(index <0)
{
thrownew FuShuException("负数异常");
}
return a[index];
}
}
Try catch finally
Finlly 一定为执行的代码,不管你在catch中有没有return
如果有catch中有return则不会执行finally后的代码,而会执行finally中的代码
有一种情况finally不会执行,在catch中有System.exit(0);/退出jvm
Try finally 在finlly关闭自己开启的资源 try中抛出异常
注意事项:子类抛出异常,父类也要抛出异常或者改异常的子类
如果父类抛出多个异常,子类只能抛出父类异常的子集
Object
判断两个对象是否相等
Equals(Object obj);
getClass是获得的当前对象的字节码文件对象{
包括,该类的名字,类的属性
}
class Personextends Object
{
intage;
String name ;
Person(Stringname,int age){
this.name = name;
this.age = age;
}
publicboolean equals(Object obj)
{
if(!(objinstanceof Person)){
thrownew ClassCastException("类型错误");
}
Person p= (Person)obj;
returnthis.age == p.age;
}
}
publicclass ObjectTest {
publicstaticvoid main(String[] args) {
Person p1=new Person("j",2);
Person p2=new Person("j",2);
System.out.println(p1==p2);//false
System.out.println(p1.equals(p2));//false
Person p3= p1;
System.out.println(p1==p3);//true;
System.out.println(Integer.toHexString(p1.hashCode()));
Classc1 = p1.getClass();
Classc2 = p2.getClass();
System.out.println(c1==c2);//true
System.out.println(c1.getName());
System.out.println(p1);
System.out.println(p1.getClass().getName()+"@"+Integer.toHexString(p1.hashCode()));
}
多线程
进程:正在运行的程序
一个进程可以有多条路径,称之为线程
一个进程至少有一个线程
每一个线程都有自己运行的内容,这个内容称之为线程要执行的任务
如何创建线程
1. 定义一个类继承Thread类
2. 覆盖Thread类中的run方法
自定义的线程的任务;
Thread 类用于描述线程,线程是需要任务的,所以Thread类对任务的描述。
这个任务就是通过Thread类的run方法来体现,也就是说,run方法就是封装自定义线程运行的任务
Run方法中定义就是线程要运行的任务代码
如果线程对象直接调用run方法,则和普通对象一样,只有一个主线程执行
所有当定义线程对象后,调用strart()直接开启线程,自动调用run方法。此时就开启了线程。
调用run方法和start有什么区别
Run虽然有线程,但不会启动该线程,
调用start方法启动线程
可以通过Thread的getName()获得当前线程的名字。
Thread.currentThread().getName()获得当前进程的名字
package com.sdut.day3;
class Demoextends Thread
{
private Stringname;
Demo(Stringname){
super(name);
this.name = name;
}
publicvoid show()
{
for(int i = 0 ;i<10 ;i++)
{
System.out.println("线程"+name+i+"线程名字"+getName());//问题getName()是获得当前进程的名字,
//而Thread.currentThread().getName()也是获得当前进程的名字,二者有啥区别
}
}
publicvoid run()
{
show();
}
}
publicclass ThreadDemo {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
Demo d1 =new Demo("第一");
Demo d2 =new Demo("第二");//线程
d1.start();
d2.start();
}
}
创建线程
线程的开始:start()
线程的结束:stop()方法
线程的冻结sleep(time)自动醒过来
Wait()方法使线程冻结,通过notify()来唤醒进程
Cpu的执行资格:可以被cpu处理,在处理队列中等待
Cpu的执行权:正在被cpu处理
冻结:释放执行权的同时,释放执行资格
临时阻塞状态:具备执行资格,单不具备执行权,等待执行权
Stop() |
总结:线程先创建====start()=====线程的执行============线程的销毁
线程的阻塞 |
Sleep() |
线程的冻结
线程创建的第二种方式:实现Runnable
1.覆盖接口中的run方法,将线程的任务封装到run方法中
2.通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递
为什么:
因为线程的任务都封装在Runnable的run方法中,所以在线程对象创建时就必须明确要运行的任务
3. 调用线程对象的start()方法开启线程
4. 如果不传递,则是Thread的默认任务,传的话则是自己指定的。
5. /*
6. *第二种实现Runnable接口来创建对象的具体过程总结
7. *class Thread implements Runnable
8. * {
9. * private Runnable r1 ;
10. * Thread(){
11. * }
12. * Thread(Runnable r){
13. * r1 = r
14. * }
15. * public void run()
16. * {
17. * r1.run();
18. * }
19. * public void start()
20. * {
21. * run()
22. * }
23. * }
24. *class Demo implements
25. *{
26. * public void run()
27. *{
28. * System.out.println("ddd");
29. *}
30. *}
31. *class Test()
32. *{
33. * public static void main(String []args){
34. * Demo d = new Demo();
35. * Thread t = new Thread(d);//通过此处把d穿进去,利用多态,为构成方法初始化
36. *此时Thread类中的r就是d即 Runnable r = new Demo()//向上转型
37. *
38. * t.start() ;//调用start()方法时,会调用run()方法,在调用r.run()即子类的run方法,因为
39. *多态执行看右边
40. *}
41. *}
42. * */
实现Runnable的好处
1. 将线程的任务从线程的子类中分离出来,进行了单独的封装。
按照面向对象的思想将任务封装成对象
2. 避免了java的单继承的局限性
线程的安全性问题
/
class Ticketimplements Runnable
{
private intnum = 1;
publicvoid run()
{
sale();
}
publicvoid sale()
{
while(true){
if(num>0)
{
System.out.println(Thread.currentThread().getName()+"--------sale"+num--);
}
}
}
}
publicclass ThreadDemo2 {
publicstaticvoid main(String[] args) {
Ticket s=new Ticket();//线程任务对象的封装
Thread t1=new Thread(s);
Thread t2=new Thread(s);
Thread t3=new Thread(s);
t1.start();
t2.start();
t3.start();
}
}
当第一个线程进入if(num>0)判断,此时num=1进入if里面
当进入里面后,cpu切换到别的线程,此时num=1也进入if里面
同理,其他的进程也能进入if里面
这样输出:就是1 0 -1 结果明显有错
原因:
1. 多个线程在操作共享数据。
2. 操作共享数据的线程代码有多条
3. 当一个线程在执行操作共享数据的多条代码中,其他进程参与了运算。就会导致线程安全问题的产生。
解决:就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程不可以参与运算的
用同步代码块。
格式:synchroized(){需要被同步的代码}