本帖最后由 了无尘 于 2012-3-28 16:48 编辑
日常应用中,经常碰到这么样的问题,比如说,我有一个int数组需要排序,还有一个long数组进行排序,可能还有未知的对象数组需要排序,就好比基础题里边的给学生成绩排序那样,每次我们都要重新写一个代码去排序吗?这样的话重复代码有多少,更万恶的就是如果你根本不知道运行时会有怎么的对象数组需要进行什么排序,这样的代码怎么写?我想很多人都崩溃了,呵呵,其实this is so easy
那么总结下命题,对任意对象的成员变量,或者方法的返回值做为依据而对对象数组进行排序。
这里可以发现,如果需要实现这个功能吗,那么首先我们要在不知道对象的类型的情况下知道他的成员变量的值,或者是相关方法的返回值。
首先,我们先解决怎么获得任意对象的成员变量的值的问题- class Cat
- {
- public int age = 1;
- }
复制代码 对于这个Cat类的age变量,取得他的值可以通过映射方式来获得,学过映射都应该知道映射其实就是把整个类的所有成员给你映射成相关的对象。- Cat cat = new Cat();
- System.out.println(cat.getClass().getField("age").get(cat));
复制代码 这样控制台就打印出了这个cat对象的age变量的值为1。- class Cat
- {
- private int age = 1;
-
- public Cat()
- {
-
- }
- public Cat(int age)
- {
- this.age = age;
- }
- public int getAge()
- {
- return age;
- }
- }
复制代码 这样的私有成员,除非我们把访问权限改了,要不然会通过上边的字段方式是不能访问的,所以我们可以访问他的函数,拿返回值- Cat cat = new Cat();
- System.out.println(cat.getClass().getMethod("getAge").invoke(cat));
复制代码 这里的invoke方法就是执行一次这个方法,如果有返回值就返回,void返回null。
但是到这呢,我们会发现一个奇怪的问题,这和我们想的不太一样,因为变量有可能其他的类型(这里暂时只说整数和浮点),难道我们还需要去逐一检测类型?其实最简单的办法就是在排序时,把他们全变成double,这样子,包括整数和浮点都可以进行对比了。- (double)cat.getClass().getMethod("getAge").invoke(cat)
复制代码 这个代码是错误的,原因是强制转化失败,呵呵,还记得基本类型的包装类吗,parsexxx这个函数果断的是很好用的- Double.parseDouble(cat.getClass().getMethod("getAge").invoke(cat).toString())
复制代码 现在准备工作做完了,我们可以开始写个简单的例子试试成果。- Cat[] cats = {new Cat(100),new Cat(150),new Cat(50)};
- for (Cat cat : cats)
- {
- System.out.println(Double.parseDouble(cat.getClass().getMethod("getAge").invoke(cat).toString()));
- }
复制代码 100.0
150.0
50.0
输出木有问题,这里用的是调用函数来取值,如果是访问成员的话,用field那个方式。但是有些对象的成员是私有的,你只能用函数,所以,这两种方式我们都应该提供。
这里还有一个新东西,没发现的去撞墙,呵呵,就是吧,我们说的是任意对象对吧,那我们在来一个Wolf吧- class Wolf
- {
- public int age = 10;
-
- public Wolf()
- {
-
- }
- public Wolf(int age)
- {
- this.age = age;
- }
- public int getAge()
- {
- return age;
- }
-
- public String toString()
- {
- return ""+age;
- }
- }
- class Cat
- {
- private int age = 1;
-
- public Cat()
- {
-
- }
- public Cat(int age)
- {
- this.age = age;
- }
- public int getAge()
- {
- return age;
- }
-
- public String toString()
- {
- return ""+age;
- }
- }
- Object[] objects = {new Wolf(100),new Cat(150),new Cat(50)};
- for (Object object : objects)
- {
- System.out.println(Double.parseDouble(object.getClass().getMethod("getAge").invoke(object).toString()));
- }
复制代码 到这呢,其实输出就知道了,我们发所有具有getAge方法的对象,我们全可以拿来排序。。。或者只要具有相同的可以访问的成员变量的对象也行,这个跟以前我们需要他们都继承一个超类来达到上朔遍历不太一样,我们这个更开放,更自由,但是这个猫和狼呢,确实还是要一个动物的超类,这样更好理解一些东西,这个在我另外一个帖子抽象和接口选择那里有说。
好了,到这,我想应该都看明白了,只需要在实现下排序就可以了,拿值的问题都已经解决,排序的话就照葫芦画瓢就行了,下边把完整的代码贴一下,bug肯定多,就是演示下反射的简单用途,当然这是最简单的用法。- import java.lang.reflect.InvocationTargetException;
- class Wolf
- {
- public int age = 10;
-
- public Wolf()
- {
-
- }
- public Wolf(int age)
- {
- this.age = age;
- }
- public int getAge()
- {
- return age;
- }
-
- public String toString()
- {
- return ""+age;
- }
- }
- class Cat
- {
- public int age = 1;
-
- public Cat()
- {
-
- }
- public Cat(int age)
- {
- this.age = age;
- }
- public int getAge()
- {
- return age;
- }
-
- public String toString()
- {
- return ""+age;
- }
- }
- public class lll
- {
- public static final boolean FROM_SMALL_TO_LARGE = true;
- public static final boolean FROM_LARGE_TO_SMALL = false;
- public static void main(String[] args) throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException
- {
-
- Object[] objects = {new Wolf(15), new Cat(20), new Wolf(), new Cat()};
- for (Object object : objects)
- {
- System.out.println(object.toString());
- }
- bubbleSort(objects, "getAge()", FROM_SMALL_TO_LARGE);
- System.out.println("===============================>");
- for (Object object : objects)
- {
- System.out.println(object.toString());
- }
- System.out.println("===============================>");
- bubbleSort(objects, "age", FROM_LARGE_TO_SMALL);
- for (Object object : objects)
- {
- System.out.println(object.toString());
- }
- }
-
- public static void bubbleSort(Object[] src, String expression, boolean is) throws NumberFormatException, IllegalArgumentException, SecurityException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException
- {
- int index = expression.indexOf("()");
- if(index != -1)
- {
- expression = expression.substring(0, index);
- }
- double a,b;
- for (int i = 0; i < src.length; ++i)
- {
- for (int j = 0; j < src.length - i - 1; ++j)
- {
- if(index != -1)
- {
- a = Double.parseDouble(src[j].getClass().getMethod(expression).invoke(src[j]).toString());
- b = Double.parseDouble(src[j+1].getClass().getMethod(expression).invoke(src[j+1]).toString());
- }
- else
- {
- a = Double.parseDouble(src[j].getClass().getField(expression).get(src[j]).toString());
- b = Double.parseDouble(src[j+1].getClass().getField(expression).get(src[j+1]).toString());
- }
- if(is && a > b)
- {
- swap(src, j, j+1);
- }
- else if(!is && a < b)
- {
- swap(src, j, j+1);
- }
- }
- }
- }
- public static void swap(Object[] data, int i, int j)
- {
- Object temp = data[i];
- data[i] = data[j];
- data[j] = temp;
- }
- }
复制代码- 15
- 20
- 10
- 1
- ===============================>
- 1
- 10
- 15
- 20
- ===============================>
- 20
- 15
- 10
- 1
复制代码 最后说点啥呢,其实在编程里,很多东西都是活的,死记硬背是行不通的,呵呵,祝大家早日挺进黑马
关于一些其他的规则,你也可以自己定义,只有想不到,没有做不到,呵呵
另外在说点题外的,这个代码写之前我没有学过反射,也没看过视频,我原来只知道有反射这个东西,有个大概的记忆,写这个的时候都是查api写的,呵呵,其实看我的代码没什么用处,谁都能写,但是在工作中,不是所有的工作都是你会的,如果是你不会的,还没有人教你,那怎么办? |