一、J2SE部分
Java基础:
1. 九种基本数据类型的大小,以及他们的封装类。
byte(Byte) 1 ,short(Short) 2 ,int(Integer) 4 ,long(Long) 8 ,float(Float) 4 ,double(Double) 8,boolean(Boolean),char(Character)2
2. Switch能否用string做参数?
switch语句中的变量类型可以使byte,short,int,char。从jdk1.7后可以使用String类型,是通过switch中的String.hashcode将String转换成int进行判断的。
3. equals与==的区别。
==操作符是用来比较两个变量的值是否相等,即就是比较变量在内存中的存储地址是否相同,equals()方法时String类从Object类中继承的,被用来检测两个对象的内容是否相同。
4、String s=new String(‘xyz’);创建了几个object对象?
会创建一个String类型的变量s。在类加载到此处之前没有出现“xyz”字面量的话,加载此处会创建一个对应“xyz”的String常量对象。在符合规范的JVM上,执行到此处new关键字会创建
一个String对象。
5. Object有哪些公用方法?
1、clone()创建斌返回此对象的副本
2、equals()判断
3、getclass()返回object的运行类
4、hashcode()返回对象的哈希码值
5、notify()唤醒正在等待对象监听器的单个进程
6、notifyAll()唤醒正在等待对象监听器的所有进程
7、wait()导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
8、toString()返回此对象的字符串表示形式
9、finalize()当垃圾收集确定不需要该对象时,垃圾回收器调用该方法
6. Java的四种引用,强弱软虚,用到的场景。
强引用:垃圾回收器不会回收
软引用:如果内存空间足够,垃圾回收器就不会进行回收,如果内存空间不足,垃圾回收器就会进行回收
弱引用:一旦发现了只有弱引用的对象,垃圾回收器就会进行回收。
虚引用:如果发现该对象还具有虚引用,就会在回收该对象之前,吧这个虚引用加入到与之关联的引用队列中。
7. 静态变量和实例变量的区别
静态变量前要加上关键字static,实例变量则不会。
实例变量是属于某个对象的属性,必须创建了实例对象,其中的实例变量才会分配空间,才能使用这个实例变量。静态变量不属于任何的实例对象,而是属于类,也称为类变量,只
要程序加载了类的字节码,不用创建任何实例对象,就会被分配空间。总之就是,静态变量不需要创建任何的对象就可以直接使用,而实例变量需要先创建实例对象才能被使用。
8. Overload和Override的区别:
重载Overload表示的是同一个类中可以有多个相同名称的方法,但这些方法的参数列表不同,即就是参数参数或参数类型不同。重载时返回值当然可以不一样,但是如果参数列表
完全一致时,不能通过返回类型不一致而实现重载,这是不可以的。
重写Override表示子类中的方法可以与父类中的方法名称和参数完全相同,通过子类创建的对象来调用这个方法时,将调用子类中定义的方法,即就是子类中的该方法将父类的该方
法覆盖了。子类覆盖父类方法时只能抛比父类更少或者更小的异常。重写的方法其返回必须和被覆盖的方法返回一致。
9. 抽象类和接口的区别
抽象类可以有默认的方法进行实现,可以有构造器,可以有main方法进行运行,可以直接在该类中添加实现的方法
接口没有默认的方法进行实现,没有构造器,不可以使用main方法进行运行,在接口中添加方法时需要在具体实现的类中添加方法。
10. String、StringBuffer与StringBuilder的区别。
String表示内容不可修改的字符串,StringBuffer表示内容可以修改的字符串,
String覆盖了equals()方法和hashcode()方法,而StringBuffer没有覆盖两个方法,,所以StringBuffer对象存储到java集合类中时会出现问题。
StringBulider也表示内容可以修改的字符串,但是其线程是不安全的,运行效率高
11. Java面向对象的特征与含义。
封装、继承、抽象、多态
1、封装:封装的目的在于实现程序的“高内聚,低耦合”,防止程序相互依赖而带来的变动影响。封装是保证是把对同一事物进行操作的方法和相关的方法放在同一个类中,把方法
和他操作的数据放在同一个类中。
2、抽象:抽象就是找出事物的相似和共性,然后将这些事物归为同一类,这个类只考虑这些事物的相似和共性,忽略和当前主题不相关的因素。
3、继承:子类继承父类的内容作为自己的内容,可以加入新的内容或者是修改父类的内容而更加适合特殊的需要。提高了额程序的可重用性和可扩张性。
4、多态:多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类
的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
12. java多态的实现
接口实现,
继承父类进行方法重写,
同一个类中进行方法重载。
异常:
14. error和exception区别
error表示有可能恢复但比较困难的的一种严重问题,程序是不能进行处理的
exception表示一种设计或者实现问题。
15. 运行时异常和一般异常的区别
异常表示程序运行过程中可能出现的非正常状态。运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见的运行错误。java编译器要求方法必须声明抛出可能出现的非
运行时异常,但是并不要求必须声明抛出未被捕获的异常
16. Java中的异常处理机制和简单原理和应用
JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常。违反语义规则包括2种情况。一种是JAVA类库内置的语义检查。例如数组下标越界,
会引发IndexOutOfBoundsException;访问null的对象时会引发 NullPointerException。另一种情况就是JAVA允许程序员扩展这种语义检查,程序员可以创建自己的异常,并自由选
择在何时用 throw关键字引发异常。所有的异常都是java.lang.Thowable的子类。
17. Java语言如何进行异常处理,throws,throw,try catch finally代表什么意义,try块中可以抛出异常吗?
Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java中,每个异常都是一个对象,它是Throwable类或其它子类的实例。当一个
方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java的异常处理是通过5个关键词来实现的:try、catch、
throw、throws和finally。一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throws)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)
由缺省处理器来处理。
用try来指定一块预防所有”异常”的程序。紧跟在try程序后面,应包含一个catch子句来指定你想要捕捉的”异常”的类型。
throw语句用来明确地抛出一个”异常”。
throws用来标明一个成员函数可能抛出的各种”异常”。
Finally为确保一段代码不管发生什么”异常”都被执行一段代码。
可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try语句,”异常”的框架就放到堆栈上面,直到所有的try语句都完成。
如果下一级的try语句没有对某种”异常”进行处理,堆栈就会展开,直到遇到有处理这种”异常”的try语句。
18. try catch finally,try里有return,finally还执行么?
1、finally语句总会执行
2、如果try、catch中有return语句,finally中没有return,那么在finally中修改除包装类型和静态变量、全局变量以外的数据都不会对try、catch中返回的变量有任何的影响(包装类型、静态变量会改变、全局变量)
3、尽量不要在finally中使用return语句,如果使用的话,会忽略try、catch中的返回语句,也会忽略try、catch中的异常,屏蔽了错误的发生
4、finally中避免再次抛出异常,一旦finally中发生异常,代码执行将会抛出finally中的异常信息,try、catch中的异常将被忽略
19. Java中final、finally和finalize的区别、
final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量必须定义成final类型,例如,一段代码……
finally是异常处理语句结构的一部分,表示总是执行。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。JVM不保证此方法总被调用。
20. 常见的运行时异常
系统异常是RuntimeException的子类,常见的系统异常有:
ArrayIndexOutOfBoundsException - 数组越界访问
ClassCastException - 类型转换异常
NullPointerException - 试图访问一空对象的变量、方法或空数组的元素
IllegalArgumentException - 方法的参数无效
NoClassDefFoundException - JAVA运行时系统找不到所引用的类
集合:
21. Collection框架的结构
集合框架(Collection Framework)泛指java.util包的若干个类和接口.如Collection,List,ArrayList,LinkedList,Vector(自动增长数组),HashSet,HashMap等.
集合框架中的类主要封装的是典型的数据结构,如动态数组,链表,堆栈,集合,哈希表等.
集合框架类似编程中经常用到的工具类,使得编码这专注于业务层的实现,不需要从底层实现相关细节—“数据结构的封装”和”典型算法的实现”.
22. Collection包结构
Collection是集合类的上级接口,是单列集合。继承他的接口主要有Set 和List.
Set接口的子接口有:HashSet,TreeSet
List接口的子接口有:Arraylist,LinkedList,Vector
23. Collection与Collections的区别。
Collection是集合类的上级接口,继承他的接口有Set和List
Collections是针对集合类的一个帮助类,它提供一系列的静态方法实现集合的搜索,排序,线程安全等操作。
24. Colection框架中实现比较要实现什么接口?
comparable:只包含compareTo()方法
comparator:compare()和equals()
25. Map、Set、List、Queue、Stack的特点与用法。
1、Map是以键值对的形式进行存储的,其中key是唯一不可重复的,value的可以重复,当插入的值是key相同,后加入的会将已有的覆盖。他有几个具体的实现类,包括Treemap
和HashMap,TreeMap是有序的,HashMap是无序的。
2、List 有序,可重复
|--ArrayList
底层数据结构是数组,查询快,增删慢,线程不安全,效率高
|--Vector
底层数据结构是数组,查询快,增删慢,线程不安全,效率高
|--LinkedList
底层数据结构是链表,查询慢,增删块,线程安全,效率低
3、Set 无序,唯一
|--HashSet
底层数据结构是哈希表
如何保证元素的唯一性:
依赖两个方法,hashCode()和equals()
|--LinkedHashSet
底层数据结构是链表和哈希表,由链表保证元素有序,由哈希表保证元素唯一
|--TreeSet
底层数据结构是红黑树,
如何保证元素的排序:
自然排序:让元素所属的类实现Comparable接口
比较器排序:让集合接收一个Comparator的实现类对象
如何保证元素的唯一性:
根据比较的返回值是否是0来决定的
4、Query队列遵循先进先出的原则,不允许插入null值,其中提供了相应的进队和出队的方法,建议使用offer()方法来添加元素,使用poll()方法删除元素
5、Stack遵从后进先出的原则,继承自Vector。他通过5个操作对Vector类进行扩展,它提供了push和pop操作,以及去堆栈顶点的peek()方法,测试堆栈是否为空的empty方法
6、使用方法:
如果涉及到堆栈,队列等操作,建议使用List
对于快速插入和删除元素建议使用LinkedList
需要快速随机访问元素建议使用ArrayList
26. Set里面的元素不能重复,用什么方法区分重复与否。?
Set里的元素是唯一不能重复的,元素是否重复使用equals()方法进行判断。
equals()方法和==方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是两个分离的对象的内容和类型相匹配的话,返回真值。
27. HashMap和Hashtable的区别。
1、Hashtable是基于Dictionary类的,HashMap是Map接口的一个实现类
2、Hashtable是线程安全的,即是同步的;HashMap线程不是安全的,不是同步的。
3、HashMap可以将空值作为key或value
28. HashMap、LinkedHashMap、TreeMap的区别。
1、HashMap是根据键的hashcode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,取得的数据完全是随机的
2、LinkedHashMap保存了记录的插入顺序,在使用Iterator进行遍历的时候,先得到的肯定是先插入的数据,可以在构造时带参数,按照应用次数来进行排序
3、TreeMap实现SortMap接口,能够把它保存的记录根据键排序。默认的是升序排序,也可以指定排序的比较器,进行遍历的时候得到的是排序过的记录。
29. HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。
1、HashMap是java数据结构中两大结构数组和链表的组合。HashMap底层数组,数组中的每一项又是一个链表。程序会先根据key的hashcode()方法返回值决定该Entry在数组中的
存储位置,如果该位置上没有元素,就会将元素放置在此位置上,如果两个Entry的key相同,会调用equals,返回值是true则覆盖原来的value值,返回false则会形成Entry链,位于
头部
2、ArrrayList的底层实现是数组,在执行add操作时,会先检查数组 大小是否可以容纳新的元素,如果不够就会进行扩容。然后会将原来的数据拷贝到新的数组中
3、LinkedList底层是一个链表,其实现增删改查和数据结构中的操作完全相同,而且插入是有序的
4、LinkedHashMap的底层结构式是双链表,其他的逻辑处理与HashMap一致,同样没有锁保护,多线程使用时存在风险
5、ConcurrentHashMap是segment数组结构和HashEntry数组结构组成的,segment在ConcurrentHashMap中充当锁的角色,HashEntry用于存储键值对数据。segment的结构是数组
和链表,一个segment中有一个HashEntry,每个HashEntry是一个链表结构的元素。对HashEntry中的数据进行修改时,需要先获得它所对应的segment锁。每个ConcurrentHashMap
默认有16个segment。
30. 迭代器Iterator
Iterator提供了统一遍历操作集合元素的统一接口,Collection接口实现Iterator接口。每个集合都通过实现Iterator接口中的iterator()方法返回实例,然后对元素进行迭代操作,,但是
在迭代元素的时候不能使用集合的方法删除元素,否则会抛出异常,可以使用Iterator接口中的remove()方法进行删除
31. 快速失败(fail-fast)和安全失败(fail-safe)的区别
Iterator的安全失败是基于对底层集合做拷贝,因此它不受源集合修改的影响。util包下的所有集合类都是快速失败的,util.concurren包下面的所有类都是安全失败的。
IO流:
32. 什么是java序列化?如何实现java序列化
序列化就是一种用来处理对象流的 机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可以将流化后的对象在网络间进行传递。
序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable 只是为了标注 该对象时可被序列化的。
线程、反射、枚举、泛型:
33. 什么是线程安全
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类时进行保护,其他线程不能访问直到该线程访问结束,其他的线程才可以使用。一般使用synchronized关键字加锁同步
控制来解决线程不安全的问题。
34. 创建线程的3种方式。
1、继承Thread类
2、实现Runnable接口
3、应用程序可以使用Executor框架来创建线程池。
实现Runnable接口的这种方式是更好的,因为不需要继承Thread类,在应用设计中已经继承了别的对象的情况下,需要多继承,但是java不支持多继承,同时线程池也是非常高效的,
很容易实现和使用。
35. 线程从创建到死亡的几种状态
1、新建new:新创建一个线程对象
2、可运行runnable:线程创建后其他的线程调用了该对象的start()方法,该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu的使用权
3、运行running:可运行状态的线程获取了cpu的时间片,执行程序代码
4、阻塞block:线程因为某种原因放弃了cpu的使用权,暂时停止运行,知道线程进入可运行状态才会再次有机会进入运行状态。
5、死亡dead:run()、main()方法执行结束或者是因为异常退出,,该线程结束生命周期,死亡的线程不可再次复生。
36. 什么是ThreadLocal。
在面向对象编程中,创建和销毁对象是很耗费时间的,因为创建一个对象要获取内存资源或者其他的资源。在java中更是如此,所以提高服务程序效率的一个手段就是尽可能减少创建和
销毁对象。线程池,顾名思义就是事先创建若干个可执行的线程放如到一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕后不需要销毁线程而是放回到池中,从而
减少创建和销毁线程对象的开销。
37. 创建线程池的4种方式。
java5中的Executor接口定义一个执行线程的工具。它的子类型即线程池接口是ExecutorService。要配置一个线程池是非常复杂的,因此工具类Executors里面提供了一些静态的工厂方法
来生成线程池:
1、newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作。如果这个唯一的线程因为异常结束,就会有一个新的线程来代替它
2、newFixedThreadPool:创建一个固定大小的线程池。
3、newCacheThreadPool:创建一个可缓存的线程池。
4、newScheduledThreadPool:创建一个大小不限的线程池
38. 线程同步的方法:sychronized、lock、reentrantLock等
1、sychrnized关键字主要有两种用法:sychrnized方法和sychrnized块。
sychrnized方法,在方法声明前加入了sychrnized关键字,把需要同步的资源放入到该方法中,就能保证这个方法在同一时刻只能被一个线程调用,从而实现了多线程访问的安全性
sychrnized块,既可以把任意的代码段声明为sychrnized,也可以指定上锁的对象,非常具有灵活性,如果一个对象既有同步方法又有同步块,那额当前中的一个同步方法或者同步块被
线程执行时,这个对象就被锁定了,其他线程无法在此时访问这个对象的同步方法和同步块
2、Lock:jdk5新增了Lock接口以及他的一个实现类ReentrantLock(重入锁)。Lock(),以阻塞的方式来获取锁,如果获取到锁,就立即返回,如果别的线程持有锁,则当前线程等待
直到获取到锁返回
3、ReentranLock
39. Runnable接口和Callable接口的区别。
1、Runnable的方法时run()方法,Callable的方法是call()
2、Callable的任务执行后可以返回值,Runnable的任务是不能返回值
3、call方法可以抛出异常,但是run方法不能抛出异常
40. wait方法和sleep方法的区别。
sleep是线程类Thread的方法,导致此线程暂停执行时间,把执行机会给其他的线程,但是监控状态依然保持,到时会自动恢复,调用sleep不会释放对象锁
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待锁定池,只有针对此对象发出notify方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
41. 锁的等级:方法锁、对象锁、类锁。
42. 分布式环境下,怎么保证线程安全。
1、时间戳:分布式环境下是无法保证时序的,无论是通过远程接口同步调用或者一部消息,很容易造成某些对时序性有要求的业务在高并发时产生错误。对于这问问题,常用的方法是
采用时间戳的方式。系统A给系统B发送变更时需要带上一个时间戳,B通过与已经存在的时间戳进行变更,这样的方式比较简单,关键在于调用的一方要有保证时间戳的时序有效性
2、串行化:有时候可以牺牲性能和扩张性来使用串行化,满足对数据一致性的需求。
3、数据库:分布式的环境中共享资源不能 通过Java里同步方法或者加锁来保证线程安全,但是数据库是分布式各服务器的共享点,可以通过数据库的高可靠一致性来满足需求
4、行锁:
5、统一触发途径:当一个数据可能被多个触发点或多个业务涉及到,就有并发问题产生的隐患,因此 可以通过前期架构和业务世界尽量统一触发途径,触发途径少一是减少了并发的
可能性也有利于并发问题的分析和判断
43. 介绍下CAS(无锁技术)。
CAS(compare and swap),即比较并替换,实现并发算法时常用到的一种技术,CAS是通过unsafe类的compareAndSwap方法实现的
CAS的思想:三个参数,一个当前内存值V,旧的预期值A,即将更新的值B,当且仅当预期值和内存值相同时将内存值修改为即将更新的值并返回,否则什么都不做,返回false。
缺点:即就是ABA问题,也就是如果变量A初次读取的是A,并且在准备赋值的时候检查到它还是A,那能证明它没有被修改过吗?很显然是不能的,如果这段时间它被修改为B然后又被
修改为A,那么CAS就会认为它没有被修改过,针对这种情况,java并发包提供了一个带有标记的原子引用类,AtomicStampedReference,它可以通过看着呢会变量值的版本来
保证CAS的正确性。
44. 反射的作用于原理。
简单的说,反射机制其实就是指程序在运行的时候可以获取自身的信息,。如果知道一个 类的名称或者它的一个实例对象,就能把这个类的所有方法和变量的信息找出来,如果明确知道
这个类里的某个方法名和参数个数及类型,还能通过传递参数来运行那个类的方法,这就是反射。在java中,class类与java.lang.reflect类库一起对反射的概念提供了支持,该类库包含了
了Field、Method以及Construcctor类。
43. 泛型常用特点,List
泛型实现了参数化类型的概念,使得我们的代码可以在更多的场景使用。泛型的好处在于在编译时进行类型的安全检查,并且在运行的时候所有的转换都是强制的,隐式的,大大的提高
了代码的重用率。
先来回答List
的list在类型上不等价于Object的list。
44. Java1.5、1.7与1.8新特性。
JDK1.5:
JDK1.7:
JDK1.8:
45. JNI的使用
JNI即Java Native Interface的缩写,中文译为“Java本地调用”。通俗的说,JNI是一种实现Java层与Native层(C/C++)交互的技术。有时为了追求效率问题,
或者是使用用native代码编写的函数库,我们就不得不使用JNI接口。
设计模式:
46. 设计模式有哪些?
1、设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案,这些方案是众多的软件开发人员经过相当长的一段时间的实验和错误实践总结出来的
2、设计模式可以分为三大类:创建型模式、结构型模式、行为型模式
3、设计模式的6大原则:
开闭原则:对扩展开放,对修改关闭
里氏代换原则:
依赖倒转原则:
接口隔离原则
迪米特法则
合成复用原则:
47. 设计模式:单例、工厂、适配器、责任链、观察者等等。
1、单例模式
1、懒汉模式
public class SingletonDemo {
private static SingletonDemo instance;
private SingletonDemo(){}
public static SingletonDemo getInstance(){
if(instance==null){
instance=new SingletonDemo();
}
return instance;
}
}
2、懒汉模式(线程安全)
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3、饿汉模式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
4、双重校验锁
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
5、饿汉模式和懒汉模式的区别:
饿汉模式在类加载时就将自己实例化,有点在于无序考虑多线程访问的问题,从资源和利用效率来看,饿汉模式不及懒汉模式
懒汉模式在第一次使用时创建,无须一直占用资源,实现了延迟加载,需要处理好多个线程同时访问的问题,从资源和利用效率来看,实例化必然涉及资源初始化,而资源初
化很有可能耗费大量的时间,这就意味着多线程同时首次引用此类的纪律变得较大。需要通过双重检查锁定机制进行控制,这样的后果就是导致性能受到一定的影响。
2、工厂模式
工厂模式属于创建型模式,提供了一种创建对象的最佳方式。会定义一个创建对象的接口,让其子类决定实例化哪一个工厂类,,工厂模式使其创建过程延迟到子类进行
3、适配器模式
将一个类的接口转换成客户希望的另外的一个接口,适配器模式可以让那些接口不兼容的类可以一起工作。它包含3个角色:
1、Target(目标抽象类):目标抽象类定义客户所需要的接口,可以是抽象类、接口或者是具体类
2、Adapter(适配器类):它可以调用另外的一个接口,作为一个转换器,是适配器的核心
3、Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类包好了客户希望的业务方法
4、责任链模式
使多个对象都有机会处理请求,从而避免了请求者和接受者的耦合关系,将这个对象形成一条链,并沿着这条链传递该请求,知道有一个对象处理它为止。主要在三个框架中使用:
1、servlet中的filter
2、dubbo中的filter
3、mybatis中的plugin
5、观察者模式
观察者模式属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有的观察者对象,使他们可以自动的
更新自己
1、Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
2、ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
3、Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
4、ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
48. 写出生产者消费者模式。
生产者消费者模式,就是在一个系统中,存在生产者和消费者两种角色。他们通过内存缓冲区进行通信,生产者生产消费者所需要的资料,消费者把资料做成产品。
实现:生产者是一堆线程,消费者是另外的一堆线程,内存缓冲区可以使用List数组队列,数据类型只需要定义一个简单的类就好。在这个模型中,最关键的就是内存缓冲区为空的时候消费者必须等待,而内存
缓冲区满的时候生产者需要等待。值得注意的是多线程对临界资源操作的时候必须保证在读写的时候只能存在一个线程,这就需要设计锁的策略。
JVM
49. heap和stack区别
java中对象都是分配在heap(堆)中,从heap中分配内存所消耗的时间远远大于stack产生存储空间所需的时间
区别:
1、栈和堆都是java用来在Ram中存放数据的地方,java自动管理栈和堆,程序员不能直接设置栈和堆
2、栈的优势在于存取速度比堆快,仅次于直接位于cpu中的寄存器,但是缺点就是存在栈中的数据大小与生存期必须是确定的。堆的优势在于可以动态的分配内存的大小,java的垃圾收集器会自动回收这些
不能再使用的数据,但 缺点是运行时动态分配内存,存取速度较慢。
50. 描述一下JVM加载Class文件的原理和机制
1、JVM中类的加载是由ClassLoader和它的子类来实现的,Java ClassLoader是一个很重要的java运行时系统组件,他负责在运行时查找和装入类文件的类。java中的所有类,都需要装载到JVM中才能运行,
类加载器本省就是一个类,它的工作就是将class文件从硬盘读取到内存中。
2、类装载的方式有两种:
隐式转载:程序在运行过程中碰道通过new等方式生成对象时,隐式调用类加载器加载对应的类到jvm中
显示装载:通过class.forname()等方法,显示加载需要的类
51. 类加载的五个过程:加载、验证、准备、解析、初始化。
1、加载:加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lang.class对象,作为方法区这个类的各种数据的接口。
2、验证:这一阶段的主要目的是为了确保Class文件中的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全
3、准备:准备阶段是正式为类变量分配内存并设置类变量的初始阶段,即在方法区中分配这些变量所需要的内存空间
4、解析:解析阶段是虚拟机将常量池中的符号引用替换为直接引用的过程
5、初始化:初始化阶段是执行类构造器
方法已经执行完毕
52. JVM的分区:程序计数器、本地方法栈、方法区、栈和堆
GC
53. GC的基本原理
当程序员在创建对象时,GC就开始监控这个对象的地址、大小以及使用情况,GC采用有向图的方式记录和管理堆中的所有对象。通过这种方法来确定哪些对象是“可达的”,哪些是“不可达”的,当确定为“不可达”
时,GC就有责任回收这些内存空间。垃圾回收器可以马上回收内存,程序员可以手动指定system.gc()方法,通知GC进行回收,但是java语言规范并不保证GC一定会执行
54. GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?
1.标记清除算法:首先标记处所有需要回收的对象,在标记完成后统一进行回收。
缺点:标记的过程效率不高、标记清除之后产生大量不连续的内存碎片,当需要申请大块连续内存空间时,无法找到。
2.复制算法:将内存按容量费为大小相等的两块区域,每次只使用其中的一块,当一块内存用完了,就将还存活的对象复制到另一块内存上面,然后吧使用过的那块内存统一清理掉。
缺点:每次只能使用总内存容量的一半。在对象存活较多的情况下会进行大量复制操作,效率底下。
3.标记整理算法:和标记清除算法一样,先对死亡对象进行标记,然后将存活对象向一端移动,然后直接清理掉边界以外的内存。
55. GC收集器有哪些?CMS收集器与G1收集器的特点
1.Serial:一个单线程的收集器,在进行垃圾收集时候,必须暂停其他所有的工作线程直到它收集结束。
特点:CPU利用率最高,停顿时间即用户等待时间比较长。
2.Parallel:采用多线程来通过扫描并压缩
特点:停顿时间短,回收效率高,对吞吐量要求高。
3.CMS收集器:采用“标记-清除”算法实现,使用多线程的算法去扫描堆,对发现未使用的对象进行回收。
4:G1:堆被划分成 许多个连续的区域(region)。采用G1算法进行回收,吸收了CMS收集器特点。
特点:支持很大的堆,高吞吐量、支持多CPU和垃圾回收线程、在主线程暂停的情况下,使用并行收集、在主线程运行的情况下,使用并发收集
56. java中的内存泄漏
java中的内存泄漏广义通俗的说就是:不会再被使用的对象不能被回收。如果长生命周期的对象持有短生命周期的引用,就有可能会出现内存泄漏。
二、Java web部分
1. Cookie与Session的作用与原理
1、cookie是流浪器保存在用户电脑上的一小段文本,用来保存用户在网站上的必要信息。web页面或者服务器告诉浏览器按照一定的规范存储这些信息,并且在以后的所有请求中,这些信息就会自动加在http
请求头中发送给服务器,服务器根据这些信息判断不同的用户,并且cookie本身是安全的
2、session的作用和cookie差不多,但是session是存储在服务器端的,不会在网络中进行传输,所以比cookie更加安全一些。但是session是依赖cookie的,当用户访问某个站点的时候,服务器会为这个用户产生
唯一的session_id,并把这个session_id以cookie的形式,发送到客户端,以后的客户端请求都会自动携带则cookie。
2. 什么时候使用断言(assertion)?
assertion是软件开发中一种常用的调试方式,在现实中,assertion就是程序中的一条语句,他对一个boolean表达式进行检查,一个正确的程序必须保证这个Boolean表达式的值为true,如果返回false,则说明
程序已经处于不正确的状态下,系统会给出警告或者退出。一般来说,assertion用于保护程序最基本、关键的正确性。断言检查通常在开发和测试的过程中开始,在软件发布后是关闭的。
3. jsp的内置对象和作用
JSP有9个内置对象:
request:封装客户端的请求,其中包含来自GET或POST请求的参数;
response:封装服务器对客户端的响应;
pageContext:通过该对象可以获取其他对象;
session:封装用户会话的对象;
application:封装服务器运行环境的对象;
out:输出服务器响应的输出流对象;
config:Web应用的配置对象;
page:JSP页面本身(相当于Java程序中的this);
exception:封装页面抛出异常的对象。
4. jsp有哪些动作,作用是什么?
JSP 共有以下6种基本动作:
jsp:include:在页面被请求的时候引入一个文件。
jsp:useBean:寻找或者实例化一个JavaBean。
jsp:setProperty:设置JavaBean的属性。
jsp:getProperty:输出某个JavaBean的属性。
jsp:forward:把请求转到一个新的页面。
jsp:plugin:根据浏览器类型为Java插件生成OBJECT或EMBED标记。
5. Request对象的主要方法
setAttribute(String name,Object):设置名字为name的request的参数值
getAttribute(String name):返回由name指定的属性值
getAttributeNames():返回request对象所有属性的名字集合,结果是一个枚举的实例
getCookies():返回客户端的所有Cookie对象,结果是一个Cookie数组
getCharacterEncoding():返回请求中的字符编码方式
getContentLength():返回请求的Body的长度
getHeader(String name):获得HTTP协议定义的文件头信息
getHeaders(String name):返回指定名字的request Header的所有值,结果是一个枚举的实例
getHeaderNames():返回所以request Header的名字,结果是一个枚举的实例
getInputStream():返回请求的输入流,用于获得请求中的数据
getMethod():获得客户端向服务器端传送数据的方法
getParameter(String name):获得客户端传送给服务器端的有name指定的参数值
getParameterNames():获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的实例
getParameterValues(String name):获得有name指定的参数的所有值
getProtocol():获取客户端向服务器端传送数据所依据的协议名称
getQueryString():获得查询字符串
getRequestURI():获取发出请求字符串的客户端地址
getRemoteAddr():获取客户端的IP地址
getRemoteHost():获取客户端的名字
getSession([Boolean create]):返回和请求相关Session
getServerName():获取服务器的名字
getServletPath():获取客户端所请求的脚本文件的路径
getServerPort():获取服务器的端口号
removeAttribute(String name):删除请求中的一个属性
6. 对于监听器的理解
Java Web开发中的监听器(listener)就是application、session、request三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件,如下所示:
①ServletContextListener:对Servlet上下文的创建和销毁进行监听。
②ServletContextAttributeListener:监听Servlet上下文属性的添加、删除和替换。
③HttpSessionListener:对Session的创建和销毁进行监听。
session的销毁有两种情况:1). session超时(可以在web.xml中通过
④HttpSessionAttributeListener:对Session对象中属性的添加、删除和替换进行监听。
⑤ServletRequestListener:对请求对象的初始化和销毁进行监听。
⑥ServletRequestAttributeListener:对请求对象属性的添加、删除和替换进行监听。
7.过滤器的作用以及用法
1、对Web应用来说,过滤器是一个驻留在服务器端的Web组件,它可以截取客户端和服务器之间的请求与响应信息,并对这些信息进行过滤。当Web容器接受到一个对资源的请求时,它将判断是否有过滤器与这个
资源相关联。如果有,那么容器将把请求交给过滤器进行处理。在过滤器中,你可以改变请求的内容,或者重新设置请求的报头信息,然后再将请求发送给目标资源。当目标资源对请求作出响应时候,容器同
样会将响应先转发给过滤器,在过滤器中你可以对响应的内容进行转换,然后再将响应发送到客户端。
2、常见的过滤器用途主要包括:对用户请求进行统一认证、对用户的访问请求进行记录和审核、对用户发送的数据进行过滤或替换、转换图象格式、对响应内容进行压缩以减少传输量、对请求或响应进行加解密
处理、触发资源访问事件、对XML的输出应用XSLT等。
3、和过滤器相关的接口主要有:Filter、FilterConfig和FilterChain。
8. Servlet如何获取用户提交的查询参数以及表单数据
可以通过请求对象(HttpServletRequest)的getParameter()方法通过参数名获得参数值。如果有包含多个值的参数(例如复选框),可以通过请求对象的getParameterValues()方法获得。当然也可以通过请求
对象的getParameterMap()获得一个参数名和参数值的映射(Map)。
9. Servlet的生命周期是什么?是否是单例?
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
Servlet 通过调用 init () 方法进行初始化。
Servlet 调用 service() 方法来处理客户端的请求。
Servlet 通过调用 destroy() 方法终止(结束)。
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
Servlet单实例,减少了产生servlet的开销
10. MVC各个部分都有哪些技术来实现
MVC 是Model-View-Controller的简写。”Model” 代表的是应用的业务逻辑(通过JavaBean,EJB组件实现), “View” 是应用的表示面,用于与用户的交互(由JSP页面产生),”Controller” 是提供应用的处
理过程控制(一般是一个Servlet),通过这种设计模型把应用逻辑,处理过程和显示逻辑分成不同的组件实现。这些组件可以进行交互和重用。model层实现系统中的业务逻辑,view层用于与用户的交互,
controller层是model与view之间沟通的桥梁,可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作。
三、数据库部分
1、sql语句的书写、执行顺序
书写顺序:
select--from--where--group by--having--order by
其中select和from是必须的,其他关键词是可选的
执行顺序
from--where--group by--having--select--order by,
from:需要从哪个数据表检索数据
where:过滤表中数据的条件
group by:如何将上面过滤出的数据分组
having:对上面已经分组的数据进行过滤的条件
select:查看结果集中的哪个列,或列的计算结果
order by :按照什么样的顺序来查看返回的数据
2、数据库事务的四个特性及含义
原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;
一致性(Consistent):事务结束后系统状态是一致的;
隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;
持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据。
3、数据库优化
1、选取最实用的字段属性:字段的大小设计较为严谨的话,一方面可以减小资源空间的浪费,另一方面可以加快查询的速度
2、使用连接代替子查询
3、临时表的使用
临时表的使用有好有坏,但对于大量的数据操作来说,还是利大于弊的。
好处:减少阻塞,提高并发性
弊端:频繁建立和删除临时表,浪费系统的资源
4、使用事物。保持事物的一致性和完整性是较为重要的
4. sql语句的优化
1、避免全表查询,考虑建立索引
查询的过程中查询所需要的关键字段,全表查询会浪费大量的时间
合理的建立索引会大大的提高sql的效率,但索引并不是越多越好,数据的插入和删除会重新建立索引和修改索引,会消耗大量的时间。
2、避免在where子句中进行如下的操作,这都将导致引擎放弃使用索引而进行全表扫描
进行null值判断(最好不要给数据库留null)、
使用!=或<>操作符、
使用模糊查询like、
对字段进行表达式操作或函数操作
3、尽量避免在where子句中使用or来连接查询条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描;可以使用union all来代替or;
4、慎用in和not in,这也会导致全表扫描;对于连续的数值,可以用between代替in;
5、很多时候可以用exists代替in;
6、存储过程
四、手写代码
1. 常用的排序算法
2. 二分查找
2. 递归读取文件夹中的文件
3. 给定txt文件,如何得到某字符串出现的次数
4. 写出单例模式和工厂模式
5. 用 wait-notify 写一段代码来解决生产者-消费者问题?
6. 用 1,2 , 2 ,3, 4 ,5 这 6个数字, 用 Java 写一个 main 函数, 打印出所有不同的排列
7. 一个数如果恰好等于它的因子之和, 这个数就称为” ” 完数” ”. 例如 6 = 1+2+3 。 编程找出0 1000 以内的所有完数
五、J2SE部分
Hibernate和Mybatis的区别。
Spring MVC和Struts2的区别。
Spring用了哪些设计模式。
Spring中AOP主要用来做什么。
Spring注入bean的方式。
什么是IOC,什么是依赖注入。
Spring是单例还是多例,怎么修改。
Spring事务隔离级别和传播性。
介绍下Mybatis/Hibernate的缓存机制。
Mybatis的mapper文件中#和$的区别。
Mybatis的mapper文件中resultType和resultMap的区别。
Mybatis中DAO层接口没有写实现类,Mapper中的方法和DAO接口方法是怎么绑定到一起的,其内部是怎么实现的。
(注:手写代码部分和J2SE部分没有给出详细的解答,答案都可以在其他的网络资源上找到,核心重点在于前面的基础部分。)