1.集合深入
(一)hashSet实现原理:
当我们添加一个元素,HashSet会计算出其Hash值,再根据hash值在哈希表中找出存储他的位置
有两种情况:a.如果算出的hash值在哈希表中位置没有存值,就将其直接存在上面
b.如果算出的额hash值在哈希表中已有存值,会调用该元素的equals方法与该位置的元素再比较一次,返回true,一样不添加,false,添加
例子:测试hashSet添加元素的原理,重写了其equals,hashCode
class Person{ int id; String name; public Person(int id, String name) { super(); this.id = id; this.name = name; } @Override public String toString() { return "{ 编号:"+ this.id+" 姓名:"+ this.name+"}"; } @Override public int hashCode() { System.out.println("=======hashCode====="); return this.id; } @Override public boolean equals(Object obj) { System.out.println("======equals======"); Person p = (Person)obj; return this.id==p.id; } } public class Demo2 { public static void main(String[] args) { /* HashSet set = new HashSet(); set.add("狗娃"); set.add("狗剩"); set.add("铁蛋"); System.out.println("集合的元素:"+ set); */ HashSet set = new HashSet(); set.add(new Person(110,"狗娃")); set.add(new Person(220,"狗剩")); set.add(new Person(330,"铁蛋")); //在现实生活中只要编号一致就为同一个人. System.out.println("添加成功吗?"+set.add(new Person(110,"狗娃"))); System.out.println("集合的元素:"+set); } }
(二)treeSet
注意事项:a.添加元素时,要么元素本身具备了自然顺序的特性;要么实现了Comparable接口,把元素的比较规则定义在compareTo(T o)方法上;
要么在创建treeSet对象时传入一个自定义的比较器
b.要是添加的元素实现了比较器,而创建的treeSet中也传入了自定义的比较器,此时就要依据比较器的优先级
c.对字符串进行排序 的, 因为字符串已经实现了Comparable接口。
字符串的比较规则: 情况一: 对应位置有不同的字符出现, 就比较的就是对应位置不同的字符。
情况二:对应位置上 的字符都一样,比较的就是字符串的长度。
d.自定义比较器:要继承Comparator<T>
//自定义一个比较器
class MyComparator implements Comparator<Emp>{
@Override
public int compare(Emp o1, Emp o2) {
return o1.id-o2.id;
}
}
例子:
class Emp implements Comparable<Emp>{ int id; String name; int salary; public Emp(int id, String name, int salary) { super(); this.id = id; this.name = name; this.salary = salary; } @Override public String toString() { return "{ 编号:"+ this.id+" 姓名:"+ this.name+" 薪水:"+ this.salary+"}"; } //@Override //元素与元素之间的比较规则。 // 负整数、零或正整数,根据此对象是小于、等于还是大于指定对象。 public int compareTo(Emp o) { // System.out.println(this.name+"compare"+ e.name); return this.salary- o.salary; } } //自定义一个比较器 class MyComparator implements Comparator<Emp>{ @Override public int compare(Emp o1, Emp o2) { return o1.id-o2.id; } //根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。 /*@Override public int compare(Object o1, Object o2) { Emp e1 = (Emp) o1; Emp e2 = (Emp) o2; return e1.id - e2.id; }*/ } public class Demo6 { public static void main(String[] args) { //创建一个比较器对象 MyComparator comparator = new MyComparator(); //创建TreeSet的时候传入比较器 TreeSet tree = new TreeSet(comparator); tree.add(new Emp(110, "老陆", 100)); tree.add(new Emp(113, "老钟", 200)); tree.add(new Emp(220, "老汤", 300)); tree.add(new Emp(120, "老蔡", 500)); System.out.println("集合的元素:"+tree); } }
(三)存键值对Map:HashMap;TreeMap跟HashSet,TreeSet唯一的区别就是这个存放的是键值对集合
HashMap,HashTable,ConcurrentHashMap,LinkedHashMap,TreeMap,Vector区别:
HashMap
根据键的hashCode值来存储数据,根据键能直接获取他的值,具有很快的访问速度,遍历取得的数据是完全随机的。因为键对象不可重复,所以HashMap最多只允许一条记录的键为Null,允许多条为null是多线程
HashTable
与HashMap类似,是HashMap线程安全版,支持线程同步,即任一时刻只有一个线程能写HashTable,效率比较低
ConcurrentHashMap
线程安全并且锁分离,内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个hashtable,他们有自己的锁。只有多个修改操作发生在不同的段上,它们就可以并发进行。
LinkedHashMap
保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时
TreeMap
实现了SortMap接口,能够把它保存的记录根据键的顺序,默认是按键值的升需排序,也可以指定排序比较器
Vector增长率100%,arrayList增长率50%
2.泛型
(一)这个概念是在JDK1.5后提出的;
(二)好处:a.将运行的异常提到编译前;b.避免了无谓的强制类型转换
(三)应用:ArrayList<String> list = new ArrayList<String>(); true //两边都有类型, 推荐使用
ArrayList list = new ArrayList<String>(); true
ArrayList<String> list = new ArrayList(); true //只有一边又类型, 不推荐使用,这是为了兼顾新老系统
(四)注意:a.泛型没有多态的概念,左右两边的数据 类型必须 要一致,或者只是写一边的泛型类型
b.在泛型中不能使用基本数据类型,如果需要使用基本数据类型,那么就使用基本数据类型对应的包装类型。
byte----> Byte;short---> Short ;int----> Integer;long----> Long ;double ----> Double
float -----> Float;boolean-----Boolean;char-------》 Character
(五)例子:a.自定义泛型方法:
格式:修饰符 <自定义的泛型声明>返回的类型 方法名(使用自定义的泛型类型 ...){}
public class Demo2 { public static void main(String[] args) { String str = getData("abc"); Integer i = getData(123); } public static <abc>abc getData(abc o){ return o; } }
b.泛型类
格式:class 类名<声明的自定义泛型>{}
注意:1. 在类上自定义泛型的具体数据类型是在使用该类的时候创建对象时候确定的。
2. 如果一个类在类上已经声明了自定义泛型,如果使用该类创建对象 的时候没有指定 泛型的具体数据类型,那么默认为Object类型
3.在类上自定义泛型不能作用于静态的方法,如果静态的方法需要使用自定义泛型,那么需要在方法上自己声明使用。
4.用到泛型就需要声明
例子:
class MyArrays<T>{ //元素翻转 public void reverse(T[] arr){ for(int startIndex = 0, endIndex = arr.length-1 ; startIndex<endIndex ; startIndex++,endIndex--){ T temp = arr[startIndex]; arr[startIndex] = arr[endIndex]; arr[endIndex] = temp; } } // public String toString(T[] arr){ StringBuilder sb = new StringBuilder(); for(int i = 0 ; i < arr.length ; i++){ if(i==0){ sb.append("["+arr[i]+","); }else if(i==arr.length-1){ sb.append(arr[i]+"]"); }else{ sb.append(arr[i]+","); } } return sb.toString(); } public static <T>void print(T[] t){ } } public class Demo3 { public static void main(String[] args) { Integer[] arr = {10,12,14,19}; MyArrays<Integer> tool = new MyArrays<Integer>(); tool.reverse(arr); System.out.println("数组的元素:"+tool.toString(arr)); MyArrays<String> tool2 = new MyArrays<String>(); String[] arr2 = {"aaa","bbb","ccc"}; tool2.reverse(arr2); ArrayList<String> list = new ArrayList<String>(); } }
c.泛型接口
格式:interface 接口名<声明自定义泛型>{}
例子:
interface Dao<T>{ public void add(T t); } public class Demo4<T> implements Dao<T> { public static void main(String[] args) { Demo4<String> d = new Demo4<String>(); } public void add(T t){ } }
d.泛型的上下限
泛型中的通配符:? super Integer:只能存储Integer或Integer父类元素,泛型的上限
? extends Number:只能存储Number或Number子类元素,泛型的下限
public class Demo5 { public static void main(String[] args) { ArrayList<Integer> list1 = new ArrayList<Integer>(); ArrayList<Number> list2 = new ArrayList<Number>(); HashSet<String> set = new HashSet<String>(); //getData(set); } //泛型的上限 public static void getData(Collection<? extends Number> c){ } //泛型的下限 public static void print(Collection<? super Integer> c){ } }
2.提问:
a.说出ArrayLsit与Vector的区别?
相同点: ArrayList与Vector底层都是使用了Object数组实现的。
不同点: 1. ArrayList是线程不同步的,操作效率高;Vector是线程同步的,操作效率低。
2. ArrayList是JDK1.2出现,Vector是jdk1.0的时候出现的。