java基础知识学习日记9

学习内容:使用File类访问本地文件系统,使用文件过滤器,理解IO流的模型和处理方式,使用IO流执行输入、输出操作,使用转换流将字节流转为字符流,推回流的功能和用法,重定向标准输入、输出,访问其他进程的输入、输出,RandomAccessFile的功能和用法,对象序列化机制和作用,通过实现Serializable接口实现序列化,实现定制的序列化,通过实现Extrenalizable接口实现序列化,JavaIO的概念和作用,使用BufferChannel完成输入、输出,Charset的功能和作用,FileLock的功能和用法,NIO.2的文件IO和文件系统,通过NIO.2监控文件变化,通过NIO.2访问、修改文件属性

学习笔记:

1Windows的路径分隔符使用反斜线,而java程序的反斜线表示转义字符,所以如果需要在Windows的路径下包括反斜线,则应该使用两条反斜线,或者直接使用斜线也可以,java程序支持将斜线当成平台无关的路径分隔符。

2javaIO流是实现输入、输出的基础,它可以方便地实现数据的输入、输出操作,在java中把不同的输入、输出源抽象表述为流,通过流的方式允许java程序使用相同的方式来访问不同的输入、输出源。

3、这里的输入、输出都是从程序运行所在内存的角度来划分的。

4、可以从、向一个特定的IO设备读写数据的流,称为节点流,节点流也被称为低级流,处理流则用一个已经存在的流进行连接或封装,通过封装后的流来实现数据读写功能,处理流也被称为高级流。

5、实际上,java使用处理流来包装节点流是一种典型的装饰器设计模式,通过使用处理流来包装不同的节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入、输出功能,因此处理流也被称为包装流。

6、处理流的功能主要体现在以下两个方面:性能的提高:主要以增加缓冲的方式来提高输入输出的效率。操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的内容,而不是输入输出一个或多个水滴。

7、关于使用处理流的优势,归纳起来就是两点。对开发人员来说,使用处理流进行输入输出操作更简单使用处理流的执行效率更高。

8、在使用处理流包装了底层节点流之后,关闭输入输出流资源时,只要关闭最上层的处理流即可,关闭最上层的处理流时,系统会自动关闭被该处理流包装的节点流。

9、如果进行输入输出的内容是文本内容,则应该考虑使用字符流,如果进行输入输出的内容是二进制内容,则应该考虑使用字节流。

10、由于RandomAccessFile可以自由访问文件的任意位置,所以如果只需要访问文件部分内容,而不是把文件从头读到尾,使用RandomAccessFile将是更好的选择。如果程序需要向已存在的文件后追加内容,则应该使用RandomAccessFIle

11、对象的序列化指将一个java对象写入IO流中,与此对应的是,对象的反序列化则指从IO流中恢复该java对象。

12、在ObjectInputStream输入流中的readObject()方法声明抛出异常,也就是说,当反序列化时找不到对应的java类时会引发该异常。

13、如果使用序列化机制向文件中写入多个java对象,使用反序列化机制恢复对象时必须按实际写入顺序读取。

14java序列化采用了一种特殊的序列化算法,其算法内容如下。所有保存到磁盘中的对象都有一个序列化编号。当程序试图序列化一个对象时,程序将先检查对象是否已经被序列化过,只有该对象从未被序列化过,系统才会将该对象转换成字节序列并输出。如果某个对象已经序列化过,程序将只是直接输出一个序列化编号,而不是再次重新序列化该对象。

15、当使用java序列化机制序列化可变对象时一定要注意,只有第一次调用writeObject()方法来输出对象时才会将对象转换成字节序列,并写入到输出流中,在后面程序中即使该对象的实例变量发生了改变,再次调用writeObject()方法输出该对象时,改变后的实例变量也不会被输出。

16、当对某个对象进行序列化时,系统会自动把该对象的所有实例变量依次进行序列化,如果某个实例变量引用到另一个对象,则被引用的对象也会被序列化,如果被引用的对象的实例变量也引用了其他对象,则被引用的对象也会被序列化,这种情况被称为递归序列化。

17transient关键字只能用于修饰实例变量,不可以修饰java程序中的其他成分。

18wrtieObject()方法存储实例变量的顺序应该和readObject()方法中恢复实例变量的顺序一致,否则将不能正常恢复该java对象。

19、关于对象序列化,还有如下几点需要注意。对象的类名、实例变量都会被序列化,方法、类变量、transient实例变量都会不被序列化。实现serializable接口的类如果需要让某个实例变量不被序列化,则可以在该实例变量前加transient修饰符,而不是加static。虽然static关键字也可以达到这个效果,但static关键字不能这样用。保证序列化对象的实例变量类型也是可序列化的,否则需要使用transient关键字来修饰该实例变量,要不然,该类是不可序列化的。反序列化对象时必须有序列化对象的class文件。当通过文件、网络来读取序列化后的对象时,必须按照实际写入的顺序读取。

20如果修改类时仅仅修改了方法,则反序列化不受任何影响,类定义无须修改serialVersionUID类变量的值。如果修改类时仅仅修改了静态变量或瞬态实例变量,则反序列化不受任何影响。如果修改类时修改了非瞬态的实例变量,则可能导致序列化版本不兼容,如果对象流中的对象和类中包含同名的实例变量,而实例变量类型不同,则反序列化失败,类定义应该更新UID类变量的值。如果对象流中的对象比新类中包含更多的实例变量,则多出的实例变量值被忽略,序列化版本可以兼容,类定义可以不更新serialVersionUID类变量的值,如果新类比对象流中的对象包含更多的实例变量,则序列化版本可以兼容,类定义可以不更新UID的值,但反序列化得到的新对象中多出的实例变量值都是null0

