java 6个机制
*克隆机制
克隆就是在内存中复制对象,Java克隆(Clone)是Java语言的特性之一,但在实际中应用比较少见。但有时候用克隆会更方便更有效率。(缺点应该是多分配了一块空间,占内存吧,如果数据量大,内存占用的就大)
对于克隆(Clone),Java有一些限制:
1、被克隆的类必须自己实现Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。Cloneable 接口实际上是个标识接口,没有任何接口方法。
2、实现Cloneable接口的类应该使用公共方法重写 Object.clone(它是受保护的)。某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。
3、在https://www.360docs.net/doc/9d8951027.html,ng.Object类中克隆方法是这么定义的:
protected Object clone()throws CloneNotSupportedException{ }
创建并返回此对象的一个副本。表明是一个受保护的方法,同一个包中可见。
按照惯例,返回的对象应该通过调用 super.clone 获得。
克隆分为深克隆和浅克隆
浅度克隆:浅度克隆对于要克隆的对象,对于其基本数据类型的属性,复制一份给新产生的对象,对于非基本数据类型的属性,仅仅复制一份引用给新产生的对象,即新产生的对象和原始对象中的非基本数据类型的属性都指向的是同一个对象;
深度克隆:在浅度克隆的基础上,对于要克隆的对象非基本数据类型的属性对应的类,也实现克隆,这样对于非基本数据类型的属性,复制的不是同一份引用,即新产生的对象和原始对象中的非基本数据类型的属性指向的不是同一个对象。
*序列化机制
序列化也叫串行化,试讲对象转换成紧凑的二进制域的形式,使该对象具备可以被持久化即永久保存的特性。
序列化的必要性
Java中,一切都是对象,在分布式环境中经常需要将Object从这一端网络或设备传递到另一端。
这就需要有一种可以在两端传输数据的协议。Java序列化机制就是为了解决这个问题而产生。
如何序列化一个对象
一个对象能够序列化的前提是实现Serializable接口,Serializable接口没有方法,更像是个标记。
有了这个标记的Class就能被序列化机制处理。
import java.io.Serializable;
class TestSerial implements Serializable {
public byte version = 100;
public byte count = 0;
}
然后我们写个程序将对象序列化并输出。ObjectOutputStream能把Object输出成Byte流。
我们将Byte流暂时存储到temp.out文件里。
public static void main(String args[]) throws IOException {
FileOutputStream fos = new FileOutputStream("temp.out");
ObjectOutputStream oos = new ObjectOutputStream(fos);
TestSerial ts = new TestSerial();
oos.writeObject(ts);
oos.flush();
oos.close();
}
如果要从持久的文件中读取Bytes重建对象,我们可以使用ObjectInputStream。
public static void main(String args[]) throws IOException {
FileInputStream fis = new FileInputStream("temp.out");
ObjectInputStream oin = new ObjectInputStream(fis);
TestSerial ts = (TestSerial) oin.readObject();
System.out.println("version="+ts.version);
}
多线程机制
*反射机制
反射是Class类具备了解析其他类的对象的内部结构的功能或者说是本领。
Java中至简的说只有两个类Object和Class类。
有了Class类,就可以由Class类解析生成了你想要的实体类。
Class以类的形式存在,Object以对象的形式存在。所以说Class类是描述Object的。
反射机制也叫做自省机制,自己了解自己。Class类中有一系列的属性及方法,这些东西就可以实现反射。
应用反射,就可以知道这个类中哪些方法和属性可以调用和使用。
CLass类中的方法有很多,知晓类的内部结构,就可以调用相应的方法来获取类中相应的属性或方法数组并生成方法或者属性类的集合,这些可以自行学习API来理解。
由Class类获取到了一个类中的属性和方法等结构内容,就可以知晓一个类的内部结构是什么样的。
Class类不仅可以描述对象,还可以生成对象,生成的对象经过下塑造性就可以得到我们想要的类。
对反射进行封装的类为https://www.360docs.net/doc/9d8951027.html,ng.Class类。
多线程机制
简介:
多线程的目的是为了最大限度的利用CPU资源。
Java编写程序都运行在在Java虚拟机(JVM)中,在JVM的内部,程序的多任务是通过线程来实现的。每用java命令启动一个java应用程序,就会启动一个JVM进程。在同一个JVM进程中,有且只有一个进程,就是它自己。在这个JVM环境中,所有程序代码的运行都是以线程来运行。
对于一个进程中的多个线程来说,多个线程共享进程的内存块,当有新的线程产生的时候,操作系统不分配新的内存,而是让新线程共享原有的进程块的内存。因此,线程间的通信很容易,速度也很快。不同的进程因为处于不同的内存块,因此进程之间的通信相对困难。
实际上,操作的系统的多进程实现了多任务并发执行,程序的多线程实现了进程的并发执行。多任务、多进程、多线程的前提都是要求操作系统提供多任务、多进程、多线程的支持。
内容复习:
程序运行的本身是以进程为单位的,程序中的细小的分支即线程,线程离开进程遍无意义。
进程:是程序的一次动态执行过程(运行在操作系统平台),它对应了从代码加载,执行至执行完毕的一个完整过程(main方法中执行)。
main方法本身就是一个进程
线程:是比进程更小的执行单位,一个进程在其执行的过程中,可以产生多个线程,他们分别可以执行不同的任务。
进程与进程来讲,是彼此独立的,不共享空间,而线程之间需要互相联系,所以空间是可以相互共享的。
进程和线程的关系和区别:
进程需要操作系统为其分配独立的内存地址空间。而同一个进程中的线程在同一块地址空间中工作这些线程可以共享一块内存和系统资源,比如共享一个对象或者打开的一个文件。
操作系统是以进程为单位的,程序是以线程为单位的。
多线程程序的用途:
1 充分利用CPU资源,避免资源的浪费。提高处理数据的效率。
2 与用户的更往交互(如复制 ofice)
简化开发模型,每个线程就是指一个单独的任务,这样有助于开发人员对程序的理解和维护。
3 模拟同步动作(动画的效果,交替的执行,几个线程同步执行)
将任务分化成更细粒度的线程,交替执行,模拟同步操作每个线程都会得到一小段程序执行的时间片。
4 节约成本
提高速率的3中方法:
a 增加处理器个数
b 启动多个进程(相互独立,影响通信)
c 多线程
多线程的声明周期阶段
1 创建阶段:实例化线程
https://www.360docs.net/doc/9d8951027.html,ng.Thread https://www.360docs.net/doc/9d8951027.html,ng.Runnable接口
线程的封装类 Thread
1 设计线程类:
class A extends Thread
{
public void run()
{
被重构的Run方法:写要执行的业务逻辑代码;
代码为:当前线程抢占到资源之后所做的事情,}
}
2 设计Runnable接口类,实现该接口,创建线程
class A implements Runnable
{
public void run()
{
被重构的Run方法:写要执行的业务逻辑代码;
代码为:当前线程抢占到资源之后所做的事情,}
}
两种方法的区别,单继承就是用thread即可,实现多个父类时,用Runnable接口。
线程对象实例化方法:
实现Runnable接口时的线程对象实例化方法
Thread t=new Thread(new A());
继承Thread类时的线程对象实例化方法:
A a1=new A();
2 可运行状态
1 就绪状态:当前创建的线程对象一定要放在队列当中,这个队列叫CPU线程队列,只有放在该对列里,才有去抢占CPU资源的权利。放在该队列里了,就表明该队列处于就绪状态。
CPU看见谁,就会给谁分配时间片,让其运行,然后在交替的去分配给别的线程时间片。就绪状态调用的方法为 start()方法。
2 运行:运行状态回调的方法为run()方法,
3 阻塞状态:主动让其休眠,被动的让其休眠
调用的方法1 为sleep(int 时间ms)休眠期,哪个线程调用该方法,哪个线程休息,休息时间有参数决定。休眠时并没有退出队列,休息之后,不需要要通知CPU,可直接调用。
调用的方法2 wait(); 等待:在线程队列之外进行等待,来解决阻塞的问题。
详解为:在阻塞时,会主动退出队列,而再次需要他时,程序要主动召唤它才能再次使用,而唤醒处于等待的对象调用的方法有两种:
1void notify();如果当前的程序可以解决阻塞状态,则需要主动的去唤醒处于队列之外的其他线程对象,唤醒一个线程的方法为notify();
2唤醒所有线程的方法为notifyAll();
封装这三种方法的类为Object类:wait(),notify(),notifyAll();
系统直接支持线程阻塞机制,多线程同步机制。
多线程带来的问题:处理数据的方法有可能存在数据处理不安全,数据处理不同步的安全隐患。
那么处理该问题的方法为线程同步的处理方法(阻塞的第三种方法):在线程要处理的方法前面加上修饰词:synchronized,降低了执行速率,同步之后是排队进行处理的,但是是随机的排队。一个一个的处理,避免了其他的线程抢占资源后出现错误安全隐患。
线程同步的优缺点:
线程同步(即在线程要处理的方法前面加上修饰词:synchronized)可以确保数据在多线程的环境下时,处理是准确和安全的。
线程同步的方法处理数据的速度慢。
!!!线程同步总结:
程序处理数据时尤其是写数据,我们首先应该注意的是,数据处理的准确性,一致性和安全性。所以,为了确保以上三点,java当中是通过同步来解决上述问题的,而同步的方法,就意味着当前线程在处理数据时,其他的线程对象要处于阻塞状态,所以线程同步会导致数据的处理速度慢,可是线程同步却能保证数据处理的安全性。
使用同步的情况:
多线程程序同时访问一个方法时,该方法如果是更新(增删改)数据的方法,就一定要加上同步的修饰词synchronized,
查询数据的时候要考虑数据的速度,不需要考虑安全性。
所以不需要同步。
4 销毁状态
Yeild(); //官方解释终止线程,但实际应用时不是。
Alived(); //企鹅U定线程是否被销毁,不能使线程终止。
是线程死亡的方法是:
在run()方法中加条件,要销毁的时候return;来结束run()方法。
线程是分级别的,0,1,2:高中低
高级别的线程,CPU看到他的几率越高。
线程习题:
进程与线程的定义与区别?
进程:是程序的一次动态执行过程,他对应了从代码加载、执行至执行完毕的一个整个过程。
(一般在控制类中住方法里执行的main()本身就是一个进程)
线程:是比进程更小的执行单位,一个进程在其执行过程中,可以产生多个线程,他们分别可以执行不同的任务。
区别:
进程需要操作为其分配独立的内存地址空间,而同一个进程中的线程在同一块地址空间中工作,
这些线程可共享同一块内存和系统资源,比如共享一个对象或者共享打开的一个文件.
6、多线程的用途?
a、充分利用CPU的资源避免资源浪费
什么时候使用多线程:即提高系统效率时使用。
b、与用户的更加交互(复制Office)
简化开发模型,每一个线程就是指一个单独的任务,这样有助于开发人员对程序的理解和维护。
c、模拟同步动作(模拟同步动作)
d、节约成本
提高效率的三种办法:1、增加处理器的个数(多核)//成本高2、启动多个进程3、多线程//提高处理速度,没有在硬件上增加成本
7、线程的生命周期?分别由程序实现?例如
(1)创建状态:实例化线程对象(https://www.360docs.net/doc/9d8951027.html,ng.Thread java.long.Runnable接口)
如何设计线程类
方法一:先继承Thread 之后重构run()
例:
class A extends Thread//Thread中有一个无返回值的run()
{
public void run()//重构run()
{
}
}
方法二:
实现Runnable() 之后重构run()
例:
class A implements Runnable//Runnable中有一个无返回值的run()
{
public void run()//重构run()
{
}
}
如何创建线程:
方法一:Thread
Thread t=new Thread(new A);
方法二:Runnable
A a1=new A();
(2)可运行状态:(包括两种状态:即就绪状态和运行状态)
就绪状态调用的方法是:线程对象.start();
运行状态执行的是重构run();
(3)阻塞状态:调用方法sleep(int a)//休眠休眠时CPU将不会处理参数为整数,单位是毫秒
(4)销毁状态:
8、sleep()、wait()方法之间的区别?
sleep(Long l);//主动休眠休息一段时间会自动醒来并没有推出CPU队列。休眠期过之后会激活程序
wait();//被动等待在线程队列之外进行等待,来解决阻塞问题
9、notify()、notifyAll()方法之间的区别是什么?
notify()//唤醒一个
nottifyAll()//唤醒多个
10、线程的阻塞状态有几种?分别是哪几种,区别是什么?(答案不确定)
三种主动休眠、被动等待、同步
sleep(Long l);//主动休眠:休息一段时间会自动醒来并没有推出CPU队列。休眠期过之后会激活程序
wait();//被动等待:在线程队列之外进行等待,来解决阻塞问题
同步:同步的方法就意味着当前线程在处理数据时,其他的线程对象要处于阻塞状态,程同步会导致数据的吹速度慢,可是却能保证数据的安全性
11、为什么要进行线程同步?怎么同步?
程序处理数据时,尤其是写数据,我们首先应该注意的是数据处理的准确性、一致性、安全性,
所以为了确保以上三点,java当中是通过同步来解决问题,而同步的方法就意味着当前线程在处理数据时,
其他的线程对象要处于阻塞状态,程同步会导致数据的速度慢,可是却能保证数据的安全性线程同步:多个线程操作同一个程序
12、线程同步有什么优点?有什么缺点?
好处:线程同步可以确保数据在多线程的环境下处理是准确、安全和一致性的。
缺点:线程同步的方法处理数据的速度慢
13、在系统中加入线程的优势有哪些?
确保数据在多线程的环境下处理是准确性、安全性和一致性的。
北大青鸟推荐:Java精选笔试题(含答案解析)
北大青鸟推荐:Java精选笔试题(含答案解析)如果你是计算机专业出生,但是还没有找到工作的话,你就得补补技术了,一些关于面试、笔试的题要多刷一刷。有可能你知道答案,但是由于语言组织能力有所欠缺,所以面试官的印象不是很好,下面分享一些Java精选的鄙视题,希望对面试这者有帮助。 1,volatile关键字是否能保证线程安全?() 答案:否 volatile关键字用在多线程同步中,可保证读取的可见性,JVM只是保证从主内存加载到线程工作内存的值是最新的读取值,而非cache中。但多个线程对volatile的写操作,无法保证线程安全。 假如线程1,线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值,在线程1对count进行修改之后,会write到主内存中,主内存中的count变量就会变为6;线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6;导致两个线程及时volatile关键字修改之后,还是会存在并发的情况。 2,下面哪个流类属于面向字符的输入流( ) A、BufferedWriter B、FileInputStream C、ObjectInputStream D、InputStreamReader 答案:D Java的IO操作中有面向字节(Byte)和面向字符(Character)两种方式。
面向字节的操作为以8位为单位对二进制的数据进行操作,对数据不进行转换,这些类都是InputStream和OutputStream的子类。 面向字符的操作为以字符为单位对数据进行操作,在读的时候将二进制数据转为字符,在写的时候将字符转为二进制数据,这些类都是Reader和Writer的子类。 3,Java能不能不通过构造函数创建对象() A、能 B、不能 答案:A Java创建对象的几种方式: (1) 用new语句创建对象,这是最常见的创建对象的方法。 (2) 运用反射手段,调用https://www.360docs.net/doc/9d8951027.html,ng.Class或者https://www.360docs.net/doc/9d8951027.html,ng.reflect.Constructor类的newInstance()实例方法。 (3) 调用对象的clone()方法。 (4) 运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法。 (1)和(2)都会明确的显式的调用构造函数;(3)是在内存上对已有对象的影印,所以不会调用构造函数;(4)是从文件中还原类的对象,也不会调用构造函数。 4,下列哪个叙述是正确的() A.子类继承父类的构造方法。 B.abstract类的子类必须是非abstract类。 C.子类继承的方法只能操作子类继承和隐藏的成员变量。 D.子类重写或新增的方法也能直接操作被子类隐藏的成员变量。 答案:C 子类是不继承父类的构造方法的,而是必须调用其父类的构造方法。
Java API 试题
永隆 JAVA笔试题 一、选择题 1、关于Java 类的加载过程,下面哪些描述是正确的() A、在 Java 中,有四种类型的类加载器:BootStrapClassLoader、ExtClassLoader、AppClassLoader 以及用户自定义的ClassLoader。//Extension ClassLoader, System ClassLoader+用户自定义的classloader B、使用 new 关键字创建类实例时,其实就显示地包含了类的加载过程 C、在 Java 中,类的实例化流程分为两个部分:类的加载和类的实例化。类的加载又分为显式加载和隐式加载。 D、Class.forName 来加载类时,是通过 ExtClassLoader进行加载的。 //system classLoader 加载 2、关于HashMap的实现机制,下面哪些描述是正确的() A、HashMap中key-value 当成一个整体进行处理,系统总是根据数组的坐标来获得key-value 的存储位置。//没有存储顺序,无下标之说! B、HashMap基于哈希表的 Map 接口的实现,允许使用 null 值和 null 键。 C、如果HashMap中,如果Key的hash相同的话,HashMap将会出错。//会替换相应的value D、HashMap每次容量的扩增都是以2的倍数来增加。//大约获得2倍的桶数! 3、下面的代码执行输出正确的是() 1. public class test( 2. public int aMethod()[ 3. static int i=0; 4. i++; 5. return I; 6. ) 7. public static void main (String args[]){ 8. test test = new test(); 9. test.aMethod(); 10.int j = test.aMethod(); 11.System.out.printIn(j); 12.] 13.} A. 编译错误 B. 编译成功,打印出是“0” C. 编译成功,打印出是“1” D. 编译成功,打印出是“2” A 4、如何获取下面表单 select