反射:内省的使用(避免一直使用暴力反射)
//通过内省技术:给一个字段的名字和字节码文件对象就可以得到关于该字段的设置和读取方法
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// new Test().setAge(-10);
Class clazz = Class.forName("com.practice922.Test");
Field field = clazz.getDeclaredField("age");
Object obj = clazz.newInstance();
field.setAccessible(true);
field.set(obj, -1);
System.out.println(obj);
}
}
class Test{
private int age;
public int getAge() {
return age;
}
public void setAge(int age) throws AgeException {
if(age<0||age>260){
throw new AgeException();
}
this.age = age;
}
@Override
public String toString() {
return "Test [age=" + age + "]";
}
}
自定义的Exception
public class AgeException extends Exception {
@Override
public String getMessage() {
return "年龄输入错误";
}
}
此时暴力反射强行写入,不会报错,不能使用。
内省
public static void main(String[] args) throws Exception {
// new Test().setAge(-10);
Class clazz = Class.forName("com.practice922.Test");
// Field field = clazz.getDeclaredField("age");
Object obj = clazz.newInstance();
// field.setAccessible(true);
// field.set(obj, -1);
// System.out.println(obj);
PropertyDescriptor pd = new PropertyDescriptor("age", clazz);
// 获取用于写入属性值的方法
Method writeMethod = pd.getWriteMethod();
writeMethod.invoke(obj, 18);
// 获取用于读属性值的方法
Method readMethod = pd.getReadMethod();
Object age = readMethod.invoke(obj, null);
System.out.println(age);
System.out.println(obj);
}
}
PropertyDescriptor pd = new PropertyDescriptor("age", clazz, "getage", "setage");直接获取读取属性值的方法
自定义类加载器(类的加密和用自己的加载器进行加载)
public class MyClassLoaderDemo {
public static void main(String[] args) throws Exception {
Person p = new Person();
System.out.println(p);
// 一个数异或一个数值两次,值是本身
// int a = 10;
// System.out.println(a = a ^ 89);
// System.out.println(a = a ^ 89);
byte[] bytes = XORClass("/Users/yoofale/Documents/JAVASEworkspace/Practice/bin/com/practice922/Person.class");
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
int len;
byte[] buf = new byte[1024];
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(
"/Users/yoofale/Documents/JAVASEworkspace/Practice/bin/com/practice922/Person.class"));
while ((len = bais.read()) != -1) {
bos.write(buf, 0, len);
bos.flush();
}
bos.close();
System.out.println("加密成功");
}
/**
*
* 加密或者解密字节码文件
*
* @param classPath
* @return 加密或者解密之后的文件数组
* @throws Exception
*/
public static byte[] XORClass(String classPath) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(classPath));
byte[] buf = new byte[1024];
int len;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((len = bis.read(buf)) != -1) {
baos.write(buf, 0, len);
baos.flush();
}
byte[] byteArray = baos.toByteArray();
// 将所有字节都异或成一个值,实现加密
for (int i = 0; i < byteArray.length; i++) {
byte b = byteArray[i];
byteArray[i] = (byte) (b ^ 32);
}
bis.close();
return byteArray;
}
}
自定义的加载器
public class MyClassLoder extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
// TODO Auto-generated method stub
byte[] bytes = ClassUtils.XORClass(name);
return defineClass(null, bytes, 0, bytes.length);
} catch (ClassFormatError | Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
}
封装的加密
public class ClassUtils {
/**
*
* 加密或者解密字节码文件
*
* @param classPath
* @return 加密或者解密之后的文件数组
* @throws Exception
*/
public static byte[] XORClass(String classPath) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(classPath));
byte[] buf = new byte[1024];
int len;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((len = bis.read(buf)) != -1) {
baos.write(buf, 0, len);
baos.flush();
}
byte[] byteArray = baos.toByteArray();
// 将所有字节都异或成一个值,实现加密
for (int i = 0; i < byteArray.length; i++) {
byte b = byteArray[i];
byteArray[i] = (byte) (b ^ 32);
}
bis.close();
return byteArray;
}
}
主程序
public class MyClassLoaderDemo {
public static void main(String[] args) throws Exception {
// Person p = new Person();
// System.out.println(p);
MyClassLoder classLoder = new MyClassLoder();
Class clazz = classLoder
.loadClass("/Users/yoofale/Documents/JAVASEworkspace/Practice/bin/com/practice922/Person.class");
System.out.println(clazz.newInstance());
}
// 一个数异或一个数值两次,值是本身
// int a = 10;
// System.out.println(a = a ^ 89);
// System.out.println(a = a ^ 89);
public static void test() throws Exception {
byte[] bytes = ClassUtils
.XORClass("/Users/yoofale/Documents/JAVASEworkspace/Practice/bin/com/practice922/Person.class");
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
int len;
byte[] buf = new byte[1024];
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(
"/Users/yoofale/Documents/JAVASEworkspace/Practice/bin/com/practice922/Person.class"));
while ((len = bais.read(buf)) != -1) {
bos.write(buf, 0, len);
bos.flush();
}
bos.close();
System.out.println("加密成功");
}
}