泛型机制:
(1)概念
jdk1.5版本开始使用的新特性,本质是进行"参数化类型",在类,接口,方法的定义上都可以使用,用来指定数据类型名的。
(2)集合在定义时,可以用泛型机制来指定元素的类型,这样编译器在编译期间就可以进行检查元素类型是否匹配,避免了程序在运行时出现过多的错误
(3)集合框架中的所有类型(接口,抽象类,实现类)都是用了泛型机制
(4)泛型机制的参数只能传引用类型
练习:自定义一个类型,练习泛型机制
定义一个类型MyContaionner:使用泛型机制,用于规定要存储的元素类型
package com.hyxy.se.day07;
import java.util.Arrays;
/*定义类型时使用泛型机制,泛型机制的本质是参数化类型
* PS:与参数化对象/数据比较,与方法的形参比较*/
public class MyContainer<M> {
private static final String M = null;
Object[] values;
public MyContainer(){
values=new Object[16];
}
/*定义方法时,使用泛型机制*/
public void add(M m){
for(int i=0;i<values.length;i++){
if(values [i]==null){
values [i]=m;
break;
}
}
}
public M remove(Object obj){
M m=null;
for(int i=0;i<size();i++){
if(values[i].equals(obj)){
//存储要被移除的对象
m=(M)values[i];//Object型强转成M类型
System.arraycopy(values, i+1, values, i, size()-1-i);
//values=Arrays.copyOf(values, values.length);
values[size()-1]=null;
break;
}
}
return m;
}
public int size(){
for(int i=0;i<values.length;i++){
if(values [i]==null){
return i;
}
}
return values.length;
}
/**重写toString
* 插入方法add(int index,M m)
* M remove(int index)
*/
public void add(int index,M m){
//考虑扩容
if((size()+1)>values.length){
values=Arrays.copyOf(values, values.length+16);
}
System.arraycopy(values,index,values,index+1,size()-index);
values[index]=m;
}
public M remove(int index) {
M m;
if (index<0||index>size()) {
throw new RuntimeException("下标越界");
}
System.arraycopy(values, index+1, values, index, size()-index-1);
values[size()-1]=null;
return m=(M)values;
}
public String toString(){
String str="[";
for(int i=0;i<size()-1;i++){
str+=values[i]+",";
}
str+=values[size()-1]+"]";
return str;
}
}
第二部分
package com.hyxy.se.day07;
public class TestMyContainer {
public static void main(String[] args) {
MyContainer<String> my=new MyContainer<String>();
System.out.println(my.size());
//添加一个元素
my.add("abc");
System.out.println(my.size());
my.add("hhhh");
my.add("java");
System.out.println(my.size());
String e=my.remove("java");
System.out.println(e);
System.out.println(my.size());
System.out.println(my);//com.hyxy.se.day07.MyContainer@15db9742 未重写
}
}
List排序
Comparable接口:
如何定义集合中元素之间的大小之分?我们需要在定义元素类型时实现Comparable接口,实现接口内的compareTo(E e)。实现此接口的类型的对象之间可以进行比较。
方法:int compareTo(E e):
比较规则:
(1)this与e比较,this-e,按照升序排序
如果大于0,返回大于0的一个数
如果等于0, 返回0
如果小于0, 返回小于0的一个数
(2)e-this,降序排序
工具类:Collections
提供了一个sort(Collection c)方法,对集合里的元素进行排序
练习:定义一个类型Point,在集合List中存储五个Point对象按照到原点的距离长短进行降序排序。
package com.hyxy.se.day07;
/*定义一个Point类型,在集合List中存储5个Point对象,按照到原点距离进行 降序排列*/
public class Point implements Comparable<Point>{
private int x;
private int y;
public Point(int x,int y){
this.x=x;
this.y=y;
}
public void add(int x,int y){
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public int hashCode() {
final int prime = 31;---定义一个素数局部变量进行初始化
int result = 1; ---定义一个局部变量进行初始化
result = prime * result + x;//定义一个素数prime 用新结果去乘以prime
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Point other = (Point) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
@Override
public String toString() {
return "(" + x + "," + y + ")";
}
/*按照到原点距离的大小排序,降序排序*/
public int compareTo(Point o){
int dis1=x*x+y*y;
int dis2=o.x*o.x+o.y*o.y;
return (dis2-dis1);
}
}
第二部分
package com.hyxy.se.day07;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TestPoint {
public static void main(String[] args) {
List<Point> list=new ArrayList<Point>();
for(int i=0;i<5;i++){
int x=(int)(Math.random()*10);
int y=(int)(Math.random()*10);
list.add(new Point(x,y));
}
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
}
Comparator比较器接口:
如果元素类型已经实现了comparable接口,定义了默认的比较规则。之后,再想换其他比较规则时,不修改源码。可以利用比较器接口,来重新定义比较规则
方法:
int compare(E o1,E o2);
比较规则:
升序: o1-o2
降序: o2-o1
Set接口:
特点1: 无序,存储的元素与添加顺序无关
特点2: 不可重复(使用元素的equals方法来判定是否重复)
特点3: 能存储null元素,只能存储一次。
set集合不能使用经典for循环但是可以用迭代器
Hash算法机制
Set集合在添加或查看元素时,当集合中的元素过多时,就是进行多次的比较,效率变低。
在设计元素类型时,提供hash算法,用于返回对象的一个int值。在内存中开辟很多小的区域,用于存储一定范围的返回值的对象。当我们想添加元素或查看元素,先计算此元素的返回值,然后去相应区域中查找遍历,
--如果在这个区域没有找到对象,说明集合中可以添加这个对象。
--如果有,然后查看两个对象的equals的返回值
--如果为true, 不能添加
--如果为false, 可以添加,添加至对应的链表结构中(尽可能的避免发生)
重写HashCode方法:
重写规则:尽可能的让所有的成员变量都参与运算,尽可能的避免出现hash值碰撞
注意:
重写的必要性:
(1)如果重写了equals(), 有必要重写hashCode方法
(2)如果equals()返回true, hashCode返回值有必要相同
(3)如果equals()返回false,hashCode返回值不一定相同,如果返回值不同,可以提高检索的效率
反过来说:
(1)hashCode值相同,equals方法可能不同
(2)hashCode值不同,equals方法一定不同
Set接口派生的子类:
HashSet:通过实现hash算法的一种数据结构,无序,不重复。
LinkedHashSet:通过实现hash算法的一种数据结构,但是通过链表来维持顺序。顺序与添加顺序一致。
TreeSet:使用二叉树的一种数据结构,顺序与自然排序有关系。支持定制排序