反射:
理解:
通过对反射的学习,得到最初的解释:反射就是把java类中的各个成员映射成相应的java类。
应用反射,可以实现框架,满足更多的程序的需求。反射还可以使用私有方法,可以实现更多的功能。反射允许程序创建和控制任何类的对象,无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的库。Java reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。
上例子:
实体类源代码:
ackage com.hu;
public class ReflectPoint {
public int x;
private int y;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "canhua";
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
private int getY() {
return y;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
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;
}
@Override
public String toString() {
return "ReflectPoint [x=" + x + ", y=" + y + ", str1=" + str1
+ ", str2=" + str2 + ", str3=" + str3 + "]";
}
}
测试程序:
package com.hu;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Text1 {
public static void main(String[] args) throws Exception {
String str1 = "abc";
Class cls1 = str1.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
System.out.println("cls1 == cls2:" + (cls1 == cls2));
System.out.println("cls1 == cls3:" + (cls1 == cls3));
// isPrimitive()方法 表示返回是否为基本数据类型
System.out.println("cls1.isPrimitive():" + (cls1.isPrimitive()));
System.out.println("int.class.isPrimitive():"
+ (int.class.isPrimitive()));
// Integer.class 表示Integer对象的Class的实例
System.out.println("int.class == Integer.class:"
+ (int.class == Integer.class));
// Integer.TYPE 表示基本类型int的Class的实例
System.out.println("int.class == Integer.TYPE:"
+ (int.class == Integer.TYPE));
// 在java中数组也是一种对象,所以也有Class类返回
System.out.println("int[].class.isPrimitive():"
+ (int[].class.isPrimitive()));
System.out.println("int[].class.isArray():" + (int[].class.isArray()));
int[] a1 = new int[3];
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[4];
int[] a5 = new int[3];
// 打印false
System.out.println("a1.getClass() == a2.getClass():"
+ (a1.getClass() == a2.getClass()));
// 打印true
System.out.println("a1.getClass() == a5.getClass():"
+ (a1.getClass() == a5.getClass()));
// new String(new StringBuffer("abc"));与下面两行是相同的。
Constructor constructor = String.class
.getConstructor(StringBuffer.class);
String str2 = (String) constructor.newInstance(new StringBuffer("abc"));
System.out.println("str2:" + str2);
System.out.println("str2.charAt(2):" + str2.charAt(2));// 应该打印c
ReflectPoint pt1 = new ReflectPoint(3, 5);
System.out.println("pt1.x:" + pt1.x);
// 获得ReflectPoint中的变量,跟上面的效果是一样的
Field fieldX = pt1.getClass().getField("x");
System.out.println("fieldX.getInt(pt1):" + (fieldX.getInt(pt1)));
// 获得ReflectPoint的私有变量
Field fieldY = pt1.getClass().getDeclaredField("y");
// 设置可以访问属性(暴力反射)
fieldY.setAccessible(true);
System.out.println("fieldY.getInt(pt1):" + (fieldY.getInt(pt1)));
// 获得其中的方法,第一个参数是方法名,第二个参数是传入的参数类型
Method method = pt1.getClass().getMethod("getX", null);
// 调用该方法,第一个参数是哪个对象,第二个参数是传入的参数
int temp = (int) method.invoke(pt1, null);
System.out.println(method.getName() + " " + temp);
// 获得私有方法
Method method2 = pt1.getClass().getDeclaredMethod("getY", null);
// 设置可以访问属性(暴力反射)
method2.setAccessible(true);
// 调用该方法,第一个参数是哪个对象,第二个参数是传入的参数
int temp2 = (int) method2.invoke(pt1, null);
System.out.println(method2.getName() + " " + temp2);
changeStringValue(pt1);
}
private static void changeStringValue(Object obj)
throws IllegalArgumentException, IllegalAccessException {
// 获得所有成员变量
Field[] fields = obj.getClass().getFields();
for (Field field : fields) {
// 这里用equals可以实现同样的效果,但类型为同一个,字节码想通过,如下写更好
if (field.getType() == String.class) {
// 获得成员变量的值
String oldvalue = (String) field.get(obj);
// 将所有的ball替换为***
String newValue = oldvalue.replace("ball", "***");
// 同样的,前一个参数是哪个对象,第二个参数是替换为什么值
field.set(obj, newValue);
}
}
System.out.println(obj.toString());
}
}
打印的结果:
cls1 == cls2:true
cls1 == cls3:true
cls1.isPrimitive():false
int.class.isPrimitive():true
int.class == Integer.class:false
int.class == Integer.TYPE:true
int[].class.isPrimitive():false
int[].class.isArray():true
a1.getClass() == a2.getClass():true
a1.getClass() == a5.getClass():true
str2:abc
str2.charAt(2):c
pt1.x:3
fieldX.getInt(pt1):3
fieldY.getInt(pt1):5
getX 3
getY 5
ReflectPoint [x=3, y=5, str1=***, str2=basket***, str3=canhua]
配置文件的内容是:
config.properties
className=java.util.ArrayList
测试的类:
package com.hu;
import java.io.FileInputStream;
import java.util.Collection;
import java.util.Properties;
/**
* 利用反射,可以根据传入的参数动态的调用不同的类,同样的可以调用不同的方法,所谓框架就是如此,因为框架要适应多种情况,应用配置文件进行配置,接着进行调用,
* 这样框架更具健壮性
*
* @author hucanhua
*
*/
public class hu {
public static void main(String[] args) throws Exception {
// 这里是用文件输入流读取类的名字
FileInputStream ips = new FileInputStream("config.properties");
// 这个是java的默认的参数对象,我们可以使用它
Properties props = new Properties();
// 从字节流读取配置信息
props.load(ips);
ips.close();
// 获得配置信息中className字段的值
String className = props.getProperty("className");
System.out.println(className);
Collection collection = (Collection) Class.forName(className)
.newInstance();
ReflectPoint pt1 = new ReflectPoint(3, 3);
ReflectPoint pt2 = new ReflectPoint(5, 5);
ReflectPoint pt3 = new ReflectPoint(3, 3);
collection.add(pt1);
collection.add(pt2);
collection.add(pt3);
collection.add(pt1);
// 因为配置信息是java.util.ArrayList类型,所以是允许重复的,故打印出来的个数是4
// 如果配置信息是java.tuil.HashSet类型,同时ReflectPoint实现以上hashCode方法,则会打印3个
System.out.println(collection.size());
}
}
java.util.ArrayList
4