集合:Collection体系、Map体系。java
Collection体系:单列集合的共性操做规则。windows
List:列表,能够重复,有下标,拥有特有的迭代器ListIterator。数组
ArrayList:底层是可变数组。增删慢,查询快。不安全安全
LinkedList:底层是链表结构,增删快,查询慢。不安全。有头和尾,特有的头尾操做的方法。能够模数据结构
拟数据结构(堆栈、队列)。学习
Vector:底层是可变数组,增删,查询都慢。安全。被ArrayList代替。this
Enumeration:它是古老的迭代器,被Iterator代替。spa
Set:不能存放重复元素。操作系统
HashSet:底层是哈希表。不保证存取的顺序。保证对象惟一须要依赖对象的hashCode和equals方法。3d
所以给HashSet中存放的对象须要重写Object类中的hashCode和equals方法。
TreeSet:底层是二叉树结构。保证对象惟一和排序须要依赖对象的比较方法(compareTo),对象要具
备比较方法,须要实现Comparable接口。
若是对象具有的比较功能不适合需求,或者对象自己不具有比较功能,这时咱们能够本身指定比较器对象(Comparator)。而后将这个对象传递给TreeSet集合。
LinkedHashSet:它是HashSet的子类,底层是哈希表和链表组合。它能够保证存取的顺序。
Map体系:双列集合的共性操做规则。存放的是具备必定对应关系的数据。key值是不能重复的。
HashMap:底层是哈希表,不保证存取顺序。主要做用在key上。key是自定义对象,须要复写hashCode
和equals方法。
TreeMap:底层是二叉树,做用在key上。key是自定义对象,须要实现Comparable接口,或者给集合
传递Comparator对象。
Hashtable:它底层是哈希表,安全。被HashMap代替。
LinkedHashMap:它是HashMap的子类,能够保证存取的顺序。底层链表和哈希表。
Map集合的遍历,不能直接使用Iterator,而须要将Map集合转成单列集合。
keySet方法,将Map中的全部key取出存放在Set集合中。遍历Set集合,获得每一个key值,而后调用Map中的get方法,进而获取到key对应的value值。
entrySet方法。将Map中的key和value组成Entry对象(key和value对应关系对象)。存储在set中,遍历set集合,获得Entry对象,而后调用getKey和getValue方法获得key和value。
values方法:获取到的是Map中的全部value值,存放在Collection集合中。
能够存放重复元素:
ArrayList:主要用在查询较多的时候。
LinkedList:主要是根据头尾操做时。
Vector:基本不用
不能够出现重复元素:
HashSet: 对数据的存取顺序没有要求
LinkedHashSet:保证存取顺序
TreeSet:对其中的数据排序
数据具备对应关系:
HashMap: 对数据的存取顺序没有要求
TreeMap: 对其中的数据排序
Hashtable: 基本不用
LinkedHashMap:保证存取顺序
在使用集合的时候,因为集合中存放的元素没有作任何的限制,所以能够将任何对象保存到集合中。这样会致使在从集合中取出对象的时候,对象都被提高为Object类型,若是须要使用对象的特有方法,这时须要向下转型,就有可能发生类型转换异常。
、
集合是容器,数组也是容器,可是数组容器一旦定义完成以后,其中可以存放的数据类型就必定肯定,若是在给数组中存放元素的时候,类型和数组限定的类型不匹配,这时编译就直接报错
上述集合和数组的差别,是由于集合中的元素没有进行类型的限定。
咱们能够想办法给集合中可以存储的元素进行类型的限定,这样若是在给集合中存储元素的时候,类型与限定的类型不一致,就不让程序编译经过。只要程序可以编译经过,确定集合中保存的类型是限定的类型。这样在取出的时候,咱们确定知道取出的元素是什么类型。
解决上述的问题,须要使用JDK中提供的泛型技术。泛型实际上是在限定数据类型的。
泛型的书写格式:
<引用数据类型>
泛型在使用的时候,主要是限定数据类型,程序中加入泛型以后,操做数据的时候,类型必定要和泛型中指定的类型一致。泛型中不能书写基本数据类型(使用对应的包装类型)。
1 * 2 * 泛型技术演示 3 */ 4 5 //自定义比较器 6 class MyComparator implements Comparator<String>{ 7 8 public int compare(String o1, String o2) { 9 int temp = o1.length() - o2.length(); 10 return temp == 0 ? o1.compareTo(o2) : temp; 11 } 12 } 13 public class GeneratorDemo { 14 public static void main(String[] args) { 15 16 //演示泛型在集合中的使用 泛型的菱形技术 17 TreeSet<String> set = new TreeSet<String>( new MyComparator() ); 18 19 set.add("aaaaa"); 20 set.add("aba"); 21 set.add("cb"); 22 set.add("ABC"); 23 set.add("CCB"); 24 set.add("ICBC"); 25 26 //遍历 27 for (Iterator<String> it = set.iterator(); it.hasNext();) { 28 //String s = it.next(); 29 System.out.println(it.next()); 30 } 31 } 32 }
a、 泛型的菱形技术:在定义类型的时候声明的泛型的类型,后面建立对象时须要指定的泛型类型能够省略。
b、 泛型的擦除技术:泛型技术属于编译时期的技术。当前程序编译完成以后,泛型所有被删除。
泛型技术在程序可以使用,缘由是在使用的类或者接口上提供书写泛型的地方。若是类或者接口上没有提供书写泛型的地方,在实际代码中咱们也不能书写。
咱们本身来模拟JDK中能够书写泛型的类或者接口。
咱们本身定义类或者接口的时候,声明<变量>泛型,当在使用这个类或者接口的时候就能够指定具体的类型。
1 /* 2 * 自定义泛型类: 3 * 定义的类上声明泛型。 4 */ 5 /* 6 * 需求:定义类,封装任意类型的数据 7 * 分析: 8 * 能够在类中定义Object类型的变量,接收任意类型的数据 9 * 可是给调用者返回这个数据的时候,数据就被提高成Object类型 10 * 调用者须要本身手动的再向下转型。 11 * 12 * 咱们能够在定义类的时候,在类上定义泛型,让调用者本身类声明保存的数据类型。 13 * 14 * class Data<T> : 在定义类的时候,在类上定义一个泛型参数。 15 * 当使用者使用这类的时候,会指定当前这个参数的类型。 16 * 例如:Data<String> d = new Data<String>(); 17 * 咱们定义的类上的泛型T就被String代替。 18 * 19 * 在类上定义的泛型参数,其实就是一个数据类型,只是尚未被使用的时候 20 * 咱们不知道是什么类型,可是调用者只要建立对象,就会明确这个类型, 21 * 只要程序在运行,泛型类型确定就已经明确。 22 * 所以在类上定义的泛型参数,在类中的任意地方均可以使用。 23 */ 24 class Data<T>{ 25 26 private T data; 27 28 public T getData() { 29 return data; 30 } 31 32 public void setData(T data) { 33 this.data = data; 34 } 35 } 36 37 38 public class Demo2 { 39 public static void main(String[] args) { 40 41 Data<Integer> d = new Data<Integer>(); 42 d.setData(123); 43 44 } 45 }
总结:
泛型类:在定义类的时候,定义泛型参数。在类上定义的泛型参数,在类中可使用。
类上定义的泛型参数,须要在 建立这个类对象的时候明确,若是没有明确这个类型,默认是Object
类型。
方法的定义格式:
修饰符 返回值类型 方法名( 参数类型 变量名 , 参数类型 变量名 ...... ){
方法体
}
方法上定义的泛型格式:
修饰符 <泛型参数> 返回值类型 方法名( 参数类型 变量名 , 参数类型 变量名 ...... ){
方法体
}
1 /* 2 * 泛型方法: 3 * 类上能够定义泛型,在类中是可以直接使用类上定义的泛型。 4 * 5 * 在类中也能够不使用类上的泛型。 6 */ 7 //类上定义泛型 8 class Test2<W>{ 9 10 //在方法上使用泛型 11 public void show(W w){ 12 System.out.println(w); 13 } 14 15 //方法上也能够不使用类上的泛型 16 public void method(int a){ 17 18 } 19 /* 20 * 若是方法上接收的参数类型也不肯定,可是咱们知道方法上 21 * 接收的参数类型和类上定义的泛型的类型不一致, 22 * 这时能够在方法上单独去定义适合这个方法本身的泛型 23 * 24 */ 25 public <Q> void function( Q q ){ 26 System.out.println(q); 27 } 28 29 } 30 public class Demo3 { 31 public static void main(String[] args) { 32 33 Test2<Double> t = new Test2<Double>(); 34 //使用拥有泛型的方法 35 t.function('a'); 36 37 } 38 }
静态方法不能使用类上定义的泛型。由于类上的泛型类型须要在建立这个类的对象时明确。而静态方法运行时候能够没有对象。
在定义接口的时候,能够在接口上定义泛型参数。
1 /* 2 * 演示接口上定义泛型 3 */ 4 //在接口上定义了泛型参数 5 interface Inter<P>{ 6 public void show(P p); 7 } 8 /* 9 * 接口的实现类,在实现接口的时候,明确接口上泛型的具体数据类型 10 */ 11 class InterImpl implements Inter<String>{ 12 13 public void show(String p) { 14 15 } 16 }
接口上的泛型:在实现接口的时候明确具体的数据类型。
interface Collection<E>{}
interface List<E> extends Collection<E>{}
class ArrayList<E> implements List<E>{}
开发者本身的类:ArrayList<String> list = new ArrayList<String>();
1 /* 2 * 演示泛型的通配符技术: 3 * 通配符:通通都匹配的符号。使用一个符号去匹配其余的数据。这个符号被称为通配符 4 * 5 * 泛型的通配符符号:?号 ;当接收的数据的时候,若是须要使用泛型,殊不知道当前应该 6 * 书写什么数据类型的时候,这时可使用?表示。 7 */ 8 public class GenericTest { 9 public static void main(String[] args) { 10 11 List<String> list = new ArrayList<String>(); 12 Collections.addAll(list, "aa", "bb", "cc", "dd"); 13 printCollection(list); 14 15 Set<Integer> set = new HashSet<Integer>(); 16 Collections.addAll(set, 11, 22, 33, 44, 55, 66, 77); 17 // 打印集合 18 printCollection(set); 19 } 20 21 //泛型的通配符 22 public static void printCollection( Collection<?> list ) { 23 // 打印集合 24 for (Iterator it = list.iterator(); it.hasNext();) { 25 System.out.println(it.next()); 26 } 27 } 28 29 }
1 /* 2 * 演示泛型的通配符技术: 3 * 通配符:通通都匹配的符号。使用一个符号去匹配其余的数据。这个符号被称为通配符 4 * 5 * 泛型的通配符符号:?号 ;当接收的数据的时候,若是须要使用泛型,殊不知道当前应该 6 * 书写什么数据类型的时候,这时可使用?表示。 7 */ 8 public class GenericTest2 { 9 public static void main(String[] args) { 10 11 List<Teacher> list = new ArrayList<Teacher>(); 12 list.add(new Teacher("老唐",18)); 13 list.add(new Teacher("老张",28)); 14 list.add(new Teacher("花和尚",38)); 15 list.add(new Teacher("圣手书生",28)); 16 //printCollection(list); 17 18 19 Set<Student> set = new HashSet<Student>(); 20 set.add(new Student("班长",38)); 21 set.add(new Student("班花",18)); 22 set.add(new Student("班草",28)); 23 set.add(new Student("班导",48)); 24 printCollection(set); 25 26 27 Set<Person> set2 = new HashSet<Person>(); 28 set2.add(new Person("班长",38)); 29 set2.add(new Person("班花",18)); 30 set2.add(new Person("班草",28)); 31 set2.add(new Person("班导",48)); 32 printCollection(set2); 33 34 } 35 /* printCollection( Collection<?> coll ) 这个方法能够接收任何的Collection下的集合容器 36 * 而且能够将其中的说打印出来。 37 * 38 * printCollection 只打印集合中保存的数据是Person或者Person的子类数据 39 * 若是传递的集合中给出的数据不是Person或者Person的子类,就不接受这样的数据。 40 * 41 * 泛型的限定: 42 * 上限限定: ? extends E 当前的?表示的数据类型能够是E类型,也能够是E的子类类型 43 * 例如:? extends Person 当前的?能够是Person类型或者Person的子类类型 44 * 45 * 下限限定:? super E 当前的?表示的数据类型能够是E自己类型,或者E的父类类型 46 * 例如:? super Student 当前的?能够是Student类型或者Student的父类类型, 47 * 但不能是Student的子类或者兄弟类型 48 * 49 * TreeSet(Comparator<? super E> comparator) 50 * TreeSet(Collection<? > c) 51 * 52 * public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) 53 */ 54 public static void printCollection( Collection<? super Student> coll ) { 55 56 for (Iterator it = coll.iterator(); it.hasNext();) { 57 System.out.println(it.next()); 58 } 59 } 60 61 }
class TreeSet<E>{
public TreeSet( Collection<? exntends E> c ){
}
}
当在程序中咱们建立TreeSet集合对象的时候,须要明确TreeSet上定义的泛型的具体类型。若是已经明确的了具体的类型,那么构造方法上使用的E,就能够明确的类型一致。
建立TreeSet对象:
TreeSet<Person> set = new TreeSet<Person>( 传递集合数据 );
就意味着TreeSet集合中全部使用E的地方都会变成Person类型。
构造方法上的Collection<? extends Person> ,限定当前能够给集合中保存的数据是Person或者Person的子类。
上面是TreeSet的构造方法,它的目的是在建立TreeSet集合对象的时候,将Collection集合中的数据添加到TreeSet集合中。
而建立TreeSet集合时咱们设定集合中添加的数据类型应该Person类型,那么就说明Collection中的元素可以添加到TreeSet中,Collection中的数据要么是Person类型,要么是Person子类类型。
建立TreeSet对象的时候,会明确E的类型,同时还能够给TreeSet传递一个比较器对象。
传递的比较器是用来比较正要给集合中保存的数据和已经在集合中的数据的大小。
TreeSet<Student> set = new TreeSet< Student >(); 声明TreeSet上的泛型E为Student类型。
set.add(new Student(“zs”,23));
set.add(new Student(“ls”,33));
至关于要把第二个Student和第一个Student对象传递给Comparator中的compare方法进行比较大小。
compare方法须要接收当前这两个Student对象。
public int compare( Person o1 , Person o2 ){
}
Comparator接口中的compare方法主要任务的接收给集合中存储的元素和已经在集合中的元素数据,而后对其进行比较。
compare方法上负责接收2个对象的那个类型能够和集合中的数据类型一致,或者是集合中数据类型的父类型也能够。
所以得出:TreeSet构造方法上传递的Comparator接口能够接收的数据类型能够和集合一致,或者集合中的数据类型的父类类型。
咱们的数据所有存储在计算机的内存中。当程序运行结束以后,数据就所有消失。下次程序启动的时候,若是须要上次运行的结果数据,这时是没法获取到的。
咱们须要在 程序中加入其它的技术,将程序中的有效的数据长久的保存起来,之后程序启动的时候能够读取这些数据,接着进行处理。
须要将数据长久保存,就须要使用Java中提供的IO技术。
IO技术:
I:Input 输入,读取操做
O:Output 输出,写操做。
数据从其余的设备上被加载到内存中的这个过程被称为输入(读取)操做。
数据从内存中输出到其余的设备上的这个过程被称为输出(写)操做。
一、 学习如何操做硬盘上的文件或者文件夹
二、 学习如何读写文件中的数据。
注意:IO操做中的数据方向,而后肯定最后须要使用的类或接口中的方法。
数据须要保存在文件中,而文件多了,就须要文件夹进行管理。也就是说文件或者文件夹是咱们长久保存数据的设备上存在的一类事物。
Java确定会有一个类多这个事物进行描述。
Java中使用File类描述文件或者文件夹这个事物。
只要在java中须要操做硬盘上的文件或者文件夹就应该使用File类。
1 /* 2 * 演示File类中的构造方法 3 */ 4 public class FileConstructorDemo { 5 public static void main(String[] args) { 6 method3(); 7 } 8 /* 9 * File(File parent, String child) 10 * File parent 已经将父目录封装成File对象, 11 * String child 文件或者文件夹 12 */ 13 public static void method3() { 14 15 //封装的父目录 16 File dir = new File("d:/abc/bbb/ccc"); 17 18 //将父目录下的文件或文件夹封装成File对象 19 File file = new File(dir , "1.txt"); 20 21 System.out.println(file); 22 } 23 /* 24 * File(String parent, String child) 25 * String parent 当前文件或者文件夹所在的父目录 26 * String child 是当前的文件或者文件夹 27 * 注意: 28 * 在windows中,目录(文件夹)之间的使用的是\ 做为默认分隔符 29 * 咱们能够可使用 / 做为分隔符 30 */ 31 public static void method2() { 32 33 //建立File对象 34 File file = new File("d:/abc","1.txt"); 35 36 System.out.println(file); 37 } 38 /* 39 * File(String pathname) 40 * new File("d:/1.txt") 将指定的字符串中的数据封装成File对象 41 * 可是这个字符串中表示的文件或者文件夹究竟是否真实存在, 42 * 建立File对象的时候不会去验证 43 */ 44 public static void method() { 45 46 //建立File对象 47 File file = new File("d:/1.txt"); 48 49 System.out.println(file); 50 } 51 }
1 /* 2 * 演示File类中的 获取 方法 3 * 4 * 举例说明: 5 * 绝对路径:上海市闵行区浦江镇三鲁公路3279号明浦广场3号楼1楼125室 6 * 相对路径:三鲁公路3279号明浦广场3号楼1楼125室 7 * 8 * 绝对路径: 9 * 文件或文件所在的全路径。 10 * 相对路径: 11 * 文件或文件夹相对其余文件而言的路径。 12 * 13 * 例如: 14 * "1.txt" 这时并无说明文件具体在哪一个目录中, 15 * 这时JVM会认为当前的这个文件是相对当前程序所在的项目而言。 16 * "d:/1.txt" 全路径。这时JVM就已经能够识别这个目录的具体位置 17 * /1.txt 它相对的是当前项目所在的文件系统的根目录而言。 18 * 19 */ 20 public class FileGetMethodDemo { 21 public static void main(String[] args) throws IOException { 22 23 File file = new File("abc/1.txt"); 24 25 //getAbsolutePath 获取到的是File对象保存的文件或者文件所在的全路径 26 System.out.println("getAbsolutePath="+file.getAbsolutePath()); 27 System.out.println("getAbsoluteFile="+file.getAbsoluteFile()); 28 // getCanonicalPath 获取到的全路径中的真实目录 29 System.out.println("getCanonicalPath="+file.getCanonicalPath()); 30 //getName 获取到的是File对象中封装的最后一级的名称 31 System.out.println("getName="+file.getName()); 32 // getParent 获取到的最后一级目录以前的全部目录 33 System.out.println("getParent="+file.getParent()); 34 System.out.println("getParentFile="+file.getParentFile()); 35 36 System.out.println("getFreeSpace="+file.getFreeSpace()); 37 System.out.println("getTotalSpace="+file.getTotalSpace()); 38 System.out.println("getUsableSpace="+file.getUsableSpace()); 39 40 //获取操做系统全部的根目录,windows 全部的盘符 41 File[] roots = File.listRoots(); 42 for (File root : roots) { 43 System.out.println(root); 44 } 45 } 46 }
注意:delete方法不走回收站,慎用
6. 判断方法
1 /* 2 * 演示File类中的判断方法 3 */ 4 public class FileDemo3 { 5 public static void main(String[] args) throws IOException { 6 7 File file = new File("d:/1234.txt"); 8 //file.createNewFile(); 9 file.mkdir(); 10 //isDirectory 判断是不是目录(文件夹) 11 System.out.println(file.isDirectory()); 12 //isFile 判断是不是文件 13 System.out.println(file.isFile()); 14 //isHidden 判断是不是隐藏文件或文件夹 15 System.out.println(file.isHidden()); 16 //exists 判断文件或者文件夹是否存在 17 System.out.println(file.exists()); 18 19 } 20 }
上述的方法是能够根据指定的目录(文件夹),获取到这个目录(文件夹)下的全部文件和文件夹数据。
String[] list() 它是获取到指定文件夹下的全部文件和文件夹的名称,将这些名称保存到字符串数组中。
File[] listFiles() 它获取到的是指定的文件夹下的全部文件和文件夹对象,并将这些对象存储在File数组中。
1 /* 2 * 演示获取指定目录下的文件或文件夹名称 3 */ 4 public class ListDemo { 5 public static void main(String[] args) { 6 7 //指定目录 8 File dir = new File("d:/"); 9 10 //列出当前目录下的文件和文件夹的名称保存在字符串数组中 11 String[] list = dir.list(); 12 13 for (String s : list) { 14 System.out.println(s); 15 } 16 17 } 18 } 19 20 /* 21 * 获取指定目录下的文件和文件夹,会将这些文件和文件夹再次封装成File对象 22 * 存储在File数组中 23 */ 24 public class ListFilesDemo { 25 public static void main(String[] args) { 26 //建立File对象 27 File dir = new File("d:/"); 28 29 //列出指定目录下的全部文件和文件夹对象 30 File[] files = dir.listFiles(); 31 32 for (File file : files) { 33 System.out.println(file.isDirectory()); 34 } 35 } 36 }
注意:使用list方法和listFiles方法获取指定目录下的文件和文件夹的时候,若是指定的目录Java没有权限,这时list或listFiles方法返回的结果是null。
1 /* 2 * 获取指定目录下,以及子目录,子子目录(多级目录)下的全部内容 3 */ 4 public class ListFilesTest { 5 public static void main(String[] args) { 6 //获取系统的全部盘符 7 File[] roots = File.listRoots(); 8 for(File root : roots){ 9 //列出每一个盘符下的全部文件 10 getFiles(root); 11 } 12 File dir = new File("d:/"); 13 getFiles(dir); 14 } 15 //获取指定目录下的文件和文件夹 16 public static void getFiles(File dir) { 17 System.out.println("......"+dir); 18 //列出当前这个目录下的文件和文件夹对象 19 File[] files = dir.listFiles(); 20 if( files != null ){ 21 //遍历数组 22 for (File file : files) { 23 //判断当前的file是不是文件夹,是文件夹就须要继续列出其中的文件或文件夹 24 if( file.isDirectory() ){ 25 //判断成立说明当前的file对象必定是文件夹(目录) 26 getFiles(file); 27 }else{ 28 //判断不成立,说明当前的file对象必定是文件 29 System.out.println(file); 30 //file.delete(); 31 } 32 } 33 } 34 } 35 }