/**
*介绍:什么是反射机制
* 在程序运行中 对于任意一个类或对象, 都可以获取到这个类的方法和属性(包含私有属性与方法)
* 这种动态的获取信息以及动态的调用对象方法的功能,我们称为反射机制
* 简单来说: 通过反射 类在我们面前是完全透明的。想要获取任何东西都可以
* 优点:
* 在程序的运行中,可以动态的获取类的属性与方法.操作这些对象
* 可以解耦,提高程序的可扩展性
* JAVA代码在计算机中所经历的三个阶段
* 1: Source 阶段: 通过 javac 命令 .java 文件 编译成 .class 文件
* 2: Class 类对象阶段 .class 字节码文件被类加载器 加载至内存 并将其封装成Class对象
* (用于在内存中描述字节码文件) Class 对象将原字节码中的成员变量抽取出来封装成数组Field[]
* 将字节码文件中的构造函数抽取出来封装成Construction[] ,将成员方法 封装成数组 Method[]
* Class 类内不止这个,我们常用的就这三个
* 3: RunTime运行时阶段: 使用 new 创建对象的过程
*/
public class ReflexTemplate {
/**
* 介绍:什么是反射机制
* 在程序运行中 对于任意一个类或对象, 都可以获取到这个类的方法和属性(包含私有属性与方法)
* 这种动态的获取信息以及动态的调用对象方法的功能,我们称为反射机制
* 简单来说: 通过反射 类在我们面前是完全透明的。想要获取任何东西都可以
*/
/**
* 优点:
* 在程序的运行中,可以动态的获取类的属性与方法.操作这些对象
* 可以解耦,提高程序的可扩展性
*/
/**
* JAVA代码在计算机中所经历的三个阶段
* 1: Source 阶段: 通过 javac 命令 .java 文件 编译成 .class 文件
* 2: Class 类对象阶段 .class 字节码文件被类加载器 加载至内存 并将其封装成Class对象
* (用于在内存中描述字节码文件) Class 对象将原字节码中的成员变量抽取出来封装成数组Field[]
* 将字节码文件中的构造函数抽取出来封装成Construction[] ,将成员方法 封装成数组 Method[]
* Class 类内不止这个,我们常用的就这三个
* 3: RunTime运行时阶段: 使用 new 创建对象的过程
*/
public static void test01() throws ClassNotFoundException {
/*
获取对象的三种方式
*/
// 方式1: [Source阶段] Class.forName("全类名") 将字节码文件加载至内存。返回 Class 对象
// 多用于配置文件 将类名定义于配置文件中 通过读取配置文件加载类
Class<?> class1 = Class.forName("com.shangqing.api.reflex.ReflexTemplate");
// 方式2: [Class] 类对象阶段 通过类名的属性 class 获取 多用于参数的传递
Class<ReflexTemplate> class2 = ReflexTemplate.class;
// 方式3: [Runtime运行时阶段] 对象.getClass(); 此方法定义于 Object 类中的方法 因此所有类都会继承这个方法 多用于对象获取字节码文件
ReflexTemplate template = new ReflexTemplate();
Class<? extends ReflexTemplate> class3 = template.getClass();
System.out.println(class1 == class2); // true
System.out.println(class1 == class3); // true
// 同一个字节码文件 .class 在一次程序运行中 只会被加载一次 无论通过哪种方式获取Class对象 都是同一个
}
public String name;
private Integer age;
Integer height;
protected String sex;
public static void test02() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
/*
获取成员变量
*/
Class<ReflexTemplate> reflexTemplateClass = ReflexTemplate.class;
// 获取所有 public 修饰的成员变量
Field[] fields = reflexTemplateClass.getFields();
// 获取指定名称的 成员变量
Field field = reflexTemplateClass.getField("name");
Arrays.stream(fields).forEach(o->System.out.println(o.getName())); // name
System.err.println(field.getName()); // name
ReflexTemplate template = reflexTemplateClass.newInstance();
field.set(template,"张三");
System.out.println(field.get(template)); // 张三
// 获取所有成员变量 不考虑修饰符
Field[] declaredFields = reflexTemplateClass.getDeclaredFields();
// 获取指定成员变量 不考虑修饰符
Field declaredField = reflexTemplateClass.getDeclaredField("age");
Arrays.stream(declaredFields).forEach(o-> System.out.println(o.getName())); // name age height sex
System.err.println(declaredField.getName()); // age
// 设置属性
declaredField.set(template,11);
System.out.println(declaredField.get(template)); // 11
}
public ReflexTemplate() {
}
private ReflexTemplate(String name) {
this.name = name;
}
public ReflexTemplate(String name, Integer age) {
this.name = name;
this.age = age;
}
public static void test03() throws NoSuchMethodException {
/*
获取构造方法
*/
Class<ReflexTemplate> templateClass = ReflexTemplate.class;
// 获取所有 public 修饰的 构造方法
Constructor<?>[] constructors = templateClass.getConstructors();
// com.shangqing.api.reflex.ReflexTemplate-------2 com.shangqing.api.reflex.ReflexTemplate-------0
Arrays.stream(constructors).forEach(o-> System.out.println(o.getName()+ "-------"+o.getParameterCount()));
// 获取指定的 public 修饰的 构造方法
Constructor<ReflexTemplate> constructor = templateClass.getConstructor(String.class,Integer.class);
System.err.println(constructor.getName()+ "-------"+constructor.getParameterCount()); // com.shangqing.api.reflex.ReflexTemplate-------2
// 获取所有 构造方法 忽略修饰符
Constructor<?>[] declaredConstructors = templateClass.getDeclaredConstructors();
//com.shangqing.api.reflex.ReflexTemplate-------1 com.shangqing.api.reflex.ReflexTemplate-------0 com.shangqing.api.reflex.ReflexTemplate-------2
Arrays.stream(declaredConstructors).forEach(o->System.out.println(o.getName()+ "-------"+o.getParameterCount() ));
// 获取指定 构造方法 忽略修饰符
Constructor<ReflexTemplate> declaredConstructor = templateClass.getDeclaredConstructor(String.class);
System.err.println(declaredConstructor.getName()+ "-------"+constructor.getParameterCount()); // com.shangqing.api.reflex.ReflexTemplate-------2
}
public String method01(Integer i){
return "method01";
}
private String method02(String i){
return "method02";
}
public static void test04() throws NoSuchMethodException {
/*
获取成员方法
*/
Class<ReflexTemplate> templateClass = ReflexTemplate.class;
// 获取所有 Public 方法
Method[] methods = templateClass.getMethods();
Arrays.stream(methods).forEach(o->System.out.println(o.getName())); // Public 包含 父类方法
// 获取指定 Public 方法
Method method = templateClass.getMethod("method01",Integer.class);
System.err.println(method.getName()); // method01
// 获取所有方法 忽略修饰符
Method[] declaredMethods = templateClass.getDeclaredMethods();
/*
main
test02
test01
lambda$test02$0
test04
lambda$test04$4
lambda$test03$3
method01
test05
lambda$test02$1
lambda$test03$2
method02
test03
*/
Arrays.stream(declaredMethods).forEach(o->System.out.println(o.getName()));
// 获取指定方法 忽略修饰符
Method declaredMethod = templateClass.getDeclaredMethod("method02", String.class);
System.err.println(declaredMethod.getName()); // method02
}
public static void test05(){
Class<ReflexTemplate> templateClass = ReflexTemplate.class;
System.out.println(templateClass.getName());
}
public static void main(String[] args) throws Exception {
test01();
test02();
test03();
test04();
test05();
}
newInstance()和new()区别:
1、两者创建对象的方式不同,前者是实用类的加载机制,后者则是直接创建一个类:
2、newInstance创建类是这个类必须已经加载过且已经连接,new创建类是则不需要这个类加载过
3、newInstance: 弱类型(GC是回收对象的限制条件很低,容易被回收)、低效率、只能调用无参构造,new 强类型(GC不会自动回收,只有所有的指向对象的引用被移除是才会被回收,若对象生命周期已经结束,但引用没有被移除,经常会出现内存溢出
(注:newInstance实例化对象是只能调用无参构造方法,在A、B类中并没有构造方法,是因为每个创建的类都有一个默认的无参构造方法,如果你重写了一个带参构造方法,想要使用newInstance,则必须指定一个无参构造方法,否则会报初始化错误)
附: 通过反射 ResultSet 遍历取值
public static <T> List<T> paresList(Class<T> c , ResultSet resultSet) {
List<T> result = new ArrayList<>();
try {
// 获取当前返回数据字段名
ResultSetMetaData metaData = resultSet.getMetaData();
// 得到当前共有多少列
int count = metaData.getColumnCount();
// 得到列名 装到数组中 根据返回获取get,set方法
String[] clumnNames = new String[count];
for (int i = 0; i < clumnNames.length; i++) {
clumnNames[i] = metaData.getCatalogName(i+1);
}
Method[] methods = c.getDeclaredMethods();
while (resultSet.next()){
// 调取 class 无参构造方法
T instance = c.newInstance();
for (String name : clumnNames) {
name = "set" + name;
// 获取到返回数据 字段名
for (Method method : methods) {
// 遍历方法.
if (method.getName().equalsIgnoreCase(name)){
// 进行反射 调取方法赋值
method.invoke(instance,resultSet.getObject(name));
break;
}
}
}
result.add(instance);
}
} catch (SQLException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return result;
}
附: 自定义注解 + 反射 获取执行sql
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value=ElementType.TYPE)
// 用于指定数据库表名称
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String value();
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value=ElementType.FIELD)
//用于指定数据库的主键
@Retention(RetentionPolicy.RUNTIME)
public @interface PromaryKey {
String value();
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value=ElementType.METHOD)
// 用于指定数据表的列名称
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value();
}
//定义一个泛型类
public class BaseDao<T> {
public <V> String add(T t) {
/*
* 通过userBean自动生成insert语句
*insert into product(price,name,id) values('5000.0','iphone','1')
*/
Class clazz = t.getClass();//返回此 t的运行时类。
/*通过运行实类,可以调用反射中的
getDeclaredAnnotation(返回对象全部注解),
getDeclaredFields(返回对象的全部属性)
getDeclaredMethods(返回对象的全部方法)*/
Table table = (Table) clazz.getDeclaredAnnotation(Table.class);
String tableName = table.value();
Map<Object, Object> columnAndValue = getColumnAndValue(clazz, t);
//获取指定行视图和指定列中的单元格的值
Set<Entry<Object, Object>> set = columnAndValue.entrySet();
StringBuilder keys = new StringBuilder();
StringBuilder values = new StringBuilder();
for (Entry<Object, Object> entry : set) {
if(keys.length()>0) {
keys.append(",");
}
if(values.length()>0) {
values.append(",");
}
keys.append(entry.getKey());
values.append("'").append(entry.getValue()).append("'");
}
return "insert into "+tableName+"("+keys+") values("+values+")";
}
public String delete(T t) {
/*
* 通过userBean自动生成delete语句
*
* delete from product where id = 1
*/
Class clazz = t.getClass();
//获得Bean
//获取表名称
Table table = (Table) clazz.getDeclaredAnnotation(Table.class);
//getDeclaredAnnotation()返回直接存在于此元素上的所有注释
String tableName = table.value();
Map<Object, Object> columnAndValue = getColumnAndValue(clazz, t);
//获取指定行视图和制定列中的单元格的值
Set<Entry<Object, Object>> set = columnAndValue.entrySet();
List<Object> primaryKey = getPrimaryKey(clazz);
StringBuilder keysAndvalues = new StringBuilder();
for (Entry<Object, Object> entry : set) {
//上面这个是我没有用PrimaryKey注解时的写法,这个写过于鸡肋,因为如果主键的name不是id就不行了
if(primaryKey.contains(entry.getKey())){
keysAndvalues.append(entry.getKey()).append(" = ").append(entry.getValue());
}
}
return "delete from "+tableName+" where "+keysAndvalues;
}
public String update(T t) {
/*
* 通过ProductBean自动生成update语句
*
* update product set price = 5000.0 and name = iphone where id = 1
*/
Class clazz = t.getClass();
Table table = (Table) clazz.getDeclaredAnnotation(Table.class);
//getDeclaredAnnotation()返回直接存在于此元素上的所有注释
String tableName = table.value();
Map<Object, Object> columnAndValue = getColumnAndValue(clazz, t);
//获取指定行视图和制定列中的单元格的值
Set<Entry<Object, Object>> set = columnAndValue.entrySet();
List<Object> primaryKey = getPrimaryKey(clazz);
StringBuilder keysAndvalues = new StringBuilder();
StringBuilder FkeysAndvalues = new StringBuilder();
int i = 1;
for(Entry<Object, Object> entry : set){
if(primaryKey.contains(entry.getKey())){
FkeysAndvalues.append(" ").append(entry.getKey()).append(" = ").append(entry.getValue());
}
else{
if(1 <i && i < set.size()){
keysAndvalues.append(" and ");
keysAndvalues.append(entry.getKey()).append(" = ").append(entry.getValue());
}
else{
keysAndvalues.append(" ");
keysAndvalues.append(entry.getKey()).append(" = ").append(entry.getValue());
i++;
}
}
}
return "update "+tableName + keysAndvalues + " where "+FkeysAndvalues;
}
public String selete(T t) {
/*
* 通过userBean自动生成selete语句
*
* selete* from product where price = 5000.0 and name = iphone and id = 1
*/
Class clazz = t.getClass();
//获得Bean
//获取表名称
Table table = (Table) clazz.getDeclaredAnnotation(Table.class);
//getDeclaredAnnotation()返回直接存在于此元素上的所有注释
String tableName = table.value();
Map<Object, Object> columnAndValue = getColumnAndValue(clazz, t);
//获取指定行视图和制定列中的单元格的值
Set<Entry<Object, Object>> set = columnAndValue.entrySet();
StringBuilder keysAndvalues = new StringBuilder();
for (Entry<Object, Object> entry : set) {
if(keysAndvalues.length()>0) {
keysAndvalues.append(" and ");
}
keysAndvalues.append(entry.getKey()).append(" = ").append(entry.getValue());
}
return "selete* from "+tableName+" where "+keysAndvalues;
}
//按照<列明,属性>的格式输出所有的单元格
private Map<Object, Object> getColumnAndValue(Class<? extends T> clazz, T t) {
//首先声明了一个map键值对
Map<Object, Object> map = new HashMap<>();
//获取clazz类的所有方法
Method[] methods = clazz.getDeclaredMethods();
//获取的是类自身声明的所有方法,包含public、protected和private方法
for (Method method : methods) {
String methodName = method.getName();
if(methodName.startsWith("get")) {
//获得所有的get方法
Column column = method.getDeclaredAnnotation(Column.class);
// getDeclaredAnnotation(); //返回直接存在于此元素上的所有注释
//这个方法里放有参数时,返回指定类型的注解。如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
try {
map.put(column.value(), method.invoke(t));
//invoke执行方法
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
} // TODO Auto-generated catch block
}
}
return map;
}
private List<Object> getPrimaryKey(Class<? extends T> clazz){
List<Object> list = new ArrayList<>();
Field[] fields = clazz.getDeclaredFields();
//获得某个类的所有声明字段(id,name,price)
for (Field field : fields) {
if(field.isAnnotationPresent(PromaryKey.class)) {
//Package.isAnnotationPresent()如果指定类型的注释存在于此元素上,则返回true;否则flase
PromaryKey primaryKey = field.getDeclaredAnnotation(PromaryKey.class);
try {
list.add(primaryKey.value());
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
return list;
}
}
附 集合工具类
public class CollectionUtil {
public static <T> List<T> castList(Object obj, Class<T> clazz)
{
List<T> result = new ArrayList<T>();
if(obj instanceof List<?>)
{
for (Object o : (List<?>) obj)
{
result.add(clazz.cast(o));
}
return result;
}
return null;
}
/**
* 将源bean中的指定字段拷贝到目标map中
*/
public static void copyToMap(Object srcBean, Map<String, Object> destMap, List<String> fieldNameList, List<String> keyNameList) {
if (fieldNameList.size() != keyNameList.size()) {
throw new RuntimeException("字段集合和key集合的个数不一致,请检查后重新传入");
}
if (fieldNameList.size() == 0) {
return;
}
try {
int count = fieldNameList.size();
for (int i = 0; i < count; i++) {
String fieldName = fieldNameList.get(i);
String keyName = keyNameList.get(i);
// 转换为getter方法名
String methodName = getGetterMethodName(fieldName);
Method method = srcBean.getClass().getMethod(methodName);
Object value = method.invoke(srcBean);
if (value == null) {
// 给value一个默认值
value = getDefaultValue(method.getReturnType());
}
destMap.put(keyName, value);
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* field名称 -> getter方法名
*/
public static String getGetterMethodName(String fieldName) {
StringBuilder sb = new StringBuilder();
sb.append(fieldName);
if (Character.isLowerCase(sb.charAt(0))) {
if (sb.length() == 1 || !Character.isUpperCase(sb.charAt(1))) {
sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
}
}
sb.insert(0, "get");
return sb.toString();
// return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
}
private static Object getDefaultValue(Class<?> objectType) {
if (objectType.equals(String.class)) {
return "";
}
return null;
}
//Object转Map
public static Map<String, Object> getObjectToMap(Object obj) throws IllegalAccessException {
Map<String, Object> map = new LinkedHashMap<String, Object>();
Class<?> clazz = obj.getClass();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
String fieldName = field.getName();
Object value = field.get(obj);
if (value == null){
value = "";
}
map.put(fieldName, value);
}
return map;
}
public static String getMapToString(Map<String,Object> map){
Set<String> keySet = map.keySet();
//将set集合转换为数组
String[] keyArray = keySet.toArray(new String[0]);
//给数组排序(升序)
Arrays.sort(keyArray);
//因为String拼接效率会很低的,所以转用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keyArray.length; i++) {
// 参数值为空,则不参与签名 这个方法trim()是去空格
if ((String.valueOf(map.get(keyArray[i]))).trim().length() > 0) {
sb.append(keyArray[i]).append(":").append(String.valueOf(map.get(keyArray[i])).trim());
}
if(i != keyArray.length-1){
sb.append(",");
}
}
return sb.toString();
}
}