反射(Reflection)
1、概念
1.数据库
常见数据库:Oracle,MySQL,SQLServer(java中用的偏少,微软研发),DB2(IBM研发,银行领域用的偏多),SQLLite(用于移动端),
MySQL
目前是免费的,提供的是数据库最基本的操作,存储的数据量大概是千万级。
Oracle
收费的,存储的数据量达到上亿,售后服务良好。
2.集群(Cluster)
集群式一组相互独立的、通过高速网络互连的计算机,它们构成了一组,并以单一系统的模式加以管理。
3.耦合(Coupling)
模块之间绑定。程序结构中各个模块之间相互关联的度量。
4.解耦(Decoupling)
降低两个模块之间的依赖性。
高内聚,低耦合。
5.反射(Reflection)
反射主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
反射提供封装程序集、模块和类型对象。
反射其实是解剖类,分析类的字节码。产生类所对应的实例对象。
作用:
实现解耦操作,便于模块化开发。
2、反射中的类
1.Class class
代表字节码的类,代表类的类。每一个Class对象都对应了一个类/接口。
重要方法
forName(String className);
获取指定的字节码对象。
forName(String name,boolean initialize,ClassLoader loader);
getConstructor(Class< ?>…parameterTypes);
获取指定的公有构造函数。
Class<String> clz = String.class;
String(byte[],int,int)
// 只能获取public的构造函数
Constructor<String> c = clz.getConstructor(byte[].class, int.class,int.class);
String str = c.newInstance(new byte[] { 97, 98, 99, 100, 101, 102,103 }, 1, 3);
System.out.println(str);
getConstructors();
获取所有公有构造函数。返回的是一个构造函数数组。
// 表示获取String类中所有public的构造函数
Constructor[] cs = clz.getConstructors();
for (Constructor constructor : cs) {
System.out.println(constructor);
getDeclaredConstructor(Class< ?>…parameterTypes);
获取指定的构造函数。
// 表示获取指定的形式的构造函数
Constructor<String> c = clz.getDeclaredConstructor(char[].class, boolean.class);
// 暴力破解/暴力拆除
c.setAccessible(true);
String str = c.newInstance(new char[] { 'a', 'b', 'c' }, true);
System.out.println(str);
getDeclaredConstructors();
获取所有构造函数。返回的是一个构造函数数组。
getDeclaredField(String name);
获取指定属性。
getDeclaredFields();
获取所有属性,返回一个数组。
getDeclaredMethod(String name,Class< ?>…parameterTypes);
获取实例对象的方法,返回的是一个方法对象。
Class<String> clz = String.class;
String str = "abcdefg";
// 获取getBytes()
// byte[] bs = str.getBytes();
Method m = clz.getDeclaredMethod("getBytes");
// 执行方法对象
// 第一个参数表示方法作用的对象
// 第二个参数表示方法执行需要的实际参数
byte[] bs = (byte[]) m.invoke(str);
System.out.println(bs);
getDeclaredMethods();
获取所有方法。返回一个数组。
getField(String name);
获取公有属性。
getFields();
获取所有公有属性。
getInterfaces();
表示获取这个类或者接口实现的所有接口。返回的是一个数组类型。
Class<String> clz = String.class;
// 获取这个类/接口实现的所有接口
Class[] cs = clz.getInterfaces();
for (Class class1 : cs) {
System.out.println(class1);
}
getSuperclass();
获取父类。
getName();
获取全路径名称。
getSimpleName();
获取类名简称。
getPackage();
获取类所在包。
isAnonymousClass();
判断是否是匿名内部类。
isAssignableFrom();
判断参数是否是字节码对象的子类。
isInstance();
判断参数是否是字节码对象以及子类的实例。
isLocalClass();
判断是否是方法内部类。
isMemberClass();
判断是否是成员内部类。
isArray();
判断是否是数组。
isEnum();
判断是否是枚举。
isInterface();
判断是否是接口。
isPrimitive();
判断是否是基本类型。
newInstance();
创建一个字节码对象的实例。
获取Class对象的方法
1.通过类型名.class的方式来获取该类/接口/数组包括基本类型的字节码对象。可以添加泛型。
Class clz = String.class; //代表了String的字节码
Class<List> clz = List.class; //代表了List的字节码
Class<String[]> clz = String[].class; //代表了String[]数组的字节码
Class<int[]> clz = int[].class; //代表了int[]数组的字节码
Class clz = double.class; //代表了double的字节码
2.可以通过对象身上的getClass();方法获这个对象对应的实际类型的字节码对象。
Object str = "abc";
// 获取的对象的实际类型对应的字节码对象
@SuppressWarnings("unchecked")
Class<Object> clz = (Class<Object>) str.getClass();
System.out.println(clz);
3.通过Class.forName(类的全路径名);来获取指定的字节码对象。
// 获取代表String类的字节码
@SuppressWarnings("unchecked")
Class<String> clz = (Class<String>) Class.forName("java.lang.String");
System.out.println(clz);
产生实例对象的方法
1.通过Class类中的newInstance();方法来产生实例对象。这个方法要求实例对象所对应的类必须有无参构造方法。
// 获取了代表Object类的字节码?
@SuppressWarnings("unchecked")
Class<Object> clz = (Class<Object>)
Class.forName("java.lang.Object");
// 产生一个Object对象
// 要求这个类中必须有无参的构造函数
Object o = clz.newInstance();
System.out.println(o);
2.通过Class类中的getConstructor();方法来获取实例对象对应类的构造函数。
Class<Integer> clz = Integer.class;
// 获取构造函数
// 获取到了Integer类中Integer(String)的构造函数
// Integer in = new Integer("123");
Constructor<Integer> c = clz.getConstructor(String.class);
Integer in = c.newInstance("123");
System.out.println(in);
如果一个类只提供了含参构造,需要获取这个类中指定形式的构造函数对象,然后利用这个构造函数对象来产生度应对的实例对象;如果一个类提供了无参构造,那么这个时候可以利用这个类的字节码对象来产生实例对象
2.Constructor class
代表构造方法的类。
重要方法
setAccessible();
暴力破解、暴力拆除。
从AccessibleObject class继承过来的方法,Field,Method,也继承了这个类。
3.Method class
代表方法的类。
重要方法
invoke(Object o , Object… args);
第一个参数表示方法作用的对象;第二个参数表示方法执行需要的实际参数。如果返回值类型为void,则返回值为null。
Class<String> clz = String.class;
String str = "abcdefg";
// 获取getBytes()
// byte[] bs = str.getBytes();
Method m = clz.getDeclaredMethod("getBytes");
// 执行方法对象
// 第一个参数表示方法作用的对象
// 第二个参数表示方法执行需要的实际参数
byte[] bs = (byte[]) m.invoke(str);
System.out.println(bs);
Class<Demo> clz = Demo.class;
Demo d = new Demo();
// 如果返回值类型为void,则返回值为null
Method m = clz.getDeclaredMethod("m");
Object o = m.invoke(d);
System.out.println(o);
getAnnotation();
返回方法上带的注解。
getExceptionTypes();
获取这个方法抛出的异常。返回一个数组。
// 获取这个方法抛出的异常
Class[] es = m.getExceptionTypes();
for (Class class1 : es) {
System.out.println(class1);
}
getParameterTypes();
获取方法参数类型。
getReturnType();
获取方法的返回值类型。
getName();
获取方法名。
isVarArgs();
判断方法中是否含有可变参数。
4.Field class
代表属性的类。
重要方法
set(Object o,Object value);
设置属性值。
get(Object o);
获取属性值。
getType();
获取属性类型。
public class ClassDemo6 {
@SuppressWarnings("rawtypes")
public static void main(String[] args) throws Exception {
Class<String> clz = String.class;
String str = "abc";
// 获取指定的属性
// str.setHash(123);
Field f = clz.getDeclaredField("hash");
f.setAccessible(true);
// 设置属性值
f.set(str, 123);
// 获取属性值
System.out.println(f.get(str));
// 获取属性的声明类型
Class c = f.getType();
System.out.println(c);
}
}
5.Annotation class
代表注解的类。
6.Package class
代表包的类。
代码示例
为了省略简单的代码,我将两个类中的get和set方法都省略了,看的时候注意一下就行。
public interface Person {
public void eat();
public void work();
public void sax();
}
public class Doctor implements Person {
private String name;
private int age;
private char gender;
private Date entry;
private double salary;
//……对应get/set方法……
@Override
public void eat() {
System.out.println(name + "医生在手术室吃饭中~~~");
}
@Override
public void work() {
System.out.println(name + "医生在治病救人~~~");
}
@Override
public void sax() {
System.out.println(name + "医生缴税:" + salary * 0.5);
}
}
public class Teacher implements Person {
private String name;
private int age;
private char gender;
private Date entry;
private double salary;
//……对应get/set方法……
public void setEntry(Date entry) {
this.entry = entry;
}
@Override
public void eat() {
System.out.println(name + "老师在教室吃饭中~~");
}
@Override
public void work() {
System.out.println(name + "老师在教书育人~~~");
}
@Override
public void sax() {
System.out.println(name + "老师缴税:" + salary * 0.09);
}
}
public class ReflectionDemo {
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(String[] args) throws Exception {
while (true) {
// 读取Properties文件
Properties prop = new Properties();
FileInputStream in = new FileInputStream("config.properties");
prop.load(in);
in.close();
// 获取指定的类
Class<Person> clz = (Class<Person>) Class.forName(prop.getProperty("classname"));
// 根据字节码对象来产生对应的实例对象
Person p = clz.newInstance();
// 获取指定的属性
String[] attrnames = prop.getProperty("attrname").split("/");
// 获取属性值
String[] attrvalues = prop.getProperty("attrvalue").split("/");
for (int i = 0; i < attrnames.length; i++) {
// 获取属性对应的set方法的名字
String set = "set" + attrnames[i].substring(0, 1).toUpperCase() + attrnames[i].substring(1);
// 获取属性的类型
Class fc = clz.getDeclaredField(attrnames[i]).getType();
// 获取这个属性对应的set方法
Method m = clz.getDeclaredMethod(set, fc);
// 需要判断属性类型之后再赋值
if (fc == int.class || fc == Integer.class) {
m.invoke(p, Integer.parseInt(attrvalues[i]));
} else if (fc.equals(double.class) || fc.equals(Double.class)) {
m.invoke(p, Double.parseDouble(attrvalues[i]));
} else if (fc == char.class || fc == Character.class) {
// m.invoke(p, attrvalues[i].charAt(0));
m.invoke(p, attrvalues[i].toCharArray()[0]);
} else if (fc == Date.class) {
m.invoke(p, new SimpleDateFormat("yyyy-MM-dd").parse(attrvalues[i]));
} else {
m.invoke(p, attrvalues[i]);
}
}
// 获取这个指定的方法
Method m = clz.getDeclaredMethod(prop.getProperty("method"));
// 执行方法
m.invoke(p);
Thread.sleep(10000);
}
}
}