1.StringBuilder替代String拼接,面试中经常会遇到
String、StringBuilder、StringBuffer的区别
最佳答案:String 类作为java语言中最常见的字符串类被广泛使用,如果在做大量字符串拼接效率会变得比较低,因为虚拟机需要不断地将对象引用指向新的地址。
因此,一般方法内的私有变量推荐使用StringBuilder来完成,如果是多线程需要同步的自然选用StringBuffer。
String是字符串常量,由final修饰,不可被继承,String是常量,创建之后不能更改。
StringBuilder字符串变量(非线程安全)与StringBuffer一样都继承和实现了同样的接口和类,方法除了没使用synch修饰以外基本一致,不同之处在于最后toString的时候,会直接返回一个新对象
public String toString() {
// Create a copy, don’t share the array
return new String(value, 0, count);
}
2.对参数未做空验证,就开始判断值是否相等
将常量放在equals方法的左边,能防止NullPointerException
总结:主要是要保证String 类equals的实现方法,要保证equals方法的左边常量不能为null
3.仔细观察下面两张图 注意控制台输出结果
Integer类型当正整数小于128时是在内存栈中创建值的,并将对象只想这个值,当比较两个栈引用时因为是同一地址引用两者则相等。当大于127时将会调用new Integer(),两个整数对象地址引用不相等了。
4.下面再来一题,思考输出结果
解析过程 :
- ==操作符专门用来比较两个变量的值,比较变量所对应的内存中存储的数值
- equals比较两个独立对象的内容,好比是去比较两个人的长相,比较的两个对象是独立的。
自动装箱和自动拆箱
- JVM会自动维护八种基本数据类型的常量池,第一次执行Integer i1=100时,会将i1放入常量池,i2的数据也是100,所以不再去创建新的对象,所以,i1==i2 输出结果为true。
- Integer并不是基本数据类型,就涉及到了自动装箱和自动拆箱的概念。自动装箱就是Java自动将原始类型值转换为对应的对象,比如将int的变量类型转换成Integer对象,该过程称之为装箱,反之将Integer对象转换为int类型的值,这个过程叫做拆箱。
- 装箱和拆箱时自动进行而并非认为转换,所以就称之为自动装箱和自动拆箱。原始类型byte(8),short(16),char(16),int(32),long(64),float(32),double(64)和boolean(1)对应的封装类为:Byte,Short,Character,Integer,Long,Float,Double,Boolean。
public class Test {
public static void main(String[] args) {
// byte
System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE);
System.out.println("包装类:java.lang.Byte");
System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
System.out.println();
// short
System.out.println("基本类型:short 二进制位数:" + Short.SIZE);
System.out.println("包装类:java.lang.Short");
System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);
System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);
System.out.println();
// int
System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);
System.out.println("包装类:java.lang.Integer");
System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
System.out.println();
// long
System.out.println("基本类型:long 二进制位数:" + Long.SIZE);
System.out.println("包装类:java.lang.Long");
System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);
System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);
System.out.println();
// float
System.out.println("基本类型:float 二进制位数:" + Float.SIZE);
System.out.println("包装类:java.lang.Float");
System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);
System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);
System.out.println();
// double
System.out.println("基本类型:double 二进制位数:" + Double.SIZE);
System.out.println("包装类:java.lang.Double");
System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);
System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);
System.out.println();
// char
System.out.println("基本类型:char 二进制位数:" + Character.SIZE);
System.out.println("包装类:java.lang.Character");
// 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台
System.out.println("最小值:Character.MIN_VALUE="
+ (int) Character.MIN_VALUE);
// 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台
System.out.println("最大值:Character.MAX_VALUE="
+ (int) Character.MAX_VALUE);
}
}
输出结果
int类型的常量池中初始化范围为:-128-127.所以当Integer i1,i2=100时,都是在自动装箱的过程中从常量池中取数值,而Integer i3,i4=150时,不在常量池的范围内,所以自动装箱的过程中需要new一个对象,所以 i3==i4输出结果为false
5.下面哪个流类时属于面向字符的输入流()
A BufferedWriter
B FileInputStream
C ObjectInputStream
D InputStreamReader
答案:D
解析:以InputStream(输入)/OutputStream(输出)为后缀的都是字节流。以Reader(输入)/Writer(输出)为后缀的时字符流
6.String能被继承吗?为什么?
不可以,因为String类有final修饰符,final修饰的类是不能被继承的,实现的细节不允许改变。
String str="a" 和String str=new String("a")是有差别的。String str="a"默认调用的是String.valueOf来返回实例对象
比如String n=1; 调用的是
public static String valueOf(int i){return Integer.toString(i);}
String str=new String("a")调用的是
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
最后我们的变量都是存放在一个char类型的数组里private final char value[];
7.ArrayList和LinkedList的区别
ArrayList和LinkedList都实现了List接口
- ArrayList是基于索引的数据接口,底层是数组。可以以O(1)的事件复杂度对元素进行随机访问。LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素连接在一起,查找某个元素的时间复杂度是O(n)。
- LinkedList的插入,添加和删除速度更快,因为元素被添加到集合的认一位置的时候,不需要像数组那样重新计算大小或更新索引。
- LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向后一个元素。
8.讲讲类的实例化过程,比如父类静态方法,成员变量,构造方法和子类静态方法,构造方法,成员变量。当new的时候,他们的执行顺序
package com.springsecurity.springsecurity.security.model;
/**
* @Author zhaomengxia
* @create 2019/8/8 17:14
*/
public class ClassLoaderTest {
public static void main(String[] args) {
son son = new son();
}
}
class parent {
private static int a = 1;
private static int b;
private int c = initc();
{
System.out.println("父类代码块");
}
public parent(int c) {
this.c = c;
System.out.println("父类有参构造方法");
}
public parent() {
System.out.println("父类无参构造方法");
}
int initc() {
System.out.println("3.父类成员变量赋值:---> c的值" + c);
this.c = 12;
System.out.println("3.父类成员变量赋值:---> c的值" + c);
return c;
}
static {
b = 1;
System.out.println("1.父类静态代码块:赋值b成功");
System.out.println("1.父类静态代码块:a的值" + a);
}
}
class son extends parent {
private static int sa = 1;
private static int sb;
private int sc = initc2();
public son() {
System.out.println("子类空参构造方法");
}
static {
sb = 1;
System.out.println("2.子类静态代码块:赋值sb成功");
System.out.println("2.子类静态代码块:sa的值" + sa);
}
{
System.out.println("子类代码块");
}
int initc2() {
System.out.println("5.子类成员变量赋值--->:sc的值" + sc);
this.sc = 12;
return sc;
}
public son(int c, int sc) {
super(c);
this.sc = sc;
System.out.println("子类构造方法");
}
public son(int sc) {
this.sc = sc;
System.out.println("子类构造方法");
}
}
执行结果:
故意改变父类和子类静态代码块,构造方法,代码块和成员变量赋值的顺序结果如下,发现执行顺序一致
package com.springsecurity.springsecurity.security.model;
/**
* @Author zhaomengxia
* @create 2019/8/8 17:14
*/
public class ClassLoaderTest {
public static void main(String[] args) {
son son = new son();
}
}
class parent {
private static int a = 1;
private static int b;
private int c = initc();
public parent(int c) {
this.c = c;
System.out.println("父类有参构造方法");
}
public parent() {
System.out.println("父类无参构造方法");
}
{
System.out.println("父类代码块");
}
static {
b = 1;
System.out.println("1.父类静态代码块:赋值b成功");
System.out.println("1.父类静态代码块:a的值" + a);
}
int initc() {
System.out.println("3.父类成员变量赋值:---> c的值" + c);
this.c = 12;
System.out.println("3.父类成员变量赋值:---> c的值" + c);
return c;
}
}
class son extends parent {
private static int sa = 1;
private static int sb;
private int sc = initc2();
public son() {
System.out.println("子类空参构造方法");
}
{
System.out.println("子类代码块");
}
int initc2() {
System.out.println("5.子类成员变量赋值--->:sc的值" + sc);
this.sc = 12;
return sc;
}
static {
sb = 1;
System.out.println("2.子类静态代码块:赋值sb成功");
System.out.println("2.子类静态代码块:sa的值" + sa);
}
public son(int c, int sc) {
super(c);
this.sc = sc;
System.out.println("子类构造方法");
}
public son(int sc) {
this.sc = sc;
System.out.println("子类构造方法");
}
}
执行结果如下
- 静态方法块或则静态变量优先加载。即父类子类的所有静态方法优先执行,但是要遵循先父类后子类。静态方法中的静态变量是按顺序的,即谁在前先加载谁。接着就是父类剩余的成员变量和构造方法,先给父类的成员变量赋值,再执行父类的虚函数,最后执行相应的父类构造方法;然后才是子类,子类也是先给成员变量赋值,接着是子类的代码块,最后执行子类相应的构造方法。
9.&与&&的区别
- &逻辑与,&&短路与。&与&&都要求左右两端的布尔值都为true时表达式的值才为true。&&如果左边的表达式的值为false,右边的表达式会被直接短路掉,不会进行运算。当我们判断用户名不是null而且不是空字符串时,应当写为:username != null &&!username.equals(""),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生NullPointerException异常。注意逻辑或(|)和短路或(||)也是同样的差别。
思考一下这个输出结果,结果是不是 2 2
这个结果是不是3 4
10.解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法
- 通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间;而通过new关键字和构造器创建的对象则存放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,故堆空间还可以细分为新生代和老生代,再具体一点可以分为Eden、Survivor(又可分为From Survivor和To Survivor)、Tenured;
- 方法区和堆都是各个线程共享的内存区域,用于存储已经被JVM加载的类信息、常量、静态变量、JIT编译器编译后的代码等数据;
- 程序中的字面量如直接书写的100,"hello"和常量都是放在常量池中,常量池是方法区的一部分。
- 栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,栈和堆的大小都可以通过JVM的启动参数来进行调整,栈空间用光了会引发StackOverflowError,而堆和常量池空间不足会引发OutOfMemoryError。
String str = new String("hello");
上面语句中,str是放在栈上;用new创建出来的字符串对象放在堆上 ;而"hello"这个字面量是放在方法区的。
11.Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?
- Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整。
12.switch是否能够作用在byte上,是否能作用在long上,是否能作用在String上?
- 在Java 5以前,switch(expr)中,expr只能是byte、short、char、int。
- 从Java 5开始,Java中引入了枚举类型,expr也可以是enum类型
- 从Java 7开始,expr还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。
13.用最有效率的方法计算2乘以8?
- 2<<3(左移三位相当于乘以2的3次方,右移三位相当于除以2的3次方)
14.数组有没有length()方法?String有没有length()方法
数组有length,String有length()方法