1、
byte a = 127;
byte b = 127;
b = a + b;
b += a;
第3、4行的b的结果分别是什么?
Type mismatch: cannot convert from int to byte
-2
2、
1 String str1 = "a";
2 String str2 = "b";
3 String str3 = "ab";
4 String str4 = str1 + str2;
5 String str5 = new String("ab");
6
7 System.out.println(str5.equals(str3));
8 System.out.println(str5 == str3);
9 System.out.println(str5.intern() == str3);
10 System.out.println(str5.intern() == str4);
7-10行的结果分别是什么?
true
false
true
false
字符串常量池
见:https://segmentfault.com/a/1190000009888357
3、可以直接根据hashcode值判断两个对象是否相等吗?
肯定是不可以的,因为不同的对象可能会生成相同的hashcode值。虽然不能根据hashcode值判断两个对象是否相等,但是可以直接根据hashcode值判断两个对象不等,如果两个对象的
hashcode值不等,则必定是两个不同的对象。如果要判断两个对象是否真正相等,必须通过equals方法。
如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;
如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;
如果两个对象的hashcode值不等,则equals方法得到的结果必定为false;
如果两个对象的hashcode值相等,则equals方法得到的结果未知。
见:https://www.cnblogs.com/dolphin0520/p/3681042.html
4、final,finalize和finally的不同之处
final 是一个修饰符,可以修饰变量、方法和类。如果 final 修饰变量,意味着该变量的值在初始化后不能被改变。
finalize相当于析构函数,他是垃圾回收器回收一个对象的时候第一个要调用的方法。不过由于Java的垃圾回收机制能自动为我们做这些事情,所以我们在一般情况下是不需要自己来手工释
放的。
finally 是一个关键字,与 try 和 catch 一起用于异常的处理。finally 块一定会被执行,无论在 try 块中是否有发生异常。
5、引用拷贝、对象拷贝、深拷贝和浅拷贝的区别是什么?
引用拷贝:创建一个指向对象的引用变量的拷贝。即值相等、地址相等;
比如Teacher teacher = new Teacher("Taylor",26);
Teacher otherteacher = teacher;
对象拷贝:创建对象本身的一个副本,值相等,但地址不等,
比如使用clone方法:Teacher otherteacher = (Teacher)teacher.clone();
注意:深拷贝和浅拷贝都是对象拷贝。
浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深拷贝把要复制的对象所
引用的对象都复制了一遍。
见:https://blog.csdn.net/baiye_xing/article/details/71788741
6、static都有哪些用法?
静态变量、静态方法、静态块、静态内部类。
7、java中short int char long各占多少字节?
类型 字节数 位数
short 2 16
int 4 32
long 8 64
float 4 32
double 8 64
char 2 16
8、int和Integer的区别
Integer是int的包装类型,在拆箱和装箱中,二者自动转换.int是基本类型,直接存数值,而integer是对象,用一个引用指向这个对象.
9、StringBuffer和StringBuilder的区别
StringBuffer是线程安全的可变字符串,其内部实现是可变数组.StringBuilder是jdk 1.5新增的,其功能和StringBuffer类似,但是非线程安全.因此,在没有多线程问题的前提下,使用
StringBuilder会取得更好的性能.
https://segmentfault.com/a/1190000009956880
10、HashMap和Hashtable的区别
1 HashMap不是线程安全的
hastmap是一个接口 是map接口的子接口,是将键映射到值的对象,其中键和值都是对象,并且不能包含重复键,但可以包含重复值。HashMap允许null key和null value,
而hashtable不允许。
2 HashTable是线程安全的一个Collection。
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。
HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。
HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。
Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。
11、sleep() 和 wait() 有什么区别?
sleep()方法是使线程停止一段时间的方法。在sleep 时间间隔期满后,线程不一定立即恢复执行。这是因为在那个时刻,其它线程可能正在运行而且没有被调度为放弃执行,
除非
(a)“醒来”的线程具有更高的优先级 。
(b)正在运行的线程因为其它原因而阻塞。
wait()是线程交互时,如果线程对一个同步对象x 发出一个wait()调用,该线程会暂停执行,被调对象进入等待状态,直到被唤醒或等待时间到。
12、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢?
需要重写 equals 方法 和 hashCode方法
见:https://www.oschina.net/code/snippet_175869_6121
13、WeakHashMap与HashMap的区别是什么?
WeakHashMap 的工作与正常的 HashMap 类似,但是使用弱引用作为 key,意思就是当 key 对象没有任何引用时,key/value 将会被回收。
14、ArrayList和LinkedList的区别?
最明显的区别是 ArrrayList底层的数据结构是数组,支持随机访问,而 LinkedList 的底层数据结构是双向循环链表,不支持随机访问。使用下标访问一个元素,ArrayList 的时间复杂度是
O(1),而 LinkedList 是 O(n)。
15、Comparator和Comparable的区别?
Comparable 接口用于定义对象的自然顺序,而 comparator 通常用于定义用户定制的顺序。Comparable 总是只有一个,但是可以有多个 comparator 来定义对象的顺序。
见:http://www.cnblogs.com/sunflower627/p/3158042.html
16、遍历ArrayList时如何正确移除一个元素?
非线程安全的ArrayList使用iterator遍历,线程安全的使用for 然后remove
https://blog.csdn.net/superxlcr/article/details/51534428
17、throw和throws的区别
throw用于主动抛出java.lang.Throwable 类的一个实例化对象,意思是说你可以通过关键字 throw 抛出一个 Error 或者 一个Exception,如:throw new IllegalArgumentException
(“size must be multiple of 2″),
而throws 的作用是作为方法声明和签名的一部分,方法被抛出相应的异常以便调用者能处理。Java 中,任何未处理的受检查异常强制在 throws 子句中声明。
18、Serializable 与 Externalizable 的区别
Serializable 接口是一个序列化 Java 类的接口,以便于它们可以在网络上传输或者可以将它们的状态保存在磁盘上,是 JVM 内嵌的默认序列化方式,成本高、脆弱而且不安全。
Externalizable 实例类的唯一特性是可以被写入序列化流中,该类负责保存和恢复实例内容。若某个要完全控制某一对象及其超类型的流格式和内容,则它要实现 Externalizable 接口的
writeExternal 和 readExternal 方法。这些方法必须显式与超类型进行协调以保存其状态。这些方法将代替定制的 writeObject 和 readObject 方法实现。
19、堆和栈的区别
VM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局部变量,而对象总是在堆上分配。栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程
共享。
基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b =
255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,
指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出 后,字段值就消失了),出于追求速度的原因,就存在于栈中。
堆(heap)。一种通用性的内存池(也存在于RAM中),堆不同于堆栈的好处是:编译器不需要知道要从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分
配存储有很大的灵活性。当你需要创建一个对象的时候,只需要new写一行简单的代码,当执行 这行代码时,会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用堆
进行存储分配比用堆栈进行存储存储需要更多的时间。
见:https://www.cnblogs.com/iliuyuet/p/5603618.html
20、XML解析的几种方式和特点
DOM,SAX,PULL三种解析方式:
DOM:消耗内存:先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据。这个写起来很简单,但是很消耗内存。要是数据过大,手机不够牛逼,可能手机直接死机
SAX:解析效率高,占用内存少,基于事件驱动的:更加简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通
知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。
PULL:与 SAX 类似,也是基于事件驱动,我们可以调用它的next()方法,来获取下一个解析事件(就是开始文档,结束文档,开始标签,结束标签),当处于某个元素时可以调用
XmlPullParser的getAttributte()方法来获取属性的值,也可调用它的nextText()获取本节点的值。
SAX
sax是一个用于处理xml事件驱动的“推”模型;
优点:解析速度快,占用内存少,它需要哪些数据再加载和解析哪些内容。
缺点:它不会记录标签的关系,而是需要应用程序自己处理,这样就会增加程序的负担。
DOM
dom是一种文档对象模型;
优点:dom可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构,dom技术使得用户页面可以动态的变化,如动态显示隐藏一个元素,改变它的属性,增加一个元素等,dom可
以使页面的交互性大大增强。
缺点:dom解析xml文件时会将xml文件的所有内容以文档树方式存放在内存中。
PULL
pull和sax很相似,区别在于:pull读取xml文件后触发相应的事件调用方法返回的是数字,且pull可以在程序中控制,想解析到哪里就可以停止解析。 (SAX解析器的工作方式是自动将事件
推入事件处理器进行处理,因此你不能控制事件的处理主动结束;而Pull解析器的工作方式为允许你的应用程序代码主动从解析器中获取事件,正因为是主动获取事件,因此可以在满足了需
要的条件后不再获取事件,结束解析。pull是一个while循环,随时可以跳出,而sax不是,sax是只要解析了,就必须解析完成。)
21、Servlet执行流程
客户端发出http请求,web服务器将请求转发到servlet容器,servlet容器解析url并根据web.xml找到相对应的servlet,并将request、response对象传递给找到的servlet,servlet根据request就可以知道是谁发出的请求,请求信息及其他信息,当servlet处理完业务逻辑后会将信息放入到response并响应到客户端。
22、SpringMVC的执行流程
springMVC是由dispatchservlet为核心的分层控制框架。首先客户端发出一个请求web服务器解析请求url并去匹配dispatchservlet的映射url,如果匹配上就将这个请求放入到dispatchservlet,dispatchservlet根据mapping映射配置去寻找相对应的handel,然后把处理权交给找到的handel,handel封装了处理业务逻辑的代码,当handel处理完后会返回一个逻辑视图modelandview给dispatchservlet,此时的modelandview是一个逻辑视图不是一个正式视图,所以dispatchservlet会通过viewresource视图资源去解析modelandview,然后将解析后的参数放到view中返回到客户端并展现。
23、父类与子类之间的调用顺序(打印结果)
a) 父类静态代码块
b) 子类静态代码块
c) 父类构造方法
d) 子类构造方法
e) 子类普通方法
f) 重写父类的方法,则打印重写后的方法
24、WeakReference与SoftReference的区别?
WeakReference ,一旦失去最后一个强引用,就会被 GC 回收,而软引用虽然不能阻止被回收,但是可以延迟到 JVM 内存不足的时候。
25、Java集合类框架的基本接口有哪些?Java中的集合Queue、LinkedList的区别是什么?
https://www.cnblogs.com/nayitian/p/3266090.html
https://www.cnblogs.com/be-forward-to-help-others/p/6825738.html
26、请画一张Java集合类框架图
27、Java类加载的过程概述
https://www.cnblogs.com/xiaoxian1369/p/5498817.html
28、如何)从数组创建ArrayList
我有一个数组,初始化如下:
1
Element[] array = {new Element(1), new Element(2), new Element(3)};
我希望将这个数组转化成一个ArrayList类的对象。
解决方案
1
new ArrayList<Element>(Arrays.asList(array))
29、遍历HashMap的最佳方法
遍历HashMap中元素的最佳方法是什么?
解决方案
这样遍历entrySet:
public static void printMap(Map mp) {
Iterator it = mp.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
System.out.println(pair.getKey() + " = " + pair.getValue());
it.remove(); // avoids a ConcurrentModificationException
}
}
30、使用Java在一个区间内产生随机整数数
如下:
import java.util.Random;
public static int randInt(int min, int max) {
Random rand;
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
31、访问修饰符public,private,protected,以及不写(默认)时的区别?
答:区别如下:
作用域 当前类 同包 子类 其他
public √ √ √ √
protected √ √ √ ×
default √ √ × ×
private √ × × ×
类的成员不写访问修饰时默认为default。默认对于同一个包中的其他类相当于公开(public),对于不是同一个包中的其他类相当于私有(private)。受保护(protected)对子类相当于公
开,对不是同一包中的没有父子关系的类相当于私有。
32、面向对象的特征有哪些方面?
答:面向对象的特征主要有以下几个方面:
1)抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
2)继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续
性,同时继承也是封装程序中可变因素的重要手段(如果不能理解请阅读阎宏博士的《Java与模式》或《设计模式精解》中关于桥梁模式的部分)。
3)封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的
方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口(可以想想普通洗衣机和全自动
洗衣机的差别,明显全自动洗衣机封装更好因此操作起来更简单;我们现在使用的智能手机也是封装得足够好的,因为几个按键就搞定了所有的事情)。
4)多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态
性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对A系统来说都是透明的(就像
电动剃须刀是A系统,它的供电系统是B系统,B系统可以使用电池供电或者用交流电,甚至还有可能是太阳能,A系统只会通过B类对象调用供电的方法,但并不知道供电系统的底层实现是什么
,究竟通过何种方式获得了动力)。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态
是面向对象最精髓的东西,要实现多态需要做两件事:1. 方法重写(子类继承父类并重写父类中已有的或抽象的方法);2. 对象造型(用父类型引用引用子类型对象,这样同样的引用调用
同样的方法就会根据子类对象的不同而表现出不同的行为)。
33、String 是最基本的数据类型吗?
答:不是。Java中的基本数据类型只有8个:byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type)和枚举类型(enumeration type),剩下的都是引
用类型(reference type)。
34、int 和Integer 有什么区别?
答:Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入不是对象的基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型(wrapper class),int的包装类就是Integer,从JDK 1.5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。
Java 为每个原始类型提供了包装类型:
原始类型: boolean,char,byte,short,int,long,float,double
包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double
package com.lovo;
// 何问起 hovertree.com
public class AutoUnboxingTest {
public static void main(String[] args) {
Integer a = new Integer(3);
Integer b = 3; // 将3自动装箱成Integer类型
int c = 3;
System.out.println(a == b); // false 两个引用没有引用同一对象
System.out.println(a == c); // true a自动拆箱成int类型再和c比较
}
}
35、&和&&的区别?
答:&运算符有两种用法:(1)按位与;(2)逻辑与。&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是true。&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是null而且不是空字符串,应当写为:username != null &&!username.equals(“”),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生NullPointerException异常。注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。
36、Java中的堆内存、栈内存、静态存储区
一、栈
栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈数据可以共享。
那些数据存放在栈中?
基本数据类型(int, short, long, byte, float, double, boolean, char)的变量存放于栈中。
对象的引用存放于栈中。
栈数据共享具体指什么意思?(方法区中的常量池)
int a = 3; int b = 3;
编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。即共享了3这个栈数据。
另外,比较特殊的是String,虽然String类型不是简单的基本数据类型,但是当用String a="abc"这样的语法定义String变量的时候,会把数据存储在栈中,因此也会有上面所说的数据共享特性。
java的八种基本类型(Byte Short、Integer、Long、Character、Boolean、Float、Double),除Float及Double意外,其它六种都实现了常量池,但是他们只在大于等于-128且小于等于127时才能使用常量池,如果不在此范围内,则会new一个出来,保存在堆内存中。
二、堆
堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器。堆数据在没有引用变量指向它的时候,才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
那些数据存放在堆中?
堆内存用于存放由new创建的对象和数组,即堆主要是用来存储对象的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。
三、方法区中的静态存储区
存储static声明的静态变量
37、用最有效率的方法计算2乘以8?
答: 2 << 3(左移3位相当于乘以2的3次方,右移3位相当于除以2的3次方)。
38、如何实现对象克隆?
有两种方式:
1.实现Cloneable接口并重写Object类中的clone()方法;
2.实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,代码如下。
package com.lovo;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class MyUtil {
private MyUtil() {
throw new AssertionError();
}
public static <T> T clone(T obj) throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bout);
oos.writeObject(obj);
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bin);
return (T) ois.readObject();
// 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义
// 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源
}
} //何问起 hovertree.com
下面是测试代码:
package com.lovo;
import java.io.Serializable;
class Person implements Serializable {
private static final long serialVersionUID = -9102017020286042305L;
private String name; // 姓名
private int age; // 年龄
private Car car; // 座驾
public Person(String name, int age, Car car) {
this.name = name;
this.age = age;
this.car = car;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
}
class Car implements Serializable {
private static final long serialVersionUID = -5713945027627603702L;
private String brand; // 品牌
private int maxSpeed; // 最高时速
public Car(String brand, int maxSpeed) {
this.brand = brand;
this.maxSpeed = maxSpeed;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]";
}
}
//何问起 hovertree.com
class CloneTest {
public static void main(String[] args) {
try {
Person p1 = new Person("Hao LUO", 33, new Car("Benz", 300));
Person p2 = MyUtil.clone(p1); // 深度克隆
p2.getCar().setBrand("BYD");
// 修改克隆的Person对象p2关联的汽车对象的品牌属性
// 原来的Person对象p1关联的汽车不会受到任何影响
// 因为在克隆Person对象时其关联的汽车对象也被克隆了
System.out.println(p1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。
39、Java 中的final关键字有哪些用法?
答: (1)修饰类:表示该类不能被继承;(2)修饰方法:表示方法不能被重写;(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
40、数据类型之间的转换:
1)如何将字符串转换为基本数据类型?
2)如何将基本数据类型转换为字符串?
答:
1)调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型;
2)一种方法是将基本数据类型与空字符串(””)连接(+)即可获得其所对应的字符串;另一种方法是调用String 类中的valueOf(…)方法返回相应字符串
41、如何实现字符串的反转及替换?
public static String reverse1(String originStr) {
if(originStr == null || originStr.length() <= 1)
return originStr;
return reverse(originStr.substring(1)) + originStr.charAt(0);
} /
或
String reverse = new StringBuffer(string).reverse().toString();
或
public static String reverse2(String s){
char []array=s.toCharArray();
String resever="";
for(int i=array.length-1;i>=0;i--){
resever+=array[i];
}
return resever;
}
42什么场景下使用list,set,map呢?
(或者会问为什么这里要用list、或者set、map,这里回答它们的优缺点就可以了)
答:
如果你经常会使用索引来对容器中的元素进行访问,那么 List 是你的正确的选择。如果你已经知道索引了的话,那么 List 的实现类比如 ArrayList 可以提供更快速的访问,如果经常添加删除元素的,那么肯定要选择LinkedList。
如果你想容器中的元素能够按照它们插入的次序进行有序存储,那么还是 List,因为 List 是一个有序容器,它按照插入顺序进行存储。
如果你想保证插入元素的唯一性,也就是你不想有重复值的出现,那么可以选择一个 Set 的实现类,比如 HashSet、LinkedHashSet 或者 TreeSet。所有 Set 的实现类都遵循了统一约束比如唯一性,而且还提供了额外的特性比如 TreeSet 还是一个 SortedSet,所有存储于 TreeSet 中的元素可以使用 Java 里的 Comparator 或者 Comparable 进行排序。LinkedHashSet 也按照元素的插入顺序对它们进行存储。
如果你以键和值的形式进行数据存储那么 Map 是你正确的选择。你可以根据你的后续需要从 Hashtable、HashMap、TreeMap 中进行选择。
43、谈谈JDK静态代理、动态代理、cglib动态代理的区别和优缺点。
JDK静态代理
是代理类与委托类实现同一接口,并且在代理类中需要硬编码接口;
优点:实现简单,容易理解。
缺点:代理类需要硬编码接口,不能实现运行时反射;
JDK动态代理
代理类与委托类实现同一接口,主要是通过代理类实现InvocationHandler并重写invoke方法来进行动态代理的,在invoke方法中将对方法进行增强处理,底层使用反射机制进行方法的调用。
优点:不需要硬编码接口,代码复用率高;
缺点:只能够代理实现了接口的委托类,不能针对类;
CGLIB动态代理
代理类将委托类作为自己的父类并为其中的非final委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor接口的对象,若存在则将调用intercept方法对委托方法进行代理。底层将方法全部存入一个数组中,通过数组索引直接进行方法调用。
优点: 可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口。
缺点:不能对final类以及final方法进行代理。