java基础知识(六)——异常、IO流、多线程、反射、集合

java基础知识(六)——异常、IO流、多线程、反射、集合

一、异常

java程序中会出现不正常的情况,而这些情况我们统称为异常。

《java编程思想》中定义异常:阻止当前方法或作用域继续执行的问题。

1、异常体系

在java程序中会出现不正常的情况,java是面向对象的语言,任何的事物都可以使用类进行描述,那么这时候sun公司就是用了很多的类描述了java程序中各种不正常的情况,而用于描述程序不正常的情况的类被称为异常类,很多异常类堆积起来就形成了java中的异常体系。

等级一:Throwable(所有异常或者错误类的超类)

             等级二:Error(错误-------错误一般是用于jvm或者是硬件引发的问题,所以我们一般不会通过代码去处理错误的。)

                             Exception(异常-------是需要通过代码去处理的):

                                               编译时异常(异常较严重)

                                               运行时异常(异常较轻量)


2、Throwable类常用的方法:

toString():返回当前异常对象的完整类名+异常信息。

getMessage():返回此 throwable 的详细消息字符串。

printStackTrace():打印异常的栈信息。


3、如何区分错误与异常?

        程序出现了不正常的信息
        如果不正常的信息的类名是以Error结尾的,那么肯定是一个错误。(ThreadDeath)
        如果是以Exception结尾的,那么肯定就是一个异常。


4、异常的处理:

方式一:捕获处理
      捕获处理的格式:    
            try{
                可能发生异常的代码;

            }catch(捕获的异常类型 变量名){
                处理异常的代码....
            }
        
        捕获处理要注意的细节:
            a. 如果try块中代码出了异常经过了处理之后,那么try-catch块外面的代码可以正常执行。
            b. 如果try块中出了异常的代码,那么在try块中出现异常代码后面的代码是不会执行了。
            c. 一个try块后面是可以跟有多个catch块的,也就是一个try块可以捕获多种异常的类型。
            d. 一个try块可以捕获多种异常的类型,但是捕获的异常类型必须从小到大进行捕获,否则编译报错。
    实例:

public class TestException01 {

    public static void main(String[] args) {
        int[] arr = null;
        div(4,0,null);
    }
    
    public static void div(int a,int b,int[] arr){
        int c = 0;
        try{
            c = a/b;
            System.out.println(arr.length);
        }catch(ArithmeticException e){
            e.printStackTrace();
            System.out.println("nisb ");
        }catch(NullPointerException e){
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println("c="+c);
    }

}


     方式二:抛出处理
       抛出处理(throw throws)关键字
       抛出处理要注意的细节:
        a. 如果一个方法的内部抛出了一个 编译时异常对象,那么必须要在方法上声明抛出。
        b. 如果调用一个声明抛出 编译时异常的方法,那么调用者必须要处理异常。
        c. 如果一个方法内部抛出了一个异常对象,那么throw语句后面的代码都不会再执行了(一个方法遇到了throw关键字,该方法也会马上停止执行的)。
        d. 在一种情况下,只能抛出一种类型异常对象。
       
       throw 与throws两个关键字的区别:
        1. throw关键字是用于方法内部的,
            throws是用于方法声声明上的。
        2. throw关键字是用于方法内部抛出一个异常对象的,
            throws关键字是用于在方法声明上声明抛出异常类型的。
        3. throw关键字后面只能有一个异常对象,
            throws后面一次可以声明抛出多种类型的 异常。


二、集合

集合的体系:

1、Collection 单例集合的根接口

                1.1---List:如果是实现了List接口的集合类, 该集合类具备的特点:有序(添加进去的顺序与元素出来的顺序是一致的。),可重复。

                                1.1.1---ArrayListArrayList:底层是维护了一个线性结构的Object数组实现的,特点: 查询速度快,增删慢。

                                1.1.2---LinkedList:LinkedList底层是使用了链表数据结构实现的,特点: 查询速度慢,增删快。

                1.2---Set:如果是实现了Set接口的集合类, 该集合类具备的特点:无序(添加进去的顺序与元素出来的顺序不一致的。),不重复。

                                1.2.1---HashSet:底层是使用了哈希表来支持的,特点: 存取速度快.。

                                1.2.2---TreeSet:如果元素具备自然顺序的特性,那么就按照元素自然顺序的特性进行排序存储。

2、Map 双例集合的根接口

具备的特点: 存储的数据都是以键值对的形式存在的,键不可重复,值可以重复。

                2.1---HashMap(线程不安全)