21Buffer中包含两个重要的方法,即flip()和clear(),flip()为从Buffer中取出数据做好准备,而clear()为再次向buffer中装入数据做好准备。

22channel与传统流对象的区别。①channel可以直接将制定文件的部分或全部直接映射成buffer程序不能直接访问channel中的数据,包括读取写入都不行,channel只能与buffer进行交互,也就是说,如果要从channel中取得数据,必须先用bufferchannel中取出一些数据,然后让程序从buffer中取出这些数据,如果要将程序中的数据写入channel,一样先让程序将数据放入buffer中,程序再将buffer里的数据写入channel中。

23lock)trylock()方法存在区别:当lock()试图锁定某个文件时,如果无法得到文件锁,程序将一直阻塞,而tryLock()是尝试锁定文件,它将直接返回而不是阻塞,如果获得了文件锁,该方法则返回该文件锁,否则将返回null

24、直接使用lock()或tryLock()方法获取的文件锁是排它锁。

 

学习内容:线程的基础知识,理解线程和进程的区别与联系,两种创建线程的方式,线程的run()方法和start()方法的区别与联系,线程的生命周期,线程死亡的几种情况,控制线程的常用方法,线程同步的概念和必要性,使用syncharonized控制线程同步,使用Lock对象控制线程同步,使用Object提供的方法实现线程通信,使用条件变量实现线程通信,实现Callable接口创建线程,线程池的功能和用法,ForkJoinPoolThreadLocal类的功能和用法,使用线程安全的集合类

学习笔记:

1、一般而言,进程包含如下三个特征:独立性:进程是系统中独立存在的实体,它可以拥有自己独立的资源,每一个进程都拥有自己私有的地址空间。在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间。动态性:进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合,在进程中加入了时间的概念,进程具有自己的生命周期和各种不同的状态,这些概念在程序中都是不具备的。并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会相互影响。

2、并发性和并行性是两个概念,并行指在同一时刻,有多条指令在多个处理器上同时执行,并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。

3、线程也被称为轻量级进程,线程是进程的执行单元。线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父线程。

4、从逻辑角度看,多线程存在一个应用程序中,让一个应用程序中可以由多个执行部分同时执行,但操作系统无须将多个线程看做多个独立的应用,对多线程实现调度和管理以及资源分配。线程的调度和管理由进程本身负责完成。

5、使用多线程编程具有如下几个优点:进程之间不能共享内存,但线程之间共享内存非常容易。系统创建进程时需要为该进程重新分配系统资源,但创建线程代价小的多,因此使用多线程来实现多任务并发比多进程效率高。③java语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了java的多线程编程。

6、使用继承Thread类的方法来创建线程类时,多个线程之间无法共享线程类的实例变量。

7、创建线程的三种方式对比:线程类只是实现RunnableCallable接口的方式,还可以继承其他类。在这种方式下,多个线程可以共享同一个target对象,多以非常适合多个相同线程来处理同一分资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好的体现了面向对象的思想。劣势是,编程稍稍复杂,如果需要访问当前线程,则必须使用ThreadcurrentThread()方法。劣势是,因为线程类已经继承了Thread类,所以不能继承其他父类。优势是,编写简单,如果需要访问当前线程,直接使用this就可以了。

8、启动线程的正确方法是调用Thread对象的start()方法,而不是直接调用run()方法,否则就变成单线程程序了。

9、只能对处于新建状态的线程调用start()方法,否则将引发异常。

10、只有当一个线程调用了它的sleep()或yield()方法后才会放弃所占用的资源----也就是必须由该线程主动放弃所占用的资源。

11、当发生如下情况时,线程将会进入阻塞。线程调用sleep()方法主动放弃所占用的处理器资源。线程调用了一个阻塞时IO方法,在该方法返回之前,该线程被阻塞。线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有。线程在等待某个通知。程序调用了线程的suspend()方法将该线程挂起。

12、当发生如下特定的情况可以解除上面的阻塞,让该线程重新进入就绪状态。调用sleep()方法的线程经过了指定时间。线程调用的IO已经返回。线程成功获得了同步监视器。其他线程发出了一个通知。处于挂起状态的线程被调用了resunme()恢复方法。

13、线程会以如下三种方式结束,结束后就处于死亡状态。①run()或call()方法执行完成,线程正常结束。线程抛出了一个未捕获的异常。直接调用的线程的stop()方法---该方法很容易导致死锁,不推荐使用。

14、当主线程结束时,其他线程不受任何影响,并不会随之结束,一旦子线程启动起来后,它就拥有和主线程相同的地位,它不会受主线程的影响。

15、不要对处于死亡状态的线程调用start()方法,程序只能对新建状态的线程调用start()方法,对于新建状态的线程两次调用start()方法也是错误的。这都会引发异常。

16、当在某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被join的线程执行完为止。

17、前台线程死亡后,JVM会通知后台线程死亡,但从它接收指令到做出响应,需要一定时间,而且要将某个线程设置为后台线程,必须在该线程启动之前设置,否则将会引发异常。

18、关于sleep()方法和yield()方法的区别如下。①sleep()方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级,但yield()方法只会给优先级相同,或优先级更高的线程执行机会。②sleep()方法会将线程转入阻塞状态,直到经过阻塞时间才会转入就绪状态,而yield()不会将线程转入阻塞状态,它只是强制当前线程进入就绪状态。因此完全有可能某个线程调用yield()方法暂停之后,立即再次获得处理器资源被执行。③sleep()方法声明抛出了异常,所以调用sleep()方法时要么捕捉该异常,要么抛出异常,而yield()方法没有声明抛出任何异常。④sleep()方法比yield()方法有更好的可移植性,通常不建议使用yield()方法来控制并发线程的执行。

你可能感兴趣的:(java基础知识学习日记9)