java进阶(三):反射(3)——数组的反射与集合的运用(ArrayList、HashSet),arraylisthashset
java进阶(三):反射(3)——数组的反射与集合的运用(ArrayList、HashSet),arraylisthashset
一、数组的反射
1、简单的数组反射:
1)同样类型切且具有相同维度的数组拥有同一份字节码
/*
* 5- 数组的的反射
*/
int[] a1 = new int[3];
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[3];
System.out.println(a1 == a2);//false
//同样类型切且具有相同维度的数组拥有同一份字节码
System.out.println(a1.getClass() == a2.getClass());//true
2)getName()和getSuperclass()方法
System.out.println(a1.getClass().getName());//[I : [-表示数组,I-整数,具体见文档
System.out.println(a4.getClass().getName());//[Ljava.lang.String;
//得到父类getSuperclass(),显示其父类的名字
System.out.println(a1.getClass().getSuperclass().getName());//java.lang.Object
System.out.println(a4.getClass().getSuperclass().getName());//java.lang.Object
2、Arrays和Array类的使用。
1)java.util.Arrays类:对数组操作的类,封装了大量静态方法操作数组。
例如:A、给数组赋值:通过fill方法;
B、对数组排序:通过sort方法,按升序;
C、比较数组:通过equals方法比较数组中元素值是否相等;
D、查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作。
int[] b1 = {9,6,3};
String[] b2 = {"Z","Y","A"};
String [] c = new String[3];
//打印数组
System.out.println(Arrays.asList(b1));//看不到值,原因是int不属于Object [[I@14318bb]
System.out.println(Arrays.asList(b2));//可以看到打印的值 [Z, Y, A]
//给数组赋值
Arrays.fill(c, "4");
System.out.println("查看数据C--"+Arrays.asList(c));//查看数据C--[4, 4, 4]
//对数组排序:通过sort方法,按升序
Arrays.sort(b2);
System.out.println("排序后的数组b2--"+Arrays.asList(b2));//排序后的数组b2--[A, Y, Z]
2)java.lang.reflect.Array类:可以得到反射数组的类型,对反射数组进行赋值等操作。
int[] temp={1,2,3,4,5};
Class<?>demo = temp.getClass().getComponentType();
System.out.println("数组类型: "+demo.getName());
System.out.println("数组长度 "+Array.getLength(temp));
System.out.println("数组的第一个元素: "+Array.get(temp, 0));
Array.set(temp, 0, 100);
System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0));
【输出】
数组类型: int
数组长度 5
数组的第一个元素: 1
修改之后数组第一个元素为: 1
3、综合运用:
/**
* 方法:传一个object,打印出来,数组就遍历
* @param obj
* @throws InstantiationException
* @throws IllegalAccessException
*/
private static void printObject(Object obj) throws InstantiationException, IllegalAccessException{
Class clazz = obj.getClass();
if(clazz.isArray()) {//判断数组
int len = Array.getLength(obj);//得到数组的长度
for (int i = 0; i < len; i++) {
System.out.print(Array.get(obj, i));
}
System.out.println();
for(int i = 0; i < len; i++){
Array.set(obj, i, 99);//赋值
System.out.print(Array.get(obj, i));
}
}else {
System.out.println();
System.out.println(obj);
}
}
}
int[] temp={1,2,3,4,5};
printObject(temp);//调用
printObject("khjkhj");//调用
【输出】
12345
9999999999
khjkhj
二、ArrayList_HashSet的比较及Hashcode分析。
1、先定义一个实体,暂时没有重写父类的equals()和hashCode()方法。
package com.onhance.reflection;
/**
*
* @title 反射用到的实例
* @description
* @author SAM-SHO
*
* @Date 2014-6-29
*/
public class ReflectPoint {
private int x;
public int y;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "SAM SHO";
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "ReflectPoint [str1=" + str1 + ", str2=" + str2 + ", str3="
+ str3 + "]";
}
}
2、分别定义四个ReflectPoint对象,然后增加equals()和hashCode()方法。
//1-先定义对象
ReflectPoint pt1 = new ReflectPoint(3, 3);
ReflectPoint pt2 = new ReflectPoint(5, 5);
ReflectPoint pt3 = new ReflectPoint(7, 7);
ReflectPoint pt4 = new ReflectPoint(7, 7);
//1-2比较pt3和pt4的关系
//在ReflectPoint类重写hashcode与equals方法前为 : false,重写后,为true;
System.out.println(pt3.equals(pt4));
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;//x、y参与哈希算法
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;
ReflectPoint other = (ReflectPoint) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
清楚的看到:pt3和pt4比较在前后发生的变化。
3、把实例分别放入ArrayList和HashSet容器,观察容器的大小。
//2-1 ArrayList集合
//不管ReflectPoint有没有重写hashcode与equals方法,不管pt1-pt4之间的关系,长度适中为5
//因为ArrayList有顺序,可以重复
Collection <Object> list = new ArrayList<Object>();
list.add(pt1);
list.add(pt2);
list.add(pt3);
list.add(pt4);
list.add(pt1);
System.out.println("ArrayList的长度 : "+list.size());//显示长度为5
//2-2 HashSet集合
// 首先pt1只能放一个。
// 没有重写hashcode和equesl方法时,pt3和pt4不 equals,即指向的不是同一个对象。所以都能放进去,长度为4
// 重写hashcode和equesl方法后,pt3和pt4指向同一个对象,放不进去,长度为3.
// 因为HashSet没有有顺序,不可以重复
Collection <Object> set = new HashSet<Object>();
set.add(pt1);
set.add(pt2);
set.add(pt3);
set.add(pt4); //pt3 equals pt4 重复,没有重写hashcode和equesl方法,就可以放进去)
set.add(pt1); //重复,放不进去,只能放一个pt1
System.out.println("HashSet的长度 : "+set.size());//3个、4个
4、这边对哈希算法作简单介绍:
1)、哈希算法提高从集合中查找元素的效率,将集合分成若干个区域每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储在哪个区域。
2)、HashSet底层用的也是数组。当向数组中利用add(Object o)添加对象的时候,系统先找对象的hashCode。
int hc=o.hashCode(); 返回的hashCode为整数值:Int I=hc%n;(n为数组的长度),取得余数后,利用余数向数组中相应的位置添加数据,以n为6为例,如果I=0则放在数组a[0]位置,如果I=1,则放在数组a[1]位置。如果equals()返回的值为true,则说明数据重复。如果equals()返回的值为false,则再找其他的位置进行比较。这样的机制就导致两个相同的对象有可能重复地添加到数组中,因为他们的hashCode不同。如果我们能够使两个相同的对象具有相同hashcode,才能在equals()返回为真。
5、当一个对象被存进集合中,不要去修改这个对象参加hash算法的属性,不然会破坏哈希算法。导致存进去的对象与修改后的对象具有不同的哈希值。这样最直接的问题就是,集合中的那个对象无法删除(当然有其他办法处理),造成内存泄露。
在上例中,x/y参与了哈希算法,现在改变y的值,看一下结果:
//可以取走,结果长度为2
set.remove(pt1);//可以取走
System.out.println("HashSet的长度 : "+set.size());//2个
//不可取走,结果为3
pt1.y = 99;//y用于hashcode方法的计算,修改值以后,取不走:会导致内存泄露
set.remove(pt1);//取不走
System.out.println("HashSet的长度 : "+set.size());//3个
set.clear();//我们可以清除
System.out.println("HashSet的长度 : "+set.size());//0个
备注(写给自己):以后我会继续整理java中集合的内容。包括数据结构的内容和thinking in java中的内容。
相关文章
- 暂无相关文章
用户点评