                           HashMap的存储原理:
                                         往HashMap添加元素的时候,首先会调用键的hashCode方法得到元素的哈希码值,然后经过运算就可以算出该元素在哈希表中的存储位置。
                                         ------  情况1:如果算出的位置目前没有任何元素存储,那么该元素可以直接添加到哈希表中。
                                        ------   情况2:如果算出的位置目前已经存在其他的元素,那么还会调用该元素的equals方法与这个位置上的元素进行比较,如果equals方法返回的是  false,那么该元素允许被存储,如果equals方法返回的是true,那么该元素被视为重复元素,不允存储。

                2.2---TreeMap

                          特点:会对元素的键进行排序存储。

                         TreeMap 要注意的事项:
                                        1.  往TreeMap添加元素的时候,如果元素的键具备自然顺序,那么就会按照键的自然顺序特性进行排序存储。
                                        2.  往TreeMap添加元素的时候,如果元素的键不具备自然顺序特性,那么键所属的类必须要实现Comparable接口,把键的比较规则定义在CompareTo  方法上。
                                       3. 往TreeMap添加元素的时候,如果元素的键不具备自然顺序特性,而且键所属的类也没有实现Comparable接口,那么就必须在创建TreeMap对象的时 候传入比较器。

                2.3---HashTable(线程安全)

3、集合使用迭代器遍历:

public static void main(String[] args) {
    Iterator iter = list.iterator();
    while(iter.hasNext()){
        //遍历list集合里的所有元素
        System.out.println(iter.next());
    }
}

三、IO流

IO技术主要的作用是解决设备与设备之间的数据传输问题。

         1、输入流

              ------输入字节流:使用缓冲数组配合循环一起读取

                        --------| InputStream 所有输入字节流的基类  抽象类
                        --------| FileInputStream  读取文件数据的输入字节流 :
                                      使用FileInputStream读取文件数据的步骤:
                                      1. 找到目标文件
                                      2. 建立数据的输入通道。
                                      3. 读取文件中的数据。
                                      4. 关闭资源。

实例代码:

public static void readTest4() throws IOException{
		long startTime = System.currentTimeMillis();
		//找到目标文件
		File file = new File("D:\\a.txt");
		//建立数据的输入通道
		FileInputStream fis = new FileInputStream(file);
		//建立缓冲数组配合循环读取文件的数据。
		int length = 0; //保存每次读取到的字节个数。
		byte[] buf = new byte[1024]; 
		//存储读取到的数据 缓冲数组的长度一般是1024的倍数,
		因为与计算机的处理单位。理论上缓冲数组越大,效率越高
		while((length = fis.read(buf))!=-1){ 
		// read方法如果读取到了文件的末尾,那么会返回-1表示。
			System.out.print(new String(buf,0,length));
		}
		//关闭资源
		fis.close();
	}


              ------输入字符流:使用缓冲字符数组读取文件。

                         --------FileReader:

示例代码:

public static void readTest2() throws IOException{
		//找到目标文件
		File file = new File("D:\\Demo1.java");
		// 建立数据的输入通道
		FileReader fr = new FileReader(file);
		//建立缓冲字符数组读取文件数据
		char[] buf = new char[1024];
		int length = 0 ; 
		while((length = fr.read(buf))!=-1){
			System.out.print(new String(buf,0,length));
		}
		//关闭资源
		fr.close();
	}

                           ---------BufferedReader:缓冲输入字符流


         2、输出流

              ------输出字节流:使用字节数组把数据写出。

                        --------| OutputStream 是所有输出字节流 的父类。  抽象类
                        --------| FileOutStream 向文件输出数据的输出字节流。

                                   使用FileOutStream输出文件数据的步骤:
                                   1. 找到目标文件
                                   2. 建立数据的输出通道。
                                   3. 把数据转换成字节数组写出。
                                   4. 关闭资源

实例代码:

public static void writeTest3() throws IOException{
				//找到目标文件
				File file = new File("D:\\b.txt");
				//建立数据输出通道
				FileOutputStream fos = new FileOutputStream(file);
				//把数据写出。
				String data = "abc";
				byte[] buf = data.getBytes();
				// 0 从字节数组的指定索引值开始写, 2:写出两个字节。
				fos.write(buf, 0, 3);
				//关闭资源
				fos.close();
			}


              ------输出字符流

