Tinking in java 琐碎知识点之集合(容器)

来源:互联网 发布:复利农场源码 编辑:程序博客网 时间:2024/05/21 10:38

1、Iterator必须依附于Collection接口的对象,Iterator本身不提供盛装对象的能力。Collectionname.iterator()方法获得Iterator接口实现类的对象

2、除了使用Iterator遍历Collection集合里的元素,也可以使用foreach循环(注意类型转换)

3、Set接口不允许包含重复元素(根据equals方法判断),而Collection没有此限制。Set接口的两个实现类HashSet是使用的哈希算法决定元素的存储位置,而treeSet使用的是红黑树算法。

4、Object类中定义了hashCode和equals方法,equals方法按照内存地址比较两个对象是否相等,hashCode方法返回值是根据内存地址计算出来的,所以同一个对象hashCode一样。HashSet是通过equas方法和hashCode方法判断两个元素是否相等的,将一个对象放入HashSet中时,HashSet会调用对象的的hashCode方法获得哈希码,再根据这个哈希码计算出对象在集合中存放的位置。因此如果重写了对应类的equals方法则也应该重写hashCode方法,保证如果2个对象通过equals比较相等那这两个对象的hashCode也应该一样,否则HashSet无法正常工作。
  (即使两个对象equals方法返回true而hashCode不同也可以添加成功,使HashSet无法正常工作)

5、TreeSet集合是SortSet接口的唯一实现,TreeSet集合里的元素处于排序状态。试图把一个对象添加进TreeSet时,则该对象的类必须实现comparable接口,因为TreeSet会调用集合的元素的compareTo(Object obj)方法来比较元素之间的大小关系。
TreeSet自然排序是根据元素的大小以升序排序,也可以使用定制排序,即不用将类实现Comparable接口了,直接在创建TreeSet集合对象时提供一个Comparator对象作为TreeSet构造器参数,由该Comparator对象实现集合元素的排序逻辑。

6、compareTo(Object obj)方法返回一个整数值,如果obj1.compareTo(obj2)返回0,则表明这两个对象相等。返回一个正整数则表明obj1>obj2,如果返回一个负整数,则obj1<obj2

7、集合里的元素总是引用,但习惯上把被引用的对象称为集合元素

8、在实际应用中TreeSet集合里的对象属性被改变了不会重新排序,也就是说排序只是在元素加进集合时。所以最适合用treeSet排序的是不可变类。

9、为了保持Set规则的一致性,即Set集合中的元素总是不重复的,我们应该尽量保证两个对象通过equals方法和compareTo方法比较的结果一致(还要重写hashCode方法)。

10、关于Set的小结
    HashSet性能比TreeSet好(特别是添加、查询操作),只有当要一个保持排序的Set时才应该使用TreeSet
    EnumSet性能虽好,但是它只能保存同一个枚举类的枚举值作为集合参数

11、List接口
    ArrayList和Vector都是List的实现类(Vector老了,虽然它是线程安全的都是也不推荐使用),ArrayList不是线程安全的,得手动控制,
    Vector有个Stack子类,可以模拟栈这种数据结构。LinkedList也是一个List的实现类,它是基于链表实现的List

12、LinkedList和ArrayList、Vector的实现机制完全不同,ArrayList、Vector内部以数组的形式来保存集合中的元素,因此随机访问集合元素有较好的性能,而LinkedList内部以链表的形式来保存集合元素,随机访问性能差,但是插入删除元素时性能出色。

13、HashMap和Hashtable都是Map接口的实现类,他们的关系类似于ArrayList和Vector,Hashtable老了,用起来也不方便。另外Hashtable是线程安全的,HashMap是线程不安全的。(即使要使用线程安全的实现类也不必使用HashTable和Vector,有Collections工具)

