容器
容器Collection, 底下有两个接口:Set 和 List
Set:无序不可重复
List:有序可重复
容器Map, 键值段, 一个key对应一个value
ArrayList, LinkedList, Vector
ArrayList底层实现是数组,所以查询较快,而插入较慢。(每插入一个值,之后的索引和值全部要依次延后)
LinkedList底层实现是链表,所以查询慢,而修改和删除块。链表结构是一个链着一个,查询的时候是挨个往后找,所以较慢。而插入新元素的时候只需要断开某个链,重连上新元素。所以修改插入快,而查询慢。
Vector,底层实现也是数组。线程安全,但效率低。ArrayList和LinkedList线程都不安全。
ArrayList
public classTestDemo {public static voidmain(String[] args) {//ArrayList容器
Employee e = new Employee(0001, "Jack", 5000, "Associate", "2017-12");
Employee e1= new Employee(0002, "Rose", 2000, "Intern", "2020-12");
Employee e2= new Employee(0003, "Tom", 10000, "Senior", "2012-12");//泛型,这里的list就只能存储employee对象了
List list = new ArrayList();
list.add(e);
list.add(e1);
list.add(e2);
}//这里的Employee类一般被称为Javabean,也称实体类(只有属性,构造器和相关getter, setter方法)
}
View Code
HashMap, HashTable
HashMap线程不安全,效率高
HashTable线程安全,效率低
Map
public classTestDemo {public static voidmain(String[] args) {//一个map对象对应一行记录
Map map = newHashMap();
map.put("id", 0001);
map.put("name", "Jack");
map.put("salary", 5000);
map.put("title","Associate");
map.put("HireDate","2017-12");
Map map2= newHashMap();
map.put("id", 0002);
map.put("name", "Rose");
map.put("salary", 2000);
map.put("title","Intern");
map.put("HireDate","2020-12");
Map map3= newHashMap();
map.put("id", 0003);
map.put("name", "Tom");
map.put("salary", 10000);
map.put("title","Senior");
map.put("HireDate","2012-12");
}//不用专门构建类, 用类的属性做key
View Code
遍历List, 迭代器 Iterator
/**
*遍历list和set*/
public classTestDemo {public static voidmain(String[] args) {
List list= newArrayList();
list.add("aaaaa");
list.add("bbb");
list.add("ccccc");//遍历一个list, 可以用for循环
for (int i=0; i
System.out.println(list.get(i));
}//如果是要遍历set, 因为set是无序的,所以for循环不好用了,用Iterator, 迭代器
Set set = newHashSet();set.add("adsa");set.add("adsadd");set.add("adsdasdas");
Iterator iter= set.iterator();while(iter.hasNext()){
String result=(String) iter.next();
System.out.println(result);
}
}
}
View Code
遍历Map
/**
* for each 和Interator遍历map*/
public classTest {//for-each循环中遍历keys或values。//如果只需要map中的键或者值,你可以通过keySet或values来实现遍历,而不是用entrySet。
Map map = new HashMap();//遍历map中的键
for(Integer key : map.keySet()) {
System.out.println("Key =" +key);}//遍历map中的值
for(Integer value : map.values()) {
System.out.println("Value =" +value);
}//使用Iterator遍历//1. 使用泛型:
Map map = new HashMap();
Iterator> entries =map.entrySet().iterator();while(entries.hasNext()) {
Map.Entry entry =entries.next();
System.out.println("Key =" + entry.getKey() + ", Value =" +entry.getValue());
}//2. 不使用泛型:
Map map = newHashMap();
Iterator entries=map.entrySet().iterator();while(entries.hasNext()) {
Map.Entry entry=(Map.Entry) entries.next();
Integer key=(Integer)entry.getKey();
Integer value=(Integer)entry.getValue();
System.out.println("Key =" + key + ", Value =" +value);
}
}
View Code
泛型
泛型的作用:
1、安全:在编译的时候检查类型安全
2、方便:所有的强制类型转换都是自动的和隐式的,提高代码的重用率
/**
泛型类,在声明类时声明(加一个括号)
T Type
K V表示Key Value
E 表示element
? 表示不确定类型
在使用时确定类型
注意:
1、泛型只能使用引用数据,不能是基本类型(只能是Integer, 不能是int)
2、泛型声明时字母不能使用静态属性,静态方法
**/
public class Student {private T1 numericScore; //数字分数
private T2 AlphabeticScore; //字母分数
publicT1 getNumericScore() {returnnumericScore;
}public voidsetNumericScore(T1 numericScore) {this.numericScore =numericScore;
}publicT2 getAlphabeticScore() {returnAlphabeticScore;
}public voidsetAlphabeticScore(T2 alphabeticScore) {
AlphabeticScore=alphabeticScore;
}public static voidmain(String[] args) {//使用时指定类型
Student stu = new Student();//安全,类型检查
stu.setAlphabeticScore("A-");
stu.setNumericScore(92.33);//方便,自动类型转换
double it =stu.getNumericScore();
}
}/**
泛型接口,字母只能使用在方法中,不能使用在全局变量*/
public interface Comparator{voidcompare(T t);
}
View Code
HashMap经典储存,分拣,面向对象
/**
*定义一个student类,属性为: name, classNumber, Score
* 然后将若干student对象放入list中
* 统计每个班级的总分和平均分,分别打印出来*/
public classTestDemo {public static voidmain(String[] args) {
List studentList = new ArrayList();
exam(studentList);
Map rooms = new HashMap();
countScore(rooms,studentList);//打印总分,平均分
printScore(rooms);
}/***
* 将student对象放入list*/
public static void exam(ListstudentList){
studentList.add(new Student("a","001",80));
studentList.add(new Student("b","002",90));
studentList.add(new Student("c","002",70));
studentList.add(new Student("d","001",100));
studentList.add(new Student("e","003",78));
studentList.add(new Student("f","003",82));
studentList.add(new Student("g","003",96));
}/**
*统计分数*/
public static void countScore(Map rooms, ListstudentList){for(Student student: studentList){
String classNumber=student.getClassNumber();double score =student.getScore();//根据班级编号查看Map是否存在该班级,分拣思路
ClassRoom room = rooms.get(classNumber);if (null ==room){
room= newClassRoom(classNumber);
rooms.put(classNumber, room);
}//储存总分
room.setTotal(room.getTotal() +score);
room.getStudentList().add(student);//加入学生
}
}//打印总分与平均分
public static void printScore (Maprooms){
Set> entrySet =rooms.entrySet();
Iterator> iter =entrySet.iterator();while(iter.hasNext()){
Map.Entry entry =iter.next();
ClassRoom room=entry.getValue();double avg = room.getTotal() /room.getStudentList().size();
System.out.println("ClassNumber is" + room.getClassNumber() + "Total Score is" +room.getTotal()+ "Average score is" +avg);
}
}
View Code
自定义类型排序
1、实体类: 实体类实现java.lang.Comparable接口 + 重写 compareTo方法
2、业务排序类:java.util.Comparator + compare
Comparable vs Comparator
Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。 Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。
两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。
推荐第二种,原因如下:
1、解耦:与实体类分离
2、方便应对多变的排序规则
第一种,Comparable
public class Person implements Comparable{
String name;intage;public Person(String name, intage)
{
super();this.name =name;this.age =age;
}publicString getName()
{returnname;
}public intgetAge()
{returnage;
}
@Overridepublic intcompareTo(Person p)
{return this.age-p.getAge(); //重写compareTo方法,按年龄比较大小
}public static voidmain(String[] args)
{
Person[] people=new Person[]{new Person("xujian", 20),new Person("xiewei", 10)};
System.out.println("排序前");for(Person person : people)
{
System.out.print(person.getName()+":"+person.getAge());
}
Arrays.sort(people);
System.out.println("\n排序后");for(Person person : people)
{
System.out.print(person.getName()+":"+person.getAge());
}
}
}
View Code
第二种,comparator, 比较规则与实体类分离,解耦
/**
* 自定义数据排序*/
public classGoodsApp {public static voidmain(String[] args) {
List goods = new ArrayList();
goods.add(new Good("Car", 100000, 500));
goods.add(new Good("Plane", 1000000, 10));
goods.add(new Good("Bike", 100, 3248293));
System.out.println("排序前..." + "\n" +goods);
System.out.println();
Collections.sort(goods,new GoodsPriceSort());//前面是需要排序的内容,后面是排序规则
System.out.println("排序后..." + "\n" +goods);
}
}//运行结果:
排序前...
[GoodName: Car, AddToFavorite:500, price: 100000.0, GoodName: Plane, AddToFavorite:10, price: 1000000.0, GoodName: Bike, AddToFavorite:3248293, price: 100.0]
排序后...
[GoodName: Plane, AddToFavorite:10, price: 1000000.0, GoodName: Car, AddToFavorite:500, price: 100000.0, GoodName: Bike, AddToFavorite:3248293, price: 100.0]/**
* 一个简单的商品实体类*/
public classGood {privateString name;private doubleprice;private intaddFavorite;publicGood() {
}public Good(String name, double price, intaddFavorite) {this.name =name;this.price =price;this.addFavorite =addFavorite;
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}public doublegetPrice() {returnprice;
}public void setPrice(doubleprice) {this.price =price;
}public intgetAddFavorite() {returnaddFavorite;
}public void setAddFavorite(intaddFavorite) {this.addFavorite =addFavorite;
}
@OverridepublicString toString() {return "GoodName:" + name +", AddToFavorite:" + this.addFavorite + ", price:" + this.price + "\n";
}
}/**
* 一个用来描述排序规则的类(按价格排序)*/
public class GoodsPriceSort implements java.util.Comparator{
@Overridepublic intcompare(Good o1, Good o2) {//表示如果结果〉0,返回1,相等,返回0,否则返回1//默认是升序,想要降序,所以前面加个负号
return -(o1.getPrice() - o2.getPrice()>0?1:o1.getPrice() == o2.getPrice()?0:-1);
}
}
View Code
TreeSet和TreeMap
TreeSet: 是Set接口的一个实现类,数据不可重复,数据元素可以排序。 对比HashSet: 元素必须重写hashcode和equals方法;
去重:元素比较为0则去重
排序的两种思路:
1、元素本身可以排序,使用Java.lang.Comparable + compareTo
2、排序业务类,用一个类定义排序规则,使用Java.util.Comparator + compare
TreeSet实际就是实现了Comparator接口的一个业务类
/**
* 注意:TreeSet是在添加数据时排序,如果你更改数据,比如这里把路人甲的指数修改为101,并不改变原来的排序顺序
* 所以,在使用TreeSet时,不要修改数据,可以用Final严格修饰*/
public classTreeSetDemo {public static voidmain(String[] args) {
Person p1= new Person("You", 1);
Person p2= new Person("刘德华", 100);
Person p3= new Person("吴彦祖", 99);
Person p4= new Person("路人甲", 50);//依次放入TreeSet容器中,使用排序的业务类(匿名内部类)
TreeSet persons = new TreeSet(new java.util.Comparator(){public intcompare(Person o1, Person o2){return o1.getHandsomeIndex() -o2.getHandsomeIndex();
}
}//匿名内部类
);//TreeSet在添加数据时排序
persons.add(p1);
persons.add(p2);
persons.add(p3);
persons.add(p4);
System.out.println(persons);
}
}/**
* 实体类实现Comparable接口,重写compareTo方法*/
public class Worker implements java.lang.Comparable{privateString position;private doublesalary;public Worker(String position, doublesalary) {this.position =position;this.salary =salary;
}publicWorker() {
}publicString getPosition() {returnposition;
}public voidsetPosition(String position) {this.position =position;
}public doublegetSalary() {returnsalary;
}public void setSalary(doublesalary) {this.salary =salary;
}
@Overridepublic intcompareTo(Worker o) {return this.salary>o.salary?1:(this.salary==o.salary?0:-1);
}
}public classTreeSetDemo2 {public static voidmain(String[] args) {
Worker w1= new Worker("Clerk", 5000);
Worker w2= new Worker("Engineer", 10000);
Worker w3= new Worker("Manager", 30000);
Worker w4= new Worker("Head", 50000);
TreeSet workers = new TreeSet();
workers.add(w1);
workers.add(w2);
workers.add(w3);
workers.add(w4);
System.out.println(workers);
}
}
View Code
相同点:
TreeMap和TreeSet都是有序的集合,也就是说他们存储的值都是排好序的。
TreeMap和TreeSet都是非同步集合,因此他们不能在多线程之间共享,不过可以使用方法Collections.synchroinzedMap()来实现同步
运行速度都要比Hash集合慢,他们内部对元素的操作时间复杂度为O(logN),而HashMap/HashSet则为O(1)。
不同点:
最主要的区别就是TreeSet和TreeMap分别实现Set和Map接口
TreeSet只存储一个对象,而TreeMap存储两个对象Key和Value(仅仅key对象有序)
TreeSet中不能有重复对象,而TreeMap中可以存在
TreeMap的底层采用红黑树的实现,完成数据有序的插入,排序。
Collections
注意:Collection是一个上层接口,继承它的主要有Set和List
而Collections主要是一个工具类,提供了很多常见的,实用的方法:
Collections.reverse();
Collections.shuffle();
其他容器
队列:Queue单向队列,一端操作 / Deque双向队列,两端操作
/**
* 使用单向队列Queue模拟银行排队存款*/
public classTreeSetDemo {public static voidmain(String[] args) {
Queue que = new ArrayDeque();//模拟排队情况
for(int i = 0; i<10; i++){
finalint num = i; //因为匿名内部类只能访问final修饰的对象,所以这里需要这一步//匿名内部类
que.offer(new Request() { //offer方法给和add方法都是添加一个元素,区别是当队列满了,add抛出异常,offer返回false
@Overridepublic voiddeposit() {
System.out.println("No." + num + "is depositing...");
}
});
}
process(que);
}interfaceRequest{voiddeposit();
}public static void process(Queueque){
Request request= null;while (null!=(request=que.poll())){ //poll方法给和remove方法都是删除第一个元素,区别是当队列为空,remove抛出异常,poll返回Null
request.deposit();
}
}
}//运行结果
No.0 isdepositing...
No.1 isdepositing...
No.2 isdepositing...
No.3 isdepositing...
No.4 isdepositing...
No.5 isdepositing...
No.6 isdepositing...
No.7 isdepositing...
No.8 isdepositing...
No.9 is depositing...
View Code
Hashtable和其子类Properties
HashMap和Hashtable的区别:
1、* Hashtable线程安全,同步,效率低;HashMap线程不安全,非同步,效率高
2、两者父类不同,Hashtable - Dictionary; HashMap - AbstractMap
3、Hashtable键和值不能为null,HashMap键最多一个Null, 值可以多个Null
Properties:
1、经常用于读写配置文件
2、键和值只能为String
常用的方法:
setProperty(String key, String value)
getProperty(String key)
getProperty(String key, String DefaultValue)
存储
后缀:
.properties
store(OutputStream out, String comments)
store(Writer writer, String comments)
.xml
storeToXML(OutputStream os, String comments) //默认使用UTF-8字符集
storeToXMLOutputStream out, String comments, String encoding)
获取
loadFromXML(InputStream in)
public classTestDemo {public static voidmain(String[] args) throws FileNotFoundException, IOException {
Properties pro= newProperties();//存储
pro.setProperty("driver","oracle.jdbc.driver.OracleDriver");
pro.setProperty("url","jdbc:oracle:thin:@localhost:1521:orcl");
pro.setProperty("user","testUser");
pro.setProperty("pwd","123");//存储到e:/others 绝对路径和盘符//存储为properties文件,user = testUser, 直接对等
pro.store(new FileOutputStream(new File("e:/others/db.properties")),"db配置");//存储为xml文件,xml格式
pro.storeToXML(new FileOutputStream(new File("e:/others/db.XMLproperties")),"dbXML配置");//存储为相对路径,和项目摆在一起
pro.store(new FileOutputStream(new File("db.properties")),"db配置"); //不带盘符
pro.store(new FileOutputStream(new File("src/db.properties")),"db配置");//存到src folder底下//读取
pro.load(new FileReader("e:/others/db.properties")); //绝对路径
pro.load(new FileReader("e:/src/db.properties")); //相对路径//获取
String url = pro.getProperty("url","defaultUrl");//根据类路径加载资源配置文件,工作中常用
pro.load(TestDemo.class.getResourceAsStream("/com/test/others/pro/db.properties")); //"/"表示bin目录//当前线程的类加载器
pro.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/test/others/pro/db.properties") ); //""表示bin目录
}
}
View Code
容器的同步控制和只读设置
使容器可以线程安全,使用Collections.synchronizedList();
只读设置:
emptyXXX()
singletonXXX()
unmodifiableXXX()
Guava和Apache:对JDK容器的拓展,工作中常用的工具类
Guava
只读设置:ImmutableList.of
MultiSet.count() //可以计算每个元素出现的次数,非常方便。 //这里和HashSet不同,MultiSet也是无序,但是可重复
MultiMap //同样是键-值。但是键可以重复。//这样就使得我们可以把键和值对调,完成某些数据的统计
/**
* Guava, Multimap*/
public classTestDemo {public static voidmain(String[] args) {
Map courses = new HashMap();
courses.put("Chinese", "Mr.Huang");
courses.put("English", "Mr.Huang");
courses.put("Math", "Mr.Wang");
courses.put("Physics","Mr.Wang");
courses.put("Chemistry", "Mr.Wang");
courses.put("Art", "Ms.Li");//MultiMap
Multimap teachers =ArraryListMultimap.create();//迭代器
Iterator> itr =courses.entrySet().iterator();while(itr.hasNext()){
Map.Entry entry =itr.next();
String key=entry.getKey();
String value=entry.getValue();//转换键和值,存入MultiMap,因为MultiMap的键可以重复,所以不会报错
teachers.put(value, key);
}//查看Multimap
Set keyset =teachers.KeySet();for(String key: keyset){
Collection collection = teachers.get(keys);
System.out.println(key + "--->" +collection);
}
}
}//输出结果
Mr.Huang --->{Chinese, English}
Mr.Wang--->{Math, Physics, Chmistry}
Ms.Li---> {Art}
View Code
Bimap: 键和值都不能重复,Bimap.inverse() 非常实用,可以有效的使键值对调,从而简单的用值找键