参考Java程序员面试笔试宝典:

目录

1.字符串创建与存储的机制

2.“==”、equals和hashCode有什么区别

4.java中数组是不是对象

5.数组的初始化方式

6.length属性和length()方法有何区别


1.字符串创建与存储的机制

字符串的声明和初始化主要有两种情况:

1)对于 String s1=new String("abc") 和 String s1=new String("abc"),存在两个引用对象s1,s2,内容相同的字符串对象“abc”,他们在内存中的地址不同,只要用到new就睡生成新的对象。

2)对于String s1=“abc” 和 String s2=“abc”,在JVM中存在一个字符串池,保存很多String对象,可被共享,s1,s2引用的是同一个常量池中的对象。当创建一个字符串常量时,若已经定义,则直接获取对其的引用,不需要创建新的对象;若没定义,先创建这个对象,再加入到字符串池中,再将其引用返回。由于String是不可变类,一旦创建不能被修改,因此可被共享不会导致程序混乱。

引申:

问:对于String类型变量s,赋值语句s=null和s=“”是否相同?

答:不同。s=null,s是一个字符串类型的引用,不指向任何一个字符串;s=“”,s是一个字符串类型的引用,指向一个空字符串。因此不同。

问:new String("abc")创建了几个对象?

答:一个或两个。如果常量池中原来有“abc”,则只创建一个对象;如果没有,则会创建两个对象。

2.“==”、equals和hashCode有什么区别

1)“==”

用来比较两个变量的值是否相等。要比较两个基本类型数据或两个引用变量是否相等,只能用“==”。

具体而言,两个变量是基本数据类型,直接“==”比较值是否相等;若一个变量指向的数据是对象(引用类型)。此时,涉及到两块内存,对象本身的内存(堆内存)和变量的内存。如String s=new String(),变量s占一块内存,new String()在另一块存储空间,变量s的内存数值是对象内存的首地址。若要比较两个变量是否指向同一个对象,即是否指向同一块存储空间,可用“==”,若要比较两个对象内容是否相等,则“==”无法实现。

2)equals

是Object类提供的方法之一。默认情况下Object类中定义的equals方法直接使用“==”运算符比较两个对象,因此和“==”效果相同。但其特殊之处在于它可以被覆盖,开发人员可覆盖此方法来实现如何比较才算两个变量相同。

3)hashCode()

是从Object类中继承过来的,返回对象在内存中地址转换成的一个int值,所以若没有重写hashCode()方法,任何对象的hashCode()都是不相等的。

一般来讲,equals()方法是给用户调用的,对于hashCode()用户一般不会去调用,它相当于一个对象的编码,类似于文件的md5。

一般覆盖equals()的同时也要覆盖hashCode()方法,否则会违反Object.hashCode的通用约定,导致该类无法与所有基于散列值和集合类结合在一起正常运行。

拓展:

compareTo()方法可用于比较两个字符串,返回结果为int型。该方法会循环对比所有的字符,当两个字符串有任意一个字符不相等时,会返回两个字符串的差值。如1和2,返回就是-1;若1和1,返回就是0;若2和1,返回就是1。还有一个方法,与其类似,就是compareToIgnoreCase(),用于忽略大小写后比较两个字符串。

当用equals()返回true,compareTo()返回0时,表示两个字符串完全相同。

String类的其他一些重要方法:

indexOf():查询字符串首次出现的下标位置
lastIndexOf():查询字符串最后出现的下标位置
contains():查询字符串中是否包含另一个字符串
toLowerCase():把字符串全部转换成小写
toUpperCase():把字符串全部转换成大写
length():查询字符串的长度
trim():去掉字符串首尾空格
replace():替换字符串中的某些字符
split():把字符串分割并返回字符串数组
join():把字符串数组转为字符串

3.String、StringBuffer、StringBuilder、StringTokenizer有何区别

java语言有4个类对字符和字符串进行操作:

Character:单个字符操作。
String:字符串操作,不可变类,适合在需要被共享的场合使用。
StringBuffer:字符串操作,可变类,在字符串需要频繁修改时使用。
StringTokenizer:分割字符串。

在实例化String时,可利用构造函数 String s1=new String("chs"),也可用赋值 String s="hello";而StringBuffer只能使用构造函数StringBuffer s=new StringBuffer("hello")进行初始化。

String字符串修改实现原理:先创建一个StringBuilder,调用append()方法,最后调用toString()方法返回。

String s="hello";
StringBuilder chs=new StringBuilder(s);
chs.append("world");
System.out.println(chs.toString());

在执行效率方面,当一个字符串需要经常被修改,StringBuilder会比String好很多。

StringBuilder与StringBuffer都是字符串缓冲区,单线程中,StringBuilder效率更高,多线程时,使用StringBuffer更安全,且必要时可对方法进行同步。

总结:执行效率方面:StringBuilder最高,StringBuffer次之,String最低。若数据量小,使用String类;若单线程操作大量数据,使用StringBuilder;若多线程操作大量数据,使用StringBuffer。

StringTokenizer用来分割字符串:

import java.util.StringTokenizer;
public class Test{
    public static void main(String[] args) {
        StringTokenizer st=new StringTokenizer("aaa bbb ccc");
        while(st.hasMoreTokens()){
            System.out.println(st.nextToken());
        }
    }
}

结果:

aaa

bbb

ccc

4.java中数组是不是对象

数组是指具有相同类型的数据的集合,一般有固定的长度,且在内存中占据连续的空间。

C/C++中,数组名只是个指针,指向数组的首元素,没有属性没有方法可调用。

Java中,数组有自己的属性(如length),也有方法可调用(如clone方法)。

由于对象的特点是封装了一些数据,同时提供一些属性和方法,从这个角度讲,数组是对象。

每个数组有其对应的类型,可用instanceof来判断数据的类型。

5.数组的初始化方式

一维数组:

声明:type arrayName[] 或 type[] arrayName

type可以是基本数据类型,也可以是类,arrayName表示数组名字,[]表示变量类型位一维数组。数组创建后会根据数据类型初始化初始值,int初始化为0,对象初始化为null。java在数组定义时,不会分配存储空间,因此不要指定长度,在使用时需要为之分配空间,分配方法:arrayName=new type[arraySize]

初始化:

1)in[] a=new int[5]; 等价于 int[] a; a=new int[5];
2)int[] a={1,2,3,4,5}; 等价于 int[] a; a=new int{1,2,3,4,5};

二维数组:

声明:

1)type arrayname[][]
2)type[][] arrayName
3)type[] arrayName[]

声明时,[]必须为空。

初始化:

1)type arrayName[][]={{a1,a2,a3……},{b1,b2.b3……},{c1,c2,c3……}……};
2)type arrayName[][]=new type[行数][列数]

二维数组的第二维长度可以不同

6.length属性和length()方法有何区别

在C/C++中,传递数组时,必须同时传递数组的长度,在方法调用时传递的参数时数组的首地址,实际长度无法获知,访问可能产生越界。length属性用来获取数组的长度。(arr.length)

length()方法是针对字符串的,计算字符串长度。(str.length())

还有一个计算对象大小的方法——size()方法,是针对泛型集合而言的,查看泛型有多少个元素。