Spring中往往一个注解(如@Controller@Service)就可以完成一些复杂的操作。注解应用于反射之上,反射是java的重中之重。反射强调的是运行时状态,获取类的方法和属性的一些信息。
一、获取类
通过反射获取类的几种方式:
1、通过Class.forName
Class<?> clazz = Class.forName("java.lang.String");
//获取所有的方法
Method[] methods = clazz.getDeclaredMethods();
for(Method method : methods){
System.out.println(method);
}
System.out.println("-------------");
//获取所有public的方法
Method[] publicMethods = clazz.getMethods();
for(Method method : publicMethods){
System.out.println(method);
}
System.out.println("-------------");
//获取所有属性
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields){
System.out.println(field);
}
System.out.println("-------------");
//获取所有public的属性
Field[] pubilcFields = clazz.getFields();
for(Field field : pubilcFields){
System.out.println(field);
}
System.out.println("-------------");
//获取构造方法
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors){
System.out.println(constructor);
}
2、对象.getClass
String str = "sss";
Class<?> clazz = str.getClass();
3、类.class
Class<?> clazz = String.class;
二、给对象赋值
1、通过反射给对象赋值。
定义一个对象:
public class Student {
private String name;
private String sex;
private Integer age;
public Student(String name, String sex, Integer age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
public String doNothing(Integer a){
System.out.println(a);
return "nothing";
}
}
Class<?> clazz = Class.forName("reflection.Student");
//创建一个对象
Student student = (Student)clazz.newInstance();
//设置名字属性
Field field = clazz.getDeclaredField("name");
//强制写入private对象
if(!field.isAccessible()) {
field.setAccessible(true);
}
field.set(student,"娃哈哈");
System.out.println(student);
2、调用方法
Class<?> clazz = Class.forName("reflection.Student");
//创建一个对象
Student student = (Student) clazz.newInstance();
//得到方法
Method method = clazz.getDeclaredMethod("doNothing", Integer.class);
String str = (String) method.invoke(student,100);
System.out.println(str);
3、构造器的使用
Class<?> clazz = Class.forName("reflection.Student");
//得到构造器
Constructor constructor = clazz.getConstructor(String.class, String.class, Integer.class);
Student student = (Student)constructor.newInstance("娃哈哈", "男", 100);
System.out.println(student);
4、构造器的小应用
一般的情况下,List中存放的是一个同一数据类型的数据,现在要求将不同数据类型的数据放在同一个List中。这种要求可定需要使用反射来完成。
List<String> students = new ArrayList<String>();
students.add("娃哈哈同学");
students.add("康师傅同学");
//报错
// students.add(1234);
Class<?> clazz = students.getClass();
Method method = clazz.getMethod("add", Object.class);
method.invoke(students, 1234);
for (Object object: students){
System.out.println(object);
}
三、内省
内省是Java语言对Bean类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getName,setName来得到其值或者设置新的值。通过getName/setName来访问name属性,这就是默认的规则。Java中提供了一套API用来访问某个属性的getter/setter方法,通过这些API可以使你不需要了解这个规则(但你最好还是要搞清楚),这些API存放于包java.beans中。
Student student = (Student.class).newInstance();
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("age", Student.class);
Method method = propertyDescriptor.getWriteMethod();//setAge
method.invoke(student,100);
System.out.println(student);
这种方式要求属性值要分装有get/set方法。
四、BeanUtils
这种方式常见于Spring Web中,获取URL后面所带参数。这个带上Bean所以属性值也是要带上set/get方法。需要导入commons-beanutils包。
Student student = (Student.class).newInstance();
//Date需要手工转化
BeanUtils.setProperty(student,"name","娃哈哈");
System.out.println(student);
常见的用法,这样就把URL的参数都设置进去了。
Map<String, Object> map = new HashMap<String, Object>();
map.put("name","娃哈哈");
map.put("age", 20);
map.put("sex","女");
Student student = (Student.class).newInstance();
BeanUtils.populate(student,map);
System.out.println(student);
五、注解
注解就是放在类名、属性、方法上的标注,这个标注用于之后业务代码的处理。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyBean {
String table();
String auth() default "娃哈哈";
}
Target表示该注解能放在类上,属性上,还是方法上。Retention表示存活周期,一般是运行时。Inherited表示这个注解可以用于子类中。
@MyBean(table = "animal")
public class Animal {
@MyField("name")
private String name;
}
Class<?> clazz = Class.forName("annotation.Animal");
if (clazz.isAnnotationPresent(MyBean.class)) {
MyBean myBean = clazz.getAnnotation(MyBean.class);
System.out.println(myBean.table());
}
六、案例
根据上面讲的,自己实现一个关系型数据库的简单ORMapping框架。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyBean {
String table();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyField {
String value();
}
@MyBean(table = "animal")
public class Animal {
@MyField("nick_name")
private String name;
@MyField("real_age")
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class AnimalUtils {
public static String getTableName(Class<?> clazz) {
if (clazz == null) {
return null;
}
MyBean myBeanAnnotation = clazz.getAnnotation(MyBean.class);
if (myBeanAnnotation != null) {
return myBeanAnnotation.table();
} else {
return clazz.getSimpleName().toLowerCase();
}
}
public static String getColumnName(Field field) {
if (field == null) {
return null;
}
MyField myFieldAnnotation = field.getAnnotation(MyField.class);
if (myFieldAnnotation != null) {
return myFieldAnnotation.value();
} else {
return field.getName();
}
}
public static String getMethodName(Field field, String type) {
String name = field.getName();
return type + name.substring(0, 1).toUpperCase()
+ name.substring(1);
}
public static <T extends Object> String getDbSaveSql(T t) {
StringBuilder sb = new StringBuilder();
Class<?> clazz = t.getClass();
sb.append(" insert into ");
//表名
String tableName = getTableName(clazz);
sb.append(tableName).append(" ( ");
//字段名
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (!"id".equals(field.getName())) {
String columnName = getColumnName(field);
sb.append(columnName).append(",");
}
}
sb.deleteCharAt(sb.toString().length() - 1)
.append(" ) values (");
for (Field field : fields) {
if (!"id".equals(field.getName())) {
sb.append("?").append(",");
}
}
sb.deleteCharAt(sb.toString().length() - 1)
.append(" )");
return sb.toString();
}
public static <T extends Object> List<Object> getValues(T t) throws Exception {
List<Object> columnValues = new ArrayList<Object>();
Class<?> clazz = t.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String methodName = getMethodName(field, "get");
Method method = clazz.getDeclaredMethod(methodName);
columnValues.add(method.invoke(t));
}
return columnValues;
}
}
public class AnnotationApp {
public static void main(String[] args) throws Exception {
Animal animal = new Animal();
animal.setName("娃哈哈");
animal.setAge(12);
String sql = AnimalUtils.getDbSaveSql(animal);
List<Object> valus = AnimalUtils.getValues(animal);
Connection connection = DbUtils.getConnection();
PreparedStatement pstmt = connection.prepareStatement(sql);
int index = 1;
for (Object culomnValue : valus) {
pstmt.setObject(index++, culomnValue);
}
int rowCount = pstmt.executeUpdate();
}
}
七、后续
以上的代码看着比较难过,还可以使用Aop和注解相互结合实现ORm。