                       -----FileWriter:

实例代码:

public static void  writeTest1() throws IOException{
		//找到目标文件
		File file = new File("D:\\a.txt");
		//建立数据输出通道
		FileWriter fw = new FileWriter(file,true);
		//准备数据,把数据写出
		String data = "今天天气非常好!!";
		fw.write(data);  //字符流具备解码的功能。
		//刷新字符流
		//fw.flush();
		//关闭资源
		fw.close();
	}
                     --------BufferedWriter:缓冲输出字符流


四、反射

Java反射机制:
    程序在运行状态中,对于任意一个类(class文件),都能知道这个类的所有属性和方法;对于任意一个对象, 都能够调用它的任意一个方法和属性;这种动态获取 信息以及动态调用对象方法或属性的功能称为Java语言的反射机制。

在反射技术中一个雷的任何成员都有对于的类进行描述:构造器——》Constructor类;成员变量——》Field类;方法——》Method类;


动态代理:

    在java的动态代理机制中,有两个重要的类或接口。一个是 ImvocationHandler(Interface)、另一个则是Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。

    每一个动态代理类都必须要实现InvocationHandler这个接口,并且每一个代理类的实例都关联到了一个handler,让我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发由InvocationHandler这个接口的invoke方法来进行调用。

实例:

public interface Subject
		{
			public void rent();
			
			public void hello(String str);
		}
		
		public class RealSubject implements Subject
		{
			@Override
			public void rent()
			{
				System.out.println("I want to rent my house");
			}
			
			@Override
			public void hello(String str)
			{
				System.out.println("hello: " + str);
			}
		}
		
		public class DynamicProxy implements InvocationHandler
		{
			//这个就是我们要代理的真实对象
			private Object subject;
			
			//构造方法,给我们要代理的真实对象赋初值
			public DynamicProxy(Object subject)
			{
				this.subject = subject;
			}
			
			@Override
			public Object invoke(Object object, Method method, Object[] args)
					throws Throwable
			{
				//在代理真实对象前我们可以添加一些自己的操作
				System.out.println("before rent house");
				System.out.println("Method:" + method);
				
				//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象
				//关联的handler对象的invoke方法来进行调用
				Object result = method.invoke(subject, args);
				
				//在代理真实对象后我们也可以添加一些自己的操作
				System.out.println("after rent house");	
				return result;
			}
		}
		
		public class Client
		{
			public static void main(String[] args)
			{
				//我们要代理的真实对象
				Subject realSubject = new RealSubject();

				//我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
				InvocationHandler handler = new DynamicProxy(realSubject);

				/*
				 * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
				 * 第一个参数 handler.getClass().getClassLoader() ,
				 *				我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
				 * 第二个参数realSubject.getClass().getInterfaces(),
				 *				我们这里为代理对象提供的接口是真实对象所实行的接口,
				 * 				表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
				 * 第三个参数handler,我们这里将这个代理对象关联到了
				 *				上方的 InvocationHandler 这个对象上
				 */
				Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
						.getClass().getInterfaces(), handler);
				
				System.out.println(subject.getClass().getName());
				subject.rent();
				subject.hello("world");
			}
		}

五、多线程

进程 :正在执行的程序称作为一个进程。进程负责了内存空间的划分。

线程:线程在一个进程中负责了代码的执行,就是进程中一个执行路径

多线程:在一个进程中有多个线程同时在执行不同的任务。

一个java应用程序至少有几个线程?
  答:至少有两个线程,一个是主线程负责main方法代码的执行,一个是垃圾回收器线程,负责了回收垃圾。

多线程的好处与弊端

好处:
    1. 解决了一个进程能同时执行多个任务的问题。
    2. 提高了资源的利用率。

弊端:
    1. 增加cpu的负担。
    2. 降低了一个进程中线程的执行概率。
    3. 引发了线程安全问题。
    4. 出现了死锁现象

创建线程的方式:
            方式一:
            1. 自定义一个类继承Thread类。
            2. 重写Thread类的run方法 , 把自定义线程的任务代码写在run方法中
                疑问: 重写run方法的目的是什么?  
               每个线程都有自己的任务代码,jvm创建的主线程的任务代码
               就是main方法中的所有代码, 自定义线程的任务代码就
               写在run方法中,自定义线程负责了run方法中代码。    
            3. 创建Thread的子类对象,并且调用start方法开启线程。

线程的生命周期:
    创建:新创建了一个线程对象。
    可运行:线程对象创建后,其他线程调用了该对象的start()方法。 该状态的线程位于可运行线程池中,变得可运行,等待获取cpu的执行权。
    运行:就绪状态的线程获取了CPU执行权,执行程序代码。
    阻临时塞: 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
    死亡:线程执行完它的任务时。





  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值