14、为了在HashMap和Hashtable中存储、获取对象,用作key的对象必须实现hashCode和equals方法。HashMap和Hashtable判断两个key相等的标准是:两个key 通过equals方法返回true,通过hashCode方法返回值相等。而它们判断两个value是否相等则只要通过equals对象返回true即可。
(当重写了一个类的equals方法后,最好也重写一下hashCode方法,以保证一致性)
public class MapTest {public static void main(String[] args) {HashMap<PerId,Person> hm=new HashMap<PerId,Person>();hm.put(new PerId(0001), new Person("周鹏程1",25));hm.put(new PerId(0002), new Person("周鹏程2",25));hm.put(new PerId(0003), new Person("周鹏程3",26));hm.put(new PerId(0004), new Person("周鹏程",27));hm.put(new PerId(0005), new Person("周鹏程",27));System.out.println(hm.containsKey(new PerId(0004)));System.out.println(hm.containsValue( new Person("周鹏程1",25)));System.out.println(hm.remove(new PerId(0001)));for(Object o:hm.keySet()){System.out.println(hm.get(o).name);}}}class Person{String name;int age;public Person(String name,int age){this.name=name;this.age=age;}public boolean equals(Object obj){if(obj==this){return true;}if(obj!=null&&obj.getClass()==Person.class){Person p=(Person)obj;if(p.age==this.age&&p.name==this.name){return true;}}return false;}}class PerId{int id;public PerId(int id){this.id=id;}public boolean equals(Object obj){if(obj==this){return true;}if(obj!=null&&obj.getClass()==PerId.class){PerId p=(PerId)obj;if(p.id==this.id){return true;}}return false;}//假如没有重写hashCode方法将会出现问题public int hashCode(){return id;}}

15、遍历Map中全部key-value对:调用Map对象的keySet方法返回全部key组成的Set对象,再通过遍历Set的元素(get方法获得key对应的    value)就可以遍历Map中所有的key-value对。

16、HashMap、Hashtable保存key的方式和HashSet保存集合元素的方式一至,所以HashMap、Hashtable对key的要求与HashSet对集合元素的要求相同。如果重写了该类的equals方法则应该也重写hashCode方法。

17、与HashSet类似的是,尽量不要使用可变对象作为HashMap、Hashtable的key,如果使用了可变对象,则尽量不要在程序中修改作为key的可变对象。

18、Hashtable有一个实用的子类Properties类,在处理属性文件时特别方便。Properties类可以把Map对象和属性文件关联起来,从而可以把Map对象中的key-value写入属性文件,也可以把属性文件中的属性名、属性值加载到Map对象中。
例程:
import java.io.*;import java.util.*;public class TestProperties  {public static void main(String[] args)throws Exception {Properties props=new Properties();props.setProperty("username", "zpc");props.setProperty("password", "123456");//将Properties中的属性保存到a.ini对象中props.store(new FileOutputStream("a.ini"), "comment line(属性文件)");Properties props2=new Properties();props2.setProperty("gender", "male");props2.load(new FileInputStream("a.ini"));System.out.println(props2);}} //输出:{password=123456, gender=male, username=zpc}

19、正如Set接口派生出SortedSet子接口,SortedSet接口有一个TreeSet实现类,Map接口有一个SortedMap子接口,SortedMap也有一个TreeMap实现类。与TreeSet类似,TreeMap也是基于红黑树对TreeMap中的所有key进行排序,从而保证TreeMap中所有key-value对处于有序状态。TreeMap也有自然排序(key所在的类实现Comparable接口、所有key应该是同一个类的对象)和客户化(创建TreeMap时传入一个Comparator对象,该对象负责实现排序逻辑)排序两种方式。

20、IdentityHashMap与HashMap基本相似,只是在处理两个key是否相等时不一样:只有当两个key严格相等(key1==key2)时才会认为两个key相等
public static void main(String[] args) {IdentityHashMap ihm=new IdentityHashMap();ihm.put(new String("语文"),89);ihm.put(new String("语文"),78);ihm.put("java",89);ihm.put("java",89);System.out.println(ihm);}//“java”字符串是字符串直接量,放在缓存,而new的两个对象用==比较不等

21、操作集合工具类Collections提供了一些方法对集合元素进行排序、查询和修改操作,还提供了将集合对象设置成不可变、对集合对象实现同步控制等方法。

//showHand游戏import java.util.*;class ArrayUtils {/** * 定义一个工具方法,工具方法从字符串数组中找到对应的字符串元素的位置 *  * @param array *            搜索的数组 * @param target *            搜索的字符串 * @return 目标字符串出现的位置,-1表明找不到 */public static int search(String[] array, String target) {for (int i = 0; i < array.length; i++) {if (array[i] != null && array[i].equals(target)) {return i;}}return -1;}}public class ShowHand {private final int PLAY_NUM = 4;// 限定玩家数量private String[] types = { "\4 ", "\5", "\3", "\6" };//特殊字符,会在控制台打印出方块、草花、红心和黑桃private String[] values = { "2", "3", "4", "5", "6", "7", "8", "9", "10","J", "Q", "K", "A" };// cards存放牌private List<String> cards = new LinkedList<String>();// 用一个数组存放玩家private String[] players = new String[PLAY_NUM];// 每一个玩家都用一个List存放其获得的牌private List<String>[] playersCards = new List[PLAY_NUM];// 初始化,放入扑克牌public void initCards() {for (int i = 0; i < types.length; i++) {for (int j = 0; j < values.length; j++) {cards.add(types[i] + values[j]);}}// 调用集合工具类的方法随机排列Collections.shuffle(cards);}// 初始化玩家,为每个玩家分配用户名public void initPlayer(String... names) {if (names.length < 2 || names.length > PLAY_NUM) {System.out.println("输入玩家数量不对!");return;} else {// 初始化用户for (int i = 0; i < names.length; i++) {players[i] = names[i];}}}// 初始化保存玩家牌的Listpublic void initPlayerCards() {for (int i = 0; i < players.length; i++) {if (players[i] != null && !players.equals("")) {playersCards[i] = new LinkedList<String>();}}}// 写一个输出全部扑克牌的方法public void showAllCards() {for (String card : cards) {System.out.println(card);}}// 给玩家派牌的方法(指定一个最先派牌的玩家)public void deliverCard(String first) {int firstPos = ArrayUtils.search(players, first);//依次给位于指定玩家之后、之前的每个玩家派牌for(int i=firstPos;i<players.length;i++){if(players[i]!=null){playersCards[i].add(cards.get(0));cards.remove(0);}}//为之前的每个玩家派牌for(int i=0;i<firstPos;i++){if(players[i]!=null){playersCards[i].add(cards.get(0));cards.remove(0);}}}//输出玩家手中的牌public void showPlayerCards(){System.out.print("当前牌况:");for(int i=0;i<players.length;i++){if(players[i]!=null){System.out.println("\n"+players[i]+":");for(String card:playersCards[i]){System.out.print (card+"\t");}}}System.out.print("\n");}public static void main(String[] args) {ShowHand sh = new ShowHand();sh.initCards();sh.initPlayer("鸟鹏", "鸟朱");sh.initPlayerCards();sh.showAllCards();System.out.println("*****************");//第一次从玩家鸟鹏开始派牌sh.deliverCard("鸟鹏");sh.showPlayerCards();//第二次从玩家鸟朱开始派牌sh.deliverCard("鸟朱");sh.showPlayerCards();}}


22、泛型:JDK1.5支持的泛型很大程度上是为了让集合能记住其元素的类型,这样会带来许多好处(Java泛型可以保证如果程序在编译的时候没有警告,运行时就不会产生ClassCastException异常,集合中默认存放的都是object对象,取出来还得强制转型,使用泛型就不要了)。

//一个泛型的案例public class Apple<T> {private T info;public Apple() {}public Apple(T info){this.info=info;}public T getInfo(){return info;}public static void main(String[] args){//因为传给T形参的是String实际类型,所以构造器的参数只能是StringApple<String> apple1=new Apple<String>("苹果");System.out.println(apple1.getInfo());System.out.println(apple1.getClass());Apple<Double> apple2=new Apple<Double>(12.9);System.out.println(apple2.getInfo());System.out.println(apple2.getClass());}}//输出//苹果//12.9


泛型数组(Java允许创建无上限的通配符泛型数组):

List<?>[] lsa= new ArrayList<?>[10];Object[] oa=(Object[])lsa;List<Integer> li=new ArrayList<Integer>();li.add(new Integer(7));oa[1]=li;System.out.println("lsa.getClass():"+lsa.getClass());System.out.println("lsa[1].get(0).getClass():"+lsa[1].get(0).getClass());//String s=(String)lsa[1].get(0);//List的get方法Object target=lsa[1].get(0);if(target instanceof String){String s=(String)target;}

23、注意:在使用带了泛型声明的接口、父类之后,在使用这些接口或父类时不能再包含类型形参(方法中的形参只有当定义方法时才使用数据形参,当调用(使用)方法时必须传入实际的数据;与此类似的是:类、接口中的类型参数只有在定义类、接口时才可以使用类型参数,当使用类、接口时应该为类型参数传入实际的类型)。
如上例继承Apple类时可以有两种写法
public class A extends Apple<String>{}
或者直接不写<T>即:public class A extends Apple{}
数组和泛型有所不同,假设Son是Father的一个子类型(子类或者子接口),那么Son[]依然是Father[]的一个子类型,但是C<Son>并不是C<Father>的一个子类型。


24、使用类型通配符

(设定类型通配符的上限)比如List<? extends Shape>表示所有Shape泛型List的父类,List集合的元素要么是Shape类型的要么是Shape的子类型都行
(设定类型形参的上限)也可以在定义类时设定类型上限:public class Apple<T extends Number>。
也可以使用泛型方法:
修饰符 <T,S> 返回值类型 方法名(形参列表)
{
  //方法体
}
例程:abstract class Shape{public abstract void draw(Canvas c); } class Circle extends Shape{@Overridepublic void draw(Canvas c) {System.out.println("在画布"+c+"画一个圆");}}class Rectangule extends Shape{@Overridepublic void draw(Canvas c) {System.out.println("在画布"+c+"画一个矩形");}}public class Canvas {//同时在画布上绘制多个形状//使用被限制的泛型通配符public void drawAll(List<? extends Shape> shapes){for(Shape s:shapes){s.draw(this);}}public static void main(String[] args) {List<Circle> circleList=new ArrayList<Circle>();List<Rectangule> rectangule=new ArrayList<Rectangule>();circleList.add(new Circle());rectangule.add(new Rectangule());Canvas c=new Canvas();c.drawAll(circleList);c.drawAll(rectangule);}}


























0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 吃多了反胃想吐怎么办 抽烟胃恶心想吐怎么办 孕妇7个月头疼怎么办 我的世界狗死了怎么办 户户通搜不到台怎么办 两车相撞我全责怎么办 我全责自己的车怎么办 没有我你怎么办 酷我 仿古砖上的水泥怎么办 异界气息的ss怎么办 前夫威胁我我该怎么办 怀孕了不确定孩子是谁的怎么办 怀孕了不是老公的怎么办 吃油了反胃想吐怎么办 微盘又不能用怎么办 人在无助的时候怎么办 当人迷茫的时候怎么办 当你没钱的时候怎么办 最无助的时候能怎么办 心累了怎么办的句子 人的心累了怎么办 心累了怎么办幽默回答 书法印章盖反了怎么办 手机看yy直播卡怎么办 电脑看yy直播卡怎么办 手机yy直播很卡怎么办 dnf打团网络卡怎么办 dnf打团网络冲突怎么办 苹果6s听筒声音小怎么办 手机传话器坏了怎么办 微信不能发语音怎么办 台式电脑声卡坏了怎么办 微信说话声音小怎么办 微信不能语音了怎么办 微信不能发语音怎么办? 苹果6话筒声音小怎么办 微信视频杂音大怎么办 微信语音有杂音怎么办 苹果手机音频坏了怎么办 苹果手机送话器坏了怎么办 苹果7听筒声音大怎么办