1.String文字量对应的String对象会保存在堆区,而其引用会保存在常量池,当我们反复使用一个文字量的时候,vm(虚拟机)会把该文字量的引用复制给我们的变量。new String在运行时创建String对象,所以文字量和使用文字量创建的字符串是不同的对象。编程验证 String a="abc";String b="abc";String c=new String("abc"); 中: ① a,b指向同一个对象 ②c和a不是同一个对象。
import java.util.*;
public class Test17_1 {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
String c = new String("abc");
if(a==b)
System.out.println("a,b指向同一个对象");
else
System.out.println("a,b不指向同一个对象");
if(a==c)
System.out.println("c和a是同一个对象");
else
System.out.println("c和a不是同一个对象");
}
}
2.List、Set的初始化,以及获取特定元素。
import java.util.*;
public class Test17_2{
public static void main(String[] args) {
//list可以这么初始化,但这个list属于Arrays的一个内部类,是不能修改的(add和remove元素等)
List<Integer> immutableList = Arrays.asList(1,3,-1,0,5,3);
//set和list可以用其他collection初始化,除了用构造方法,用addAll方法也行
List<Integer> list = new ArrayList<>(immutableList);
//set无法加入重复的元素,所以3只会保留一个
Set<Integer> set = new HashSet<>(immutableList);
//TODO:输出list的第4个元素
System.out.println(list.get(3));
//TODO:输出list中3这个元素的位置
System.out.println(list.indexOf(3));
//set不能通过索引访问元素,因为set是不保证遵循某种顺序
//arraylist hashset 都实现了自己的toString,如果对格式没什么要求,直接输出就可以了
//TODO:直接输出set,但HashSet在不同运行环境下输出顺序可能不一样,我们就不自动判题了
System.out.println("set="+set);
}
}
3.List和StringBuilder。
下面的程序从控制台接收一些整数,每个整数之间用空格分开,最后输入一个非整数结束。然后,程序将这些数输出,每个数之间用逗号分隔,最后不能有逗号。如:输入 5 4 6 5 1 3 2 a,然后输出 5,4,6,5,1,3,2 。因为String是不变类,所以任何修改字符串的操作其实都要生成新的字符串,因此这类操作比较多的时候,一般会借助StringBuffer和StringBuilder,两者的用法差不多(StringBuffer有一些String也有的方法),前者是线程安全的,后者不是,但速度更快。在TODO:处补齐代码
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class T17_3 {
public static void main(String[] args) {
List<Integer> ints = new ArrayList<>();
try (Scanner scanner = new Scanner(System.in)) {
while (scanner.hasNextInt()) {
int i = scanner.nextInt();
//TODO:将i加入ints
ints.add(i);
}
scanner.next();
}
StringBuilder stringBuilder = new StringBuilder();
for (int i : ints) {
//TODO:用append方法将 i+"," 追加到stringBuilder中
stringBuilder.append(i+",");
}
if (stringBuilder.length() > 0)
//TODO:用 deleteCharAt 删掉 stringBuilder 中最后一个字符
stringBuilder.deleteCharAt(stringBuilder.length()-1);
String s = stringBuilder.toString();
System.out.println(s);//直接打印stringBuilder也行,println执行过程中会调用toString
}
}
4.TreeSet用了排序二叉树存储set,所以会按大小顺序迭代元素,排序的依据是Integer的compareTo方法返回的结果。下面的程序从控制台接收一些整数,每个整数之间用空格分开,最后输入一个非整数结束。然后,程序将这些数输出,每个数之间用逗号分隔,最后不能有逗号。如:输入 5 4 6 5 1 3 2 a,然后输出 1,2,3,4,5,6 。补齐TODO处的代码.
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;
public class Test17_4 {
public static void main(String[] args) {
//TODO:把上一题的ArrayList的ints,换成用TreeSet
TreeSet<Integer> ints = new TreeSet<>();
try (Scanner scanner = new Scanner(System.in)) {
while (scanner.hasNextInt()) {
int i = scanner.nextInt();
//TODO:将i加入ints
ints.add(i);
}
scanner.next();
}
StringBuilder stringBuilder = new StringBuilder();
for (int i : ints) {
//TODO:用append方法将 i+"," 追加到stringBuilder中
stringBuilder.append(i+",");
}
if (stringBuilder.length() > 0)
//TODO:用 deleteCharAt 删掉 stringBuilder 中最后一个字符
stringBuilder.deleteCharAt(stringBuilder.length()-1);
System.out.println(stringBuilder);
}
}
5.HashSet使用equals方法判断对象是否相等,Student类没有覆盖Object的equals方法,所以学号相同的学生可以加到一个set中。补全TODO处的代码。运行程序的时候按照 学号 姓名 的顺序输入,如果学号是end,则结束输入。
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Test17_5 {
public static void main(String[] args) {
Set<Student> students = new HashSet<>();
try (Scanner scanner = new Scanner(System.in)) {
String sno;
String sname;
while (!(sno = scanner.next()).equals("end")) {
sname = scanner.next();
//TODO:用sno和sname创建新的学生并加入students中
Student s1=new Student(sno,sname);
students.add(s1);
}
}
System.out.println(students.toString());
}
public static class Student {
private String sno;
private String name;
public Student(String sno, String name) {
this.sno = sno;
this.name = name;
}
public String getSno() {
return sno;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Student{" +
"sno='" + sno + '\'' +
", name='" + name + '\'' +
'}';
}
// public boolean equals(Object obj) {
// return (this == obj);
// }
}
}
6.HashSet使用equals方法判断对象是否相等,这次我们要给Student类加上equals和hashCode方法,使得学号相等的同学相等,其他域不等也可以。补全TODO处的代码。可以用IDE提供的功能自动加上equals和hashCode,方法自己摸索,注意只加入sno生成这两个方法。两个方法都覆盖的原因是要保证equals成立的时候,hashCode一定相等。运行程序的时候按照 学号 姓名 的顺序输入,如果学号是end,则结束输入。
import java.util.HashSet;
import java.util.Objects;
import java.util.Scanner;
import java.util.Set;
public class Test17_6 {
public static void main(String[] args) {
Set<Student> students = new HashSet<>();
try (Scanner scanner = new Scanner(System.in)) {
String sno;
String sname;
while (!(sno = scanner.next()).equals("end")) {
sname = scanner.next();
//TODO:用sno和sname创建学生,并加入students
Student s1=new Student(sno,sname);
students.add(s1);
}
}
System.out.println(students.toString());
}
public static class Student {
private String sno;
private String name;
public Student(String sno, String name) {
this.sno = sno;
this.name = name;
}
public String getSno() {
return sno;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Student{" +
"sno='" + sno + '\'' +
", name='" + name + '\'' +
'}';
}
public void setSno(String sno) {
this.sno = sno;
}
public void setName(String name) {
this.name = name;
}
//TODO:这里覆盖equals和hashCode方法
@Override
public int hashCode() {
return Objects.hash(sno, sno);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
return Objects.equals(sno, other.sno) && Objects.equals(sno, other.sno) ;
}
}
}
7.Comparable接口用于各种排序相关的api中,它的接口方法用于比较调用自己的对象(this)和另一个对象的大小。因为TreeSet中的元素要排序,所以其元素类应当实现Comparable或TreeSet有可用的排序器。补齐下面程序TODO部分。
运行程序的时候按照 学号 姓名 的顺序输入,如果学号是end,则结束输入。
import java.util.*;
public class Test17_7 {
public static void main(String[] args) {
Set<Student> students = new TreeSet<>();
try (Scanner scanner = new Scanner(System.in)) {
String sno;
String sname;
while (!(sno = scanner.next()).equals("end")) {
sname = scanner.next();
//TODO:用sno和sname创建学生并加入students
Student s1=new Student(sno,sname);
students.add(s1);
}
}
System.out.println(students.toString());
}
//注意Comparable接口有类型参数(泛型)
public static class Student implements Comparable<Student>{
private String sno;
private String name;
public Student(String sno, String name) {
this.sno = sno;
this.name = name;
}
public String getSno() {
return sno;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Student{" +
"sno='" + sno + '\'' +
", name='" + name + '\'' +
'}';
}
/**
* @param obj 和当前对象比较的对象
* @return 如果 this大于obj,返回大于0的数,如果this等于obj,返回0,如果this小于obj,返回小于0的数
*/
@Override
public int compareTo(Student obj) {
//TODO:返回 this 和 obj 的sno的比较结果,sno是String类型的,所以我们可以用String的CompareTo方法比较它们
return this.sno.compareTo(obj.sno);
}
}
}
8.Comparator除了通过Comparable接口使用类自身的compareTo方法比较对象大小,TreeSet还可以使用比较器(实现Comparator接口的类)实例来比较对象大小,而且一旦提供了比较器,它会被优先使用(而不是用类自身实现的compareTo)。
import java.util.*;
public class Test17_8 {
public static void main(String[] args) {
//TreeSet可以通过构造方法注入一个实现Comparator接口的比较器对象,这里我们用一个匿名类实现它
Set<Student> students = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//TODO: 返回o1.sno和o2.son的比较结果
return o1.sno.compareTo(o2.sno);
}
});
try (Scanner scanner = new Scanner(System.in)) {
String sno;
String sname;
while (!(sno = scanner.next()).equals("end")) {
sname = scanner.next();
//TODO:用sno和sname创建Student并加入students
Student s1=new Student(sno,sname);
students.add(s1);
}
}
System.out.println(students.toString());
}
public static class Student{
private String sno;
private String name;
public Student(String sno, String name) {
this.sno = sno;
this.name = name;
}
public String getSno() {
return sno;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Student{" +
"sno='" + sno + '\'' +
", name='" + name + '\'' +
'}';
}
}
}