Java面试题目集锦
1.equals方法用于比较对象的内容是否相等(覆盖以后)
2.hashcode方法只有在集合中用到
3.当覆盖了equals方法时,比较对象是否相等将通过覆盖后的equals方法进行比较(判断对象的内容是否相等)。
4.将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意一个元素的hashcode值是否相等,如果不相等直接将该对象放入集合中。如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals判断不相等,直接将该元素放入到集合中,否则不放入。
5.没有覆盖equals方法 采用对象内存地址是否相等来判断对象是否相等。
因为是两个新对象所以对象的内存地址不相等,所以stu1.equals(stu2) 是false。
6.线程a和b都要获取对象o的锁定,假设a获取了对象o锁,b将等待a释放对o的锁定,如果使用 synchronized ,如果a不释放,b将一直等下去,不能被中断如果使用reentrantlock,如果a不释放,可以使b在等待了足够长的时间以后,中断等待,而干别的事情
reentrantlock获取锁定与三种方式:
a) lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
b) trylock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
c)trylock(long timeout,timeunit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,
在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
d) lockinterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,
或者当前线程被别的线程中断
synchronized是在jvm层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,
jvm会自动释放锁定,但是使用lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unlock()放到finally{}中
在资源竞争不是很激烈的情况下,synchronized的性能要优于reetrantlock,但是在资源竞争很激烈的情况下,synchronized的性能会下降几十倍,但是reetrantlock的性能能维持常态;
在 jdk 中,主要由以下类来实现 java 反射机制,这些类都位于 java.lang.reflect 包中:
class 类:代表一个类。
field 类:代表类的成员变量(成员变量也称为类的属性)。
method 类:代表类的方法。
constructor 类:代表类的构造方法。
array 类:提供了动态创建数组,以及访问数组的元素的静态方法。
下面给出几个例子看看 reflection api 的实际运用:
一、通过 class 类获取成员变量、成员方法、接口、超类、构造方法等
在 java.lang.object 类中定义了 getclass() 方法,因此对于任意一个 java 对象,都可以通过此方法获得对象的类型。 class 类是 reflection api 中的核心类,它有以下方法
getname() :获得类的完整名字。
getfields() :获得类的 public 类型的属性。
getdeclaredfields() :获得类的所有属性。
getmethods() :获得类的 public 类型的方法。
getdeclaredmethods() :获得类的所有方法。
getmethod(string name, class[] parametertypes) :获得类的特定方法, name 参数指定方法的名字, parametertypes 参数指定方法的参数类型。
getconstructors() :获得类的 public 类型的构造方法。
getconstructor(class[] parametertypes) :获得类的特定构造方法, parametertypes 参数指定构造方法的参数类型。
newinstance() :通过类的不带参数的构造方法创建这个类的一个对象。
编写java反射程序的步骤:
1)必须首先获取一个类的class对象
例如:
class c1 = test.class; class c2 = class.forname(“com.reflection.test”); class c3 = new test().getclass();
2)然后分别调用class对象中的方法来获取一个类的属性/方法/构造方法的结构
注意:如果要能够正常的获取类中方法/属性/构造方法应该重点掌握如下的反射类
field
constructor
method
<servlet-mapping> <servlet-name></servlet-name> <url-pattern></url-pattern> </servlet-mapping> for (string elementa:str ) { system.out.print(elementa + " "); } list<string> list = new arraylist<string>(); for (int i=0; i<str.length; i++) { if(!list.contains(str[i])) { list.add(str[i]); } } set<string> set = new hashset<string>(); for (int i=0; i<str.length; i++) { set.add(str[i]); }
spring有六种事务五种隔离级别
第一类:整型 byte short int long
第二类:浮点型 float double
第三类:逻辑型 boolean(它只有两个值可取true false)
第四类:字符型 char
final修饰类中的方法
作用:可以被继承,但继承后不能被重写。
final修饰类
作用:类不可以被继承。
final修饰基本类型时候值不变,引用类型表示地址不变,就是new的时候那个是地址不能重新赋值
final修饰属性你懂的
preparestatement是预编译的,先把这个sql提交到数据库中进行预处理,然后将其放到缓存里面,下次发现有相同的就不用编译了,执行效率高,有语法提示方便检查,参数是动态的,防止sql注入因为语法检查
select * from tbname = ‘zck' and passwd = ” or ‘1' = ‘1';
statement就不是预编译,而且需要手动检查语法错误,属于硬编码
hashmap允许将null作为一个entry的key或者value,而hashtable不允许
put方法
hashmap会对null值key进行特殊处理,总是放到table[0]位置put过程是先计算hash然后通过hash与table.length取摸计算index值,然后将key放到table[index]位置,当table[index]已存在其它元素时,会在table[index]位置形成一个链表,将新添加的元素放在table[index],原来的元素通过entry的next进行链接,这样以链表形式解决hash冲突问题,当元素数量达到临界值(capactiy*factor)时,则进行扩容,是table数组长度变为table.length*2
get方法
同样当key为null时会进行特殊处理,在table[0]的链表上查找key为null的元素
get的过程是先计算hash然后通过hash与table.length取摸计算index值,然后遍历table[index]上的链表,直到找到key,然后返回hashmap和hashtable的底层实现都是数组+链表结构实现的添加、删除、获取元素时都是先计算hash,根据hash和table.length计算index也就是table数组的下标,然后进行相应操作
索引大多数基于b树
servlet线程安全问题主要是由实例变量造成的,因此在servlet中应避免使用实例变量。
如果应用程序设计无法避免使用实例变量,那么使用同步来保护要使用的实例变量,但为保证系统的最佳性能,应该同步可用性最小的代码路径。
写一个单例模式
public static long recursive(int n) { if (n <= 0) return 0; if (n == 1) return 1; return recursive(n - 1) + recursive(n - 2); } public static long loop(int n) { if (n <= 0) return 0; if (n == 1) return 1; long fib1 = 0; long fib2 = 1; long sum = 0; for (int i = 2; i <= n; i++) { sum = fib1 + fib2; fib1 = fib2; fib2 = sum; } return sum; }
hashtable是一个线程安全的类,它使用synchronized来锁住整张hash表来实现线程安全,即每次锁住整张表让线程独占。concurrenthashmap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。
concurrenthashmap内部使用段(segment)来表示这些不同的部分,每个段其实就是一个小的hashtable,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
有些方法需要跨段,比如size()和containsvalue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在concurrenthashmap内部,段数组是final的,并且其成员变量实际上也是final的,但是,仅仅是将数组声明为final的并不保证数组成员也是final的,这需要实现上的保证。
这可以确保不会出现死锁,因为获得锁的顺序是固定的
① threadlocal ② synchronized( ) ③ wait() 与 notify() ④ volatile
threadlocal
threadlocal 保证不同线程拥有不同实例,相同线程一定拥有相同的实例,即为每一个使用该变量的线程提供一个该变量值的副本,每一个线程都可以独立改变自己的副本,而不是与其它线程的副本冲突。
优势:提供了线程安全的共享对象
与其它同步机制的区别:同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信;
而 threadlocal 是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源,这样当然不需要多个线程进行同步了。
volatile
volatile 修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,
当成员变量发生变化时,强迫线程将变化值回写到共享内存。
优势:这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
缘由:java 语言规范中指出,为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,
而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。
这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。
而 volatile 关键字就是提示 vm :对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
使用技巧:在两个或者更多的线程访问的成员变量上使用 volatile 。
当要访问的变量已在 synchronized 代码块中,或者为常量时,不必使用。
线程为了提高效率,将某成员变量(如a)拷贝了一份(如b),线程中对a的访问其实访问的是b。只在某些动作时才进行a和b的同步,因此存在a和b不一致的情况。volatile就是用来避免这种情况的。
volatile告诉jvm,它所修饰的变量不保留拷贝,直接访问主内存中的(读操作多时使用较好;线程间需要通信,本条做不到)
volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。
这就是说线程能够自动发现 volatile 变量的最新值。volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束。
您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
对变量的写操作不依赖于当前值;该变量没有包含在具有其他变量的不变式中。
sleep() vs wait()
sleep是线程类(thread)的方法,导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyall)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 (如果变量被声明为volatile,在每次访问时都会和主存一致;如果变量在同步方法或者同步块中被访问,当在方法或者块的入口处获得锁以及方法或者块退出时释放锁时变量被同步。)
http://www.yjbys.com/news/202750.html
客户程序要先得到具体容器角色,然后再通过具体容器角色得到具体迭代器角色
iterator it=new arraylist.iterator();
1) 访问一个容器对象的内容而无需暴露它的内部表示。
2) 支持对容器对象的多种遍历。
3) 为遍历不同的容器结构提供一个统一的接口(多态迭代)。
使用new关键字 } → 调用了构造函数
使用class类的newinstance方法 } → 调用了构造函数
使用constructor类的newinstance方法 } → 调用了构造函数
使用clone方法 } → 没有调用构造函数
使用反序列化 } → 没有调用构造函数
employee emp2 = (employee) class.forname(“com.employee”).newinstance();
或者
employee emp2 = employee.class.newinstance(); constructor constructor = employee.class.getconstructor(); employee emp3 = constructor.newinstance();
使用clone方法,我们需要先实现cloneable接口并实现其定义的clone方法
employee emp4 = (employee) emp3.clone();
程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过java的类加载机制(classloader)来动态加载某个class文件到内存当中的,从而只有class文件被载入到了内存之后,才能被其它class所引用。所以classloader就是用来动态加载class文件到内存当中用的。
bootstrap classloader:称为启动类加载器,是java类加载层次中最顶层的类加载器,负责加载jdk中的核心类库,如:rt.jar、resources.jar、charsets.jar等extension classloader:称为扩展类加载器,负责加载java的扩展类库, 默认加载java_home/jre/lib/ext/目下的所有jar。
app classloader:称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。
因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子classloader再加载一次。
考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的string来动态替代java核心api中定义的类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为string已经在启动时就被引导类加载器(bootstrcp classloader)加载,所以用户自定义的classloader永远也无法加载一个自己写的string,除非你改变jdk中classloader搜索类的默认算法。
1、request对象 客户端请求,此请求会包含来自get/post请求的参数通过它才能了 解到客户的需求,然后做出响应。
2、response对象 响应客户请求的有关信息
3、session对象 它指的是客户端与服务器的一次会话,从客户端连到服务器的一个 webapplication开始,直到客户端与服务 器断开连接为止。
4、out对象 它是jspwriter类的实例,是向客户端输出内容常用的对象
5、page对象 它是指向当前jsp页面本身,有点象类中的this指针,它是 java.lang.object类的实例
6、application对象 它实现了用户间数据的共享,可存放全局变量。它开始于服务器的启动,直到服务器的关闭
7、exception对象 它是一个例外对象,当一个页面在运行过程中发生了例外,就产生这个对象。
8、pagecontext对象 它提供了对jsp页面内所有的对象及名字空间的访问
9、config对象 它是在一个servlet初始化时,jsp引擎向它传递信息用的
js有个函数 isnan(val)//如果是数字则返回 false
有xmldom解析、sax解析、stax解析
xmldom:(xmldocumentobjectmodel)处理大型文件时其性能下降的非常厉害。这个问题是由dom的树结构所造成的,这种结构占用的内存较多,而且dom必须在解析文件之前把整个文档装入内存,适合对xml的随机访问;
sax:(simpleapiforxml)不同于dom,sax是事件驱动型的xml解析方式。它顺序读取xml文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理xml文件,适合对xml的顺序访问;
stax:(streamingapiforxml)与其他方法的区别就在于应用程序能够把xml作为一个事件流来处理,无论从性能还是可用性上都优于其他方法;
thread.getstate()
以上是小编给大家整理的有关java面试题,希望对大家有所帮助
上一篇: Struts2 Result 参数详解