List,Set都是继承自Collection接口 List特点:元素有放入顺序,元素可重复 Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉 (注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法 ,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。) Set和List对比: Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。 1.1.3 List 和 Map 区别List是对象集合,允许对象重复。 Map是键值对的集合,不允许key重复 1.1.4 ArrayList 与 Vector 区别ArrayList和Vector都是用数组实现的,主要有这么三个区别:Vector是多线程安全的,线程安全就是说多线程访问同一代码,不会产生不确定的结果。而ArrayList不是,这个可以从源码中看出,Vector类中的方法很多有synchronized进行修饰,这样就导致了Vector在效率上无法与ArrayList相比; 两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不同。 Vector可以设置增长因子,而ArrayList不可以。 Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。 适用场景分析:Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。 如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。 1.1.5 Arraylist 与 LinkedList 区别Arraylist: 优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。 缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。 LinkedList: 优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景 缺点:因为LinkedList要移动指针,所以查询操作性能比较低。 适用场景分析:当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。 1.1.6 HashMap 和 Hashtable 的区别1.hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。 2.hashTable同步的,而HashMap是非同步的,效率比hashTable要高。 3.hashMap允许空键值,而hashTable不允许。 注意:
TreeMap:非线程安全基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。 Treemap:适用于按自然顺序或自定义顺序遍历键(key)。 1.1.7 HashSet 和 HashMap 区别set是线性结构,set中的值不能重复,hashset是set的hash实现,hashset中值不能重复是用hashmap的key来实现的。 map是键值对映射,可以空键空值。HashMap是Map接口的hash实现,key的唯一性是通过key值hash值的唯一来确定,value值是则是链表结构。 他们的共同点都是hash算法实现的唯一性,他们都不能持有基本类型,只能持有对象 1.2 多线程(*****)1.2.1 创建线程的方式及实现Java中创建线程主要有三种方式: 一、继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。 (2)创建Thread子类的实例,即创建了线程对象。 (3)调用线程对象的start()方法来启动该线程。 二、通过Runnable接口创建线程类 (1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。 (2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。 (3)调用线程对象的start()方法来启动该线程。 三、通过Callable和Future创建线程 (1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。 (2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。 (3)使用FutureTask对象作为Thread对象的target创建并启动新线程。 (4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值 1.2.2 创建线程的三种方式的对比采用实现Runnable、Callable接口的方式创见多线程时,优势是: 线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。 在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。 劣势是: 编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。 使用继承Thread类的方式创建多线程时优势是: 编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。 劣势是: 线程类已经继承了Thread类,所以不能再继承其他父类。 1.2.3 线程池的几种方式newFixedThreadPool(intnThreads)
创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程规模将不再变化,当线程发生未预期的错误而结束时,线程池会补充一个新的线程 newCachedThreadPool()
创建一个可缓存的线程池,如果线程池的规模超过了处理需求,将自动回收空闲线程,而当需求增加时,则可以自动添加新线程,线程池的规模不存在任何限制 newSingleThreadExecutor()
这是一个单线程的Executor,它创建单个工作线程来执行任务,如果这个线程异常结束,会创建一个新的来替代它;它的特点是能确保依照任务在队列中的顺序来串行执行 newScheduledThreadPool(intcorePoolSize)
创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。 1.2.4 线程的生命周期1)生命周期的五种状态 新建(new Thread)
当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。
例如:Thread t1=new Thread(); 就绪(runnable)
线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start(); 运行(running)
线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。 死亡(dead)
当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。 自然终止:正常运行run()方法后终止 异常终止:调用stop()方法让一个线程终止运行 堵塞(blocked)
由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。 正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。 正在等待:调用wait()方法。(调用motify()方法回到就绪状态) 被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复) 1.2.5 悲观锁 乐观锁乐观锁 悲观锁
是一种思想。可以用在很多方面。 比如数据库方面。
悲观锁就是for update(锁定查询的行)
乐观锁就是 version字段(比较跟上一次的版本号,如果一样则更新,如果失败则要重复读-比较-写的操作。) JDK方面:
悲观锁就是sync
乐观锁就是原子类(内部使用CAS实现) 本质来说,就是悲观锁认为总会有人抢我的。
乐观锁就认为,基本没人抢。 1.2.5.1乐观锁的业务场景及实现方式乐观锁(Optimistic Lock):
每次获取数据的时候,都不会担心数据被修改,所以每次获取数据的时候都不会进行加锁,但是在更新数据的时候需要判断该数据是否被别人修改过。如果数据被其他线程修改,则不进行数据更新,如果数据没有被其他线程修改,则进行数据更新。由于数据没有进行加锁,期间该数据可以被其他线程进行读写操作。 乐观锁:比较适合读取操作比较频繁的场景,如果出现大量的写入操作,数据发生冲突的可能性就会增大,为了保证数据的一致性,应用层需要不断的重新获取数据,这样会增加大量的查询操作,降低了系统的吞吐量。 1.3 IO1.3.1 什么是IO流?它是一种数据的流从源头流到目的地。比如文件拷贝,输入流和输出流都包括了。输入流从文件中读取数据存储到进程(process)中,输出流从进程中读取数据然后写入到目标文件。 1.3.2 字节流和字符流的区别字节流在JDK1.0中就被引进了,用于操作包含ASCII字符的文件。JAVA也支持其他的字符如Unicode,为了读取包含Unicode字符的文件,JAVA语言设计者在JDK1.1中引入了字符流。ASCII作为Unicode的子集,对于英语字符的文件,可以使用字节流也可以使用字符流。 1.3.3 Java中流类的超类主要有那些?· java.io.InputStream · java.io.OutputStream · java.io.Reader · java.io.Writer 1.3.4 FileInputStream和FileOutputStream是什么?这是在拷贝文件操作的时候,经常用到的两个类。在处理小文件的时候,它们性能表现还不错,在大文件的时候,最好使用BufferedInputStream (或 BufferedReader) 和 BufferedOutputStream (或 BufferedWriter) 1.3.5字节流和字符流,你更喜欢使用哪一个?个人来说,更喜欢使用字符流,因为他们更新一些。许多在字符流中存在的特性,字节流中不存在。比如使用BufferedReader而不是BufferedInputStreams或DataInputStream,使用newLine()方法来读取下一行,但是在字节流中我们需要做额外的操作。 1.4反射1.4.1 什么是Java的反射Java的反射机制是在编译并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用在编译期并不知道的类。这样的特点就是反射。 1.4.2 Java反射有什么作用 Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。大家都用过eclipse。当我们构建出一个对象的时候,去调用该对象的方法和属性的时候。一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。 1.4.3 反射的用途及实现Java反射的主要功能:
- 确定一个对象的类
- 取出类的modifiers,数据成员,方法,构造器,和超类.
- 找出某个接口里定义的常量和方法说明.
- 创建一个类实例,这个实例在运行时刻才有名字(运行时间才生成的对象).
- 取得和设定对象数据成员的值,如果数据成员名是运行时刻确定的也能做到.
- 在运行时刻调用动态对象的方法.
- 创建数组,数组大小和类型在运行时刻才确定,也能更改数组成员的值. 反射的应用 spring 的 ioc/di 也是反射….
javaBean和jsp之间调用也是反射….
struts的 FormBean 和页面之间…也是通过反射调用….
JDBC 的 classForName()也是反射…..
hibernate的 find(Class clazz) 也是反射…. 2web2.1 HTTP 请求的 GET 与 POST 方式的区别1. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,在URL中可以看到。 2.post是通过HTTPPOST机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。 3. get安全性非常低,post安全性较高。但是执行效率却比Post方法好。 4. get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。 5. 对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。 所以综上建议:
1、包含机密信息的话,建议用Post数据提交方式;
2、在做数据查询时,可以使用Get方式;而在做数据添加、修改或删除时,建议用Post方式;
|