1.字符串的字面量是否自动生成一个字符串的变量?
String str1 = “abc”;
Sring str2 = new String (“abc”);
对于str1:Jvm在遇到双引号时会创建一个String对象,该String对象代表的值是abc,实际上,在创建该对象之前会在String对象池中搜索该字符串对象是否已经被创建,如果已经被创建,就直接返回一个字符串的引用,否则先创建再返回一个引用。
对于str2:需要的额外的工作是:会创建一个新的的string对象,通过new关键字来实现,并且返回一个引用给str2.
Str1==str2会返回false,因为指向的并不是同一个引用。
equals方法会进行字符序列的比较,则会返回true.
2.字符串对象池的作用是什么?
java虚拟机在启动的时候会实例化9个对象池,用来存储8种基本数据类型的包装类对象和String对象。
作用:避免频繁的创建和撤销对象而影响系统的性能。
例子:
1 package test; 2 3 import java.util.HashSet; 4 5 class Dog{ 6 7 public Dog(String name, int age) { 8 9 super(); 10 11 this.name = name; 12 13 this.age = age; 14 15 } 16 17 private String name; 18 19 private int age; 20 21 private static HashSet<Dog> pool = new HashSet<Dog>(); 22 23 //使用对象池得到对象的方法 24 25 public static Dog newInstance(String name,int age){ 26 27 for(Dog dog :pool){ 28 29 if(dog.name.equals(name)&&dog.age==age){ 30 31 return dog; 32 33 } 34 35 } 36 37 //否则实例化一个新的dog 38 39 Dog dog = new Dog(name,age); 40 41 pool.add(dog); 42 43 return dog; 44 45 } 46 47 } 48 49 public class Main { 50 51 public static void main(String[] args) { 52 53 Dog dog1 = Dog.newInstance("xiaobai",1); 54 55 Dog dog2 = Dog.newInstance("xiaobai", 1); 56 57 Dog dog3 = new Dog("xiaobai",1); 58 59 System.out.println(dog1==dog2); 60 61 System.out.println(dog1==dog3); 62 63 } 64 65 }
本质理解:如果调用了new方法,则返回false,因为对象有了新的引用,如果没有调用new方法,就引用的是同一个对象,则返回true.
3.StringBuffer和StringBuilder的区别和应用场景?
java的String对象是不变性,只能被创建,但是不能改变其中的值。
1 Demo1: 2 3 package test; 4 5 public class Main { 6 7 public static void main(String[] args) { 8 9 String a = "a"; 10 11 String b = "b"; 12 13 String c = "c"; 14 15 //采用这种方式,可以创建5个对象 16 17 String abc = a+b+c; 18 19 //使用stringbuffer可以解决性能问题 20 21 //如果要保证是线程安全的,用stringbuilder 22 23 StringBuffer sb = new StringBuffer(); 24 25 sb.append(a); 26 27 sb.append(b); 28 29 sb.append(c); 30 31 } 32 33 } 34 35 Demo2: 36 37 1 String s = "abcd"; 38 2 s = s+1; 39 3 System.out.print(s);// result : abcd1
首先创建对象s,赋予一个abcd,然后再创建一个新的对象s用来执行第二行代码,也就是说我们之前对象s并没有变化,所以我们说 String类型是不可改变的对象了,由于这种机制,每当用String操作字符串时,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉,可想而知这样执行效率会有多低。
而StringBuffer与StringBuilder就不一样了,他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,这样就不会像String一样创建一些而外的对象进行操作了,当然速度就快了。
1 Demo3: 2 3 1 String str = “This is only a” + “ simple” + “ test”; 4 2 StringBuffer builder = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
你会很惊讶的发现,生成str对象的速度简直太快了,而这个时候StringBuffer居然速度上根本一点都不占优势。其实这是JVM的一个把戏,实际上:
1 String str = “This is only a” + “ simple” + “test”;
其实就是:
String str = “This is only a simple test”; 所以不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的String对象的话,速度就没那么快了,譬如: string str2 = “This is only a”; String str3 = “ simple”; String str4 = “ test”; String str1 = str2 +str3 + str4;
这时候JVM会规规矩矩的按照原来的方式去做。
Demo4:
StringBuilder与 StringBuffer
StringBuilder:线程非安全的
StringBuffer:线程安全的
当我们在字符串缓冲去被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证 StringBuffer是可以正确操作的。当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不 用StringBuffer的,就是速度的原因。
4.如何输出反转后的字符串?
三种方式的实现:
1 package test; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 7 String s = "hello world"; 8 9 for(int i =s.length();i>0;i--){ 10 11 System.out.print(s.charAt(i-1)); 12 13 } 14 15 System.out.println(); 16 17 System.out.println("--------------"); 18 19 char[] array = s.toCharArray(); 20 21 for(int i = array.length;i>0;i--){ 22 23 System.out.print(array[i-1]); 24 25 } 26 27 System.out.println(); 28 29 System.out.println("--------------"); 30 31 StringBuffer buff = new StringBuffer(s); 32 33 System.out.println(buff.reverse().toString()); 34 35 } 36 37 }
5.如何利用指定的字符集创造String对象?
不论是字符串的字面量,还是用String的构造方法创造字符串对象,都不会指定特定的字符集。平台的默认字符集是GBK或者GB2312,当我们用输入法输入中文后,这些中文的默认编码是GBK,但是JVM在编译的时候会按照unicode进行重新的编码。
利用特定的字符集进行编码:
1 package test; 2 3 import java.io.UnsupportedEncodingException; 4 5 public class Main { 6 7 public static void main(String[] args) throws UnsupportedEncodingException { 8 9 String s = "哈哈哈"; 10 11 String b = new String(s.getBytes(),"GBK"); 12 13 String c = new String(s.getBytes(),"UTF-8"); 14 15 System.out.println(b); 16 17 System.out.println(c); 18 19 20 21 } 22 23 } 24 25 结果:哈哈哈 ??????
解释:实际上是对原有的字符串先转换为字节数组,然后用一种新的编码方法进行二次编码。
6.如何理解数组在java中作为一个类?
数组属于引用类型,每一个数组实例都是一个对象,这些对象同属于一个类。
java数组的实质是一个类,该类还保存了数据类型的信息。该类通过成员变量的形式保存数据,并且通过[],使用下标来访问这些数据,在处理基本数据类型时,数组保存的是变量的值,如果初始化,系统为之初始化为0;处理引用类型的数据时数组保存的书数据的引用,默认初始化为null.
7.new Object[5]语句是否创建了5个对象?
并没有创建5个对象,只是开辟了存放五个对象的内存空间。
Object[] objarr = new Object[5];
创建一个存储object的数组,长度为5,这5个元素的值都为null,只有为这些元素分别赋予了具体的对象,才会使得元素指定特定的引用。
8.二维数组的长度是否固定?
实质:先创建一个一维数组,然后该数组的元素再引用另外一个一维数组,在使用二维数组时,通过两个中括号来访问每一层维度的引用,直到访问到最后的数据。
二维数组的长度没必要去指定,他们的长度是各异的。
Int[][] arr = new int[3][];
第一维的长度是固定的为3,但是第二维的长度却不固定,可以变。
9.深拷贝和浅拷贝?
浅拷贝:只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制
深拷贝:对象,对象内部的引用均复制
10.什么是集合?
集合代表了一种底层的机构,用来拓展数组的功能,它的每一种形式代表了某一种数据结构。
Set:无序存放,不允许重复,可以存放不同类型的对象
List:有序存放,允许重复,可以存放不同类型的对象
SoretdSet:排好序列set
sortedMap:排好序列的map
注意:所有的集合实现类都只能存放对象,如果存放基本数据类型的数据,则需要使用包装类。
11.java中的迭代器是什么?
迭代器模式又称为游标模式,提供一种方法,访问一个容器对象中的元素,但是隐藏对象的内部细节。
实际上,迭代器就是一个接口Iterator,实现了该接口的类是可迭代类。
一个列子:
1 package test; 2 3 import java.util.ArrayList; 4 5 import java.util.Iterator; 6 7 import java.util.List; 8 9 public class Main { 10 11 public static void main(String[] args){ 12 13 List<String> list = new ArrayList<String>(); 14 15 list.add("hello"); 16 17 list.add("world"); 18 19 Iterator<String> it = list.iterator(); 20 21 //hasnext判断是否有下个元素,next()用于输出下一个元素 22 23 while(it.hasNext()){ 24 25 System.out.println(it.next()); 26 27 } 28 29 } 30 31 }
12.java中的比较器是什么?
当用户自己自定义了一个类,这个类需要进行比较,这个时候就要使用到comparable和comparator接口。
Comparable:进行比较类需要实现的接口,仅仅包含一个CompareTo()方法,(在类中需要重写该方法)只有一个参数,返回值类型为int型,如果该返回值大于0,表示本对象大于参数对象,如果小于0,表示本对象小于参数对象,等于0,则相等。
一个例子:
1 package test; 2 3 public class User implements Comparable{ 4 5 public User(String name, int age) { 6 7 super(); 8 9 this.name = name; 10 11 this.age = age; 12 13 } 14 15 public String getName() { 16 17 return name; 18 19 } 20 21 public void setName(String name) { 22 23 this.name = name; 24 25 } 26 27 public int getAge() { 28 29 return age; 30 31 } 32 33 public void setAge(int age) { 34 35 this.age = age; 36 37 } 38 39 @Override 40 41 public int compareTo(Object o) { 42 43 // TODO Auto-generated method stub 44 45 return this.age-((User) o).getAge(); 46 47 //如果当前类的age大于参数的age 返回大于0的数 48 49 //相等则返回0 50 51 } 52 53 private String name; 54 55 private int age; 56 57 } 58 59 主函数测试: 60 61 package test; 62 63 64 65 public class Main { 66 67 public static void main(String[] args){ 68 69 User user1 = new User("hello",10); 70 71 User user2 = new User("wwww",20); 72 73 if(user1.compareTo(user2)<0){ 74 75 System.out.println("user1's age is smaller"); 76 77 }else{ 78 79 System.out.println("equal"); 80 81 } 82 83 } 84 85 }
comparator也是一个接口,它的实现者被称为比较器,包含一个compare()方法,有两个参数,comparator不会被集合元素实现类所实现,而是单独实现或者是用匿名内部类实现。
一个例子:
首先自己定义一个比较器,用于比较特定的属性:
1 package test; 2 3 import java.util.Comparator; 4 5 public class MyComparator implements Comparator { 6 7 8 9 @Override 10 11 public int compare(Object o1, Object o2) { 12 13 User u1 = (User)o1; 14 15 User u2 = (User)o2; 16 17 return u1.getAge()-u2.getAge(); 18 19 } 20 21 } 22 23 实体类: 24 25 package test; 26 27 public class User{ 28 29 public User(String name, int age) { 30 31 super(); 32 33 this.name = name; 34 35 this.age = age; 36 37 } 38 39 public String getName() { 40 41 return name; 42 43 } 44 45 public void setName(String name) { 46 47 this.name = name; 48 49 } 50 51 public int getAge() { 52 53 return age; 54 55 } 56 57 public void setAge(int age) { 58 59 this.age = age; 60 61 } 62 63 64 65 private String name; 66 67 private int age; 68 69 } 70 71 测试函数: 72 73 package test; 74 75 public class Main { 76 77 public static void main(String[] args) { 78 79 User user1 = new User("hello", 10); 80 81 User user2 = new User("wwww", 20); 82 83 int res; 84 85 MyComparator comparator = new MyComparator(); 86 87 res= comparator.compare(user1, user2); 88 89 if(res>0){ 90 91 System.out.println("user1's age bigger"); 92 93 }else if(res<0){ 94 95 System.out.println("user2's age bigger"); 96 97 }else{ 98 99 System.out.println("equal"); 100 101 } 102 103 } 104 105 }
13.Vector和arraylist的区别?
都是List接口的实现类,都代表链表形式的数据结构。
Vector是线程安全的,保证了线程安全,但是此时的执行效率会低一些,如果要求执行效率则使用arrayList.在使用方法上二者基本一样。
14.HashTable和HashMap的区别?
二者在保存元素都是无序的。
1>HashTable的方法是线程同步的,hashmap不能同步,在多线程的情况下要使用HashTable.
2>HashTable 不允许null值,key和value都不允许。HashMap允许null值,key和value都允许。
3>HashTable有一个contains方法,功能和containsvalue功能一样
4>HashTable使用Enumeration遍历,HashMap使用Iterator进行变量。
5>HashTable 中的hash数组的初始化大以及其增长方式不同
6>哈希值的使用不同,hashTable直接使用对象的HashCode,HashMap会重新计算哈希值。
如果没有要求是线程安全的,推荐使用hashMap,更符合java集合框架的设计思路。
15.集合使用泛型单来什么好处?
集合使用泛型后可以达到元素类型明确的目的,避免了手动类型转换的过程,同时也让开发者明确了容器保存的是什么类型的数据。这样,在每次从集合中取得的数据就不用每次取出一个进行类型的转换。需要注意的是,java的泛型是停在编译层的,jvm在对待泛型数据时,会依然把他们当成是object来处理,只是jvm会在底层帮助开发者完成类型的转换。
16.如何把集合对象中的元素进行排序?
vector和arraylist linkedlist本身不可以进行元素的排序。
可以使用java.utils.collections类下的sort方法进行排序。
如果列表中的全部是相同类型的数据元素,并且这个类实现了comparable接口,可以简单调用sort方法,如果没有实现comparator,就要传递一个comparator的实例作为第二个参数。
一个例子:
Student 类要实现Comparable接口,重写compareTo方法
1 package test; 2 3 public class Student implements Comparable<Student> { 4 5 @Override 6 7 public String toString() { 8 9 return "Student [name=" + name + ", age=" + age + "]"; 10 11 } 12 13 public String getName() { 14 15 return name; 16 17 } 18 19 public void setName(String name) { 20 21 this.name = name; 22 23 } 24 25 public int getAge() { 26 27 return age; 28 29 } 30 31 public void setAge(int age) { 32 33 this.age = age; 34 35 } 36 37 public Student(String name, int age) { 38 39 super(); 40 41 this.name = name; 42 43 this.age = age; 44 45 } 46 47 @Override 48 49 public int compareTo(Student o) { 50 51 if(this.age>o.age){ 52 53 return 1; 54 55 }else if(this.age<o.age){ 56 57 return -1; 58 59 }else{ 60 61 return 0; 62 63 } 64 65 } 66 67 private String name; 68 69 private int age; 70 71 72 73 } 74 75 测试类中按照三种方式去排序: 76 77 package test; 78 79 import java.util.ArrayList; 80 81 import java.util.Collections; 82 83 import java.util.Comparator; 84 85 import java.util.Iterator; 86 87 import java.util.List; 88 89 public class Main { 90 91 @SuppressWarnings("unchecked") 92 93 public static void main(String[] args) { 94 95 List<Student> list = new ArrayList<Student>(); 96 97 list.add(new Student("admin", 20)); 98 99 list.add(new Student("dddd", 30)); 100 101 list.add(new Student("wwww", 60)); 102 103 System.out.println("default order..."); 104 105 // 默认的顺序 106 107 @SuppressWarnings("rawtypes") 108 109 Iterator it = list.iterator(); 110 111 while (it.hasNext()) { 112 113 System.out.println(it.next()); 114 115 } 116 117 System.out.println("desc order..."); 118 119 // 降序排序 120 121 @SuppressWarnings("rawtypes") 122 123 Comparator comp = Collections.reverseOrder(); 124 125 Collections.sort(list, comp); 126 127 @SuppressWarnings("rawtypes") 128 129 Iterator it1 = list.iterator(); 130 131 while (it1.hasNext()) { 132 133 System.out.println(it1.next()); 134 135 } 136 137 System.out.println("by name order..."); 138 139 140 141 // 按照名字进行排序 142 143 Collections.sort(list, new Comparator<Student>() { 144 145 @Override 146 147 public int compare(Student o1, Student o2) { 148 149 return o1.getName().compareTo(o2.getName()); 150 151 } 152 153 }); 154 155 Iterator it2 = list.iterator(); 156 157 while (it2.hasNext()) { 158 159 System.out.println(it2.next()); 160 161 } 162 163 } 164 165 }