TreeSet :Set接口有一个实现类:TreeSet类,该类底层使用红黑树算法(平衡二叉树)。 可以对集合中的数据按照一定的规则来排序。
public static void main(String[] args) { // 元素可以自动排序 Set set=new TreeSet(); set.add(10); set.add(5); set.add(0); System.out.println(set); set=new TreeSet(); set.add("5"); set.add("10"); set.add("2"); set.add("5"); set.add("高数"); set.add("线代"); set.add("离散"); System.out.println(set);// 结果:10, 2, 5, 离散, 线代, 高数 。 为什么10是第一位呢?因为是字符串,会先比较10中的1.注意:使用TreeSet,一定要保证该集合中的元素必须是同一种数据类型。 只有同一种数据类型才有可比性,若数据类型不同,就会报错。
把某一对象存储在TreeSet中,对象的类通过实现Comparable接口才会具有可比性,否则报错(类型转换错误)。
第一种方法继承Comparable接口:
Comparable 接口: 方法: public int compareTo( Object o ){ 编写比较规则 }
拿当前对象(this)和传入的o对象作比较。 返回: 当前对象 > o : return 正整数; 当前对象 == o : return 0; 当前对象 < o : return 负整数; TreeSet会认为,如果compareTo方法返回的是0,则认为是同一个对象,若是同一个对象则不会添加到集合中。
class Student1 implements Comparable{ private String name; private int age; private int score; public Student1(String name, int age, int score) { this.name = name; this.age = age; this.score = score; } // 作比较 @Override public int compareTo(Object obj) { // 父类要访问对象的成员变量,必须强转成子类 Student1 other=(Student1)obj; if(this.score > other.score){ return 1; }else if(this.score < other.score){ return -1; }else{ // 如果成绩相同时则比较年龄 if(this.age > other.age){ return 1; }else if(this.age < other.age){ return -1; }else{ return this.name.compareTo(other.name); // 年龄和成绩都相同时,比较名字(String已实现compareTo方法) } } } @Override public String toString() { return "Studen1[name = "+name+",age = "+age+",score = "+score+"]"; } }^父类要访问对象的成员变量,必须强转成子类。
第二种方法继承Comparator接口:
//根据名字长度来排序,长的先排出来,短的后排出来 class Teacher { private String name; public Teacher(String name){ this.name=name; } public String getName() { return name; } @Override public String toString() { return "Teacher{" + "name='" + name + '\'' + '}'; } } public class StudentSortDemo2 { public static void main(String[] args) { Comparator com=new NameCom();// 不用Comparable接口的原因是,其采用的是自然排序(从低到高)。Comparator 更多是自定义排序(例如名字有长短之分) Set set=new TreeSet(com);// com就相当于承载了你的自定义规则,并且给了TreeSet /*Set set=new TreeSet(new Comparator() {--------------->匿名内部类的方法 @Override public int compare(Object o1, Object o2) { Teacher t1=(Teacher)o1; Teacher t2=(Teacher)o2; String name1=t1.getName(); String name2=t2.getName(); if(name1.length() > name2.length()){ return -1; }else if(name1.length() < name2.length()){ return 1; } return 0; } });*/ set.add(new Teacher("will")); set.add(new Teacher("ajksjdhbk")); set.add(new Teacher("MA")); System.out.println(set); } } class NameCom implements Comparator{ @Override public int compare(Object o1, Object o2) { Teacher t1=(Teacher)o1; Teacher t2=(Teacher)o2; String name1=t1.getName(); String name2=t2.getName(); if(name1.length() > name2.length()){ return -1; }else if(name1.length() < name2.length()){ return 1; } return 0; } }^不用Comparable接口的原因是,其采用的是自然排序(从低到高)。Comparator 更多是自定义排序(例如名字有长短之分)。
TreeSet里面应用的排序规则( Comparable和Comparator接口 ): Comparable:自然顺序排序(低–>高):内比较器 比较Set集合中是否是同一个元素的标准。 compareTo方法是否返回0。 Comparator:自定义排序 : 外比较器 比较Set集合中是否是同一个元素的标准。 compare方法是否返回0.
Map不是集合! Map表示一种映射关系: 数学中的定义:有A和B两个集合,A集合中的一个元素,总能在B集合中找到唯一的一个映射值。(B集合中的一个元素,可以被A集合中的多个元素映射)。 Map:多个Entry的集合,一个Entry表示一个键值对,Map表示多个键值对,Map表示多组映射关系。
Map接口对应常用的实现类: Hashtable类:在没有集合框架之前,就使用Hashtable来表示映射关系。现在建议使用HashMap类。通过源码可以看出,Hashtable中的每一个方法都是用synchronized修饰。
HashMap类:底层使用哈希表算法。底层没有用synchronized修饰。 HashMap相对于Hashtable来说,性能较高,但安全性较低。与ArrayList和Vector的区别相同。
LinkedHashMap类:保证Map中的key会记录添加顺序。 TreeMap类:保证Map中的key会按照指定的规则来排序。
通过观察Set和Map的体系,会发现很多实现类的名字相似(底层算法相同)。HashSet的底层就是使用HashMap。 在构建HashSet对象时,底层创建的是一个HashMap对象。 在把元素添加到set时,底层是存放在Map中的。 Map中的key其实就是Set的元素。 Map中所有的key其实就是Set集合。
集合工具类: 1:java.util.Arrays类: Public static List asList(Object… params):把一个数组转换成对应的List集合。 数组转换为List最便捷的方式:List Arrays.asList( Object… params ):其底层还是ArrayList,不过是其内部类。 注意:返回的List的长度是固定的,不能改变。不过,一旦转换成功,该集合就会定长,所以对list进行增加删减操作就会报错,但替换操作不会。
2:java.util.Collections类:操作集合的工具类。 ArrayList,HashSet,HashMap都是线程不安全的类。
// 得到一个线程安全的Set Set set=Collections.synchronizedSet(new HashSet<>()); synchronized (set){ // 对set对象的一些操作 }但是我们平时不经常用,直接在Set方法上加入synchronized就行。 Collections的一些操作:
//返回空集:没有元素的集合 List emptyList= Collections.EMPTY_LIST; // 常量 System.out.println(emptyList); emptyList =Collections.emptyList();//方法 System.out.println(emptyList); list=Arrays.asList(1,2,3,4,5,6); int index=Collections.binarySearch(list,5);//用二分法查找list中的元素,返回索引 System.out.println(index); System.out.println(list); Collections.reverse(list);//对list里的元素从后往前翻转 System.out.println(list); Collections.shuffle(list);//对list里的元素进行随机翻转 System.out.println(list);使用集合但不使用泛型所带来的问题: 1、编译器存在警告。 2、使用Tree类,如何保证只存储同一种数据类型(不是自己主动要求的那种类型)。 3、从集合中取出元素必须强转(或者使用Object)。 泛型:简概为广泛的通用类型,可以实现不同的调用者使用不同的数据类型。 若泛型不指明,就默认为Object类。 解决问题二:例如,想让TreeSet只存储String类型的元素:
Set<String> set = new TreeSet<String>();或Set<String> set = new TreeSet<>();泛型通配符 :? ------------不知道传什么类型。
public static void main(String[] args) { // 泛型通配符 :? ------------不知道传什么类型 List<Object> list1=null; List<Number> list2=null; List<Integer> list3=null; //dowork(list1); 该操作会报错,因为此时在限定泛型上限只接受 Number和其子类 dowork(list2); dowork(list3); dowork1(list1); dowork1(list2); //dowork1(list3); 该操作会报错,因为此时在限定泛型下限限只接受 Number和其父类 } static void dowork(List<? extends Number> list){ // 限定了泛型上限 } static void dowork1(List<? super Number> list){ // 限定了泛型下限 }I/O的类库都在java.io包中。---------->使用I/O的类库必须使用import引入。
Java . io . File类:表示了文件和目录。 Windows系统:表示路径使用\ 。 但是在java中,一根 \ 表示转义符,我们必须写成: \。 路径分割使用 ; 。 Unix 系统:表示路径使用/ ,但是windows也可以用。 路径分割使用 : 。 注意:File表示一个文件/一个文件夹的路径,一旦File对象创建成功,就只能表示指定的路径。
public static void main(String[] args) throws IOException { //创建File对象(使用前三个构造器) File f1=new File("E:/hello/read.txt"); // 判断文件是文件夹(目录)还是文件 if(f1.isDirectory()){ System.out.println("是目录"); } if(f1.isFile()){ System.out.println("是文件"); } //boolean exists()测试此抽象路径名表示的文件或目录是否存在。 System.out.println(f1.exists()); // 创建文件夹 new File("E:/hello/read1.txt").createNewFile();//文件不存在时 new File("E:/hello/t").mkdir();// 目录存在,尾目录不存在 new File("E:/hello1/t1").mkdirs();//创建多级目录 File f1=new File("E:/hello/read.txt"); File f2=new File("E:/hello","read.txt"); // 路径名 文档名 //使用File表示文件夹对象 File dir=new File("E:/hello"); File f3=new File(dir,"read.txt"); //获取文件名称 String fileName=f1.getName(); System.out.println(fileName); //获取文件父目录 String dir=f1.getParent(); System.out.println(dir); //获取文件的路径(相对路径):一般在该项目中找,够用 System.out.println(f1.getPath()); // 获取文件的绝对路径:不在项目中找,就要用这个 System.out.println(f1.getAbsolutePath()); // 获取最后一次修改时间 System.out.println(f1.lastModified()); //修改文件名:boolean renameTo(File dest)重新命名此抽象路径名表示的文件。 f1.renameTo(new File("E:/hello/reads.txt")); }获取当前目录的子文件:
//获取当前目录的子文件 public class FileDemo2 { public static void main(String[] args) { File file=new File("E:\\BaiduNetdiskDownload"); File[] fs=file.listFiles(); for(File f : fs){ System.out.println(f); } System.out.println("--------------------------------------------------------"); //使用递归:获取该目录下的所有文件以及子目录的所有文件 //listAllFiles(file); //列出有哪些盘符 File[] roots=file.listRoots(); for(File f : roots){ System.out.println(f); } } public static void listAllFiles(File file){ System.out.println(file); if(file.isDirectory()) { File[] fs = file.listFiles(); for( File files : fs){ listAllFiles(files); } } } }