第一次更改:修复了反编译部分格式混乱的问题
第二次更改:解决了流没关掉的问题,加入的与注解联合使用的笔记,注解的相关笔记
问题:运行之后需要手动结束,不会随主方法结束而结束
如果有知道原因的大佬请指出并提供改正方案谢谢
分享一下自己做的反射机制笔记
要是觉得做的好请多多支持
有错误的或有更好的方法请大家提出来,一起进步ovo
写在评论里就好ovo
由于整理的时候涉及大量的复制粘贴,所以注释可能有混乱的地方
我检查了一遍,如果有发现的也请提出
中间还有关于两种转码 / 规避乱码的方式,所以测试时请不要把编码方式设置为UTF-8
(因为我的eclipse默认是GBK啊我好难)
目录
反射源代码(笔记)部分
package learning;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Timer;
public class Reflection {
//反射机制
//可以读和修改字节码文件(.class)
/*
* 重要的类:
* java.lang.Class 整个字节码
* java.lang.reflect.Method 方法字节码
* java.lang.reflect.Constructor 构造方法字节码
* java.lang.reflect.Field 属性字节码
*/
@SuppressWarnings({ "rawtypes", "unused", "deprecation" })
public static void main(String[] args) {
/** 第一个操作:获取Class */
//方法一
//静态方法,实参是完整包名+类名,可能找不到
//用这个可以实现只执行静态代码块,因为这个方法的执行导致类加载
Class c1 = null;
try {
c1 = Class.forName("learning.TestReflection");
System.out.println("full name: " + c1.getName());
System.out.println("simple name: " + c1.getSimpleName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//方法二
//Java任何一个引用数据类型都有的getClass()
TestReflection tr = new TestReflection("testing", 0xabcd);
Class<?> c2 =tr.getClass();
//而且,
System.out.println("c1和c2一样:" + (c1 == c2));
//因为字节码文件装载到JVM中时,只装一个
//方法三
//Java任何一个 → 类型 ← 都有属性class
Class<TestReflection> c31 = TestReflection.class;
Class<Integer> c32 = int.class;
/** 第二个操作:通过Class来实例化对象 */
//方法一
//newInstance()方法会自动调用类的无参构造器,创建对象
//要是没无参就给你报异常
Object obj = null;
try {
obj = c1.newInstance();
System.out.println("is TestReflection: "
+ (obj instanceof TestReflection));
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
//利用属性配置文件来创建对象
//这种方式比较灵活(符合OCP开闭原则,对扩展开放,对修改关闭)
Properties pro = new Properties();
FileReader fr = null;
try {
fr = new FileReader("F:\\learning\\src\\learning\\"
+ "use for testing reflection.properties");
pro.load(fr);
Class cpro = Class.forName(pro.getProperty("class"));
Object cobj = cpro.newInstance();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}finally {
if(fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/** 第三个操作:获取类路径下文件的绝对路径 */
//这样即使代码移植了也不会有影响,是通用的
//方式在src下的都是在类路径下,这时可以这种方法
//src是类的根路径
/*
* 努力一下,把它记住
* Thread.currentThread();当前线程对象
* getContextClassLoader();获取当前线程的类加载器对象
* getResource(String name);当前线程类加载器默认从src下加载资源,返回URL
* getPath();获取绝对路径
*/
//记得在括号里填src下的路径,不要直接写文件名
//但是这样会乱码耶
System.out.println(Thread.currentThread().
getContextClassLoader().
getResource("learning/use for testing reflection.properties").
getPath());
//不乱码方式一
//用URLDecoder.decode(String s, String enc);方法重新编码
//其实直接改properties改成UTF-8也可以,要不是因为笔记做太多了懒得改我才不用qwq
try {
System.out.println(URLDecoder.decode(Thread.currentThread().
getContextClassLoader().
getResource("learning/use for testing reflection.properties").
getPath(), "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//不乱码方式二
//把返回的URL转换成URI
try {
System.out.println(Thread.currentThread().
getContextClassLoader().
getResource("learning/use for testing reflection.properties").
toURI().getPath());
} catch (URISyntaxException e) {
e.printStackTrace();
}
//资源绑定器
//只能绑定属性配置文件,且文件必须在类路径下
//写路径时,文件扩展名(.properties)不写
ResourceBundle bundle =
ResourceBundle.getBundle("learning/use for testing reflection");
String className = bundle.getString("class");
System.out.println("资源绑定器:" + className);
/** 第四个操作:和流联合使用 */
String path = null;
try {
path = Thread.currentThread().
getContextClassLoader().
getResource("learning/use for testing reflection.properties").
toURI().getPath();
} catch (URISyntaxException e1) {
e1.printStackTrace();
}
//可以用FileReader,不过还有一种方法
FileReader properties = null;
InputStream reader = null;
try {
properties = new FileReader(path);
Properties test = new Properties();
test.load(properties);
//获取value
System.out.println(test.getProperty("class"));
//-----------------------------------------------------------
//or
//直接以流的形式返回
reader = Thread.currentThread().
getContextClassLoader().
getResourceAsStream("learning/"
+ "use for testing reflection.properties");
test.load(reader);
System.out.println(test.getProperty("class"));
} catch (IOException e) {
e.printStackTrace();
}finally {
if(properties != null) {
try {
properties.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("//===================================================");
/** 第五个操作:获取Field */
System.out.println("Field: ");
//获取类中所有public修饰的Field
Field[] Pfields = c1.getFields();
System.out.println("length: " + Pfields.length);
//好像长度是0哈
//--------------------------------------------------------------------
//获取所有的Field
Field[] fields = c1.getDeclaredFields();
System.out.println("length: " + fields.length);
//啊好,有长度了,那来遍历一下
for(Field f: fields) {
System.out.println("//-------------------------------------");
//获取整个变量
System.out.println(f);
//获取名字
System.out.println("name: " + f.getName());
//获取完整类型
System.out.println("full type: " + f.getType());
//获取简单类型
System.out.println("simple type: " + f.getType().getSimpleName());
//获取修饰符列表,返回一个数字,每个数字是修饰符列表的代号
System.out.println("modifiers number: " + f.getModifiers());
//获取修饰符列表的名称
System.out.println("modifiers name: "
+ Modifier.toString(f.getModifiers()));
}
System.out.println("//===================================================");
/** 第六个操作:获取Method */
System.out.println("Method: ");
//获取类中所有的,所有的,所有的方法,包括private,但是没有构造器
Method[] methods = c1.getDeclaredMethods();
System.out.println("length: " + methods.length);
//那来遍历一下
for(Method m: methods) {
System.out.println("//-------------------------------------");
//获取整个变量
System.out.println(m);
//获取名字
System.out.println("name: " + m.getName());
//获取返回值类型
System.out.println("full return type: " + m.getReturnType());
//获取简单返回值类型
System.out.println("simple return type: "
+ m.getReturnType().getSimpleName());
//获取修饰符列表,返回一个数字,每个数字是修饰符列表的代号
System.out.println("modifiers number: " + m.getModifiers());
//获取修饰符列表的名称
System.out.println("modifiers name: "
+ Modifier.toString(m.getModifiers()));
//获取参数列表
System.out.print("parameter types: ");
Class[] parameterTypes = m.getParameterTypes();
if(parameterTypes.length == 0) {
System.out.print("null");
}else {
for(Class parameterType: parameterTypes) {
System.out.print(parameterType.getSimpleName() + " ");
}
}
System.out.println();
}
System.out.println("//===================================================");
/** 第七个操作:获取Constructor */
System.out.println("Constructor: ");
//可以反射构造器了
Constructor[] constructors = c2.getConstructors();
//遍历
for(Constructor c: constructors) {
System.out.println("//-------------------------------------");
//获取整个变量
System.out.println(c);
//获取名字
System.out.println("name: " + c.getName());
//获取修饰符列表,返回一个数字,每个数字是修饰符列表的代号
System.out.println("modifiers number: " + c.getModifiers());
//获取修饰符列表的名称
System.out.println("modifiers name: "
+ Modifier.toString(c.getModifiers()));
}
//操作五六七其实没有什么太大的区别,背出Method就好了
System.out.println("//===================================================");
/** 第八个操作:获取Annotation */
System.out.println("Annotation: ");
//注解也可以被反射(要加RUNTIME)
//判断类上面有没有@Annotation注解
System.out.println("has @annotation: "
+ c2.isAnnotationPresent(Annotation.class));
//如果有注解,获取该注解对象
if(c2.isAnnotationPresent(Annotation.class)) {
Annotation anno = c2.getAnnotation(Annotation.class);
//获取名字
System.out.println("the annotation on TestReflection: " + anno);
}
//同理,获取方法上的注解对象
try {
Method annoMethod =
c2.getMethod("printString");
if(annoMethod.isAnnotationPresent(Annotation.class)) {
Annotation anno = annoMethod.getAnnotation(Annotation.class);
System.out.println("the annotation on "
+ annoMethod.getName() + ": " + anno);
}
} catch (NoSuchMethodException e2) {
e2.printStackTrace();
} catch (SecurityException e2) {
e2.printStackTrace();
}
//其他都一样的啊都一样的
System.out.println("//===================================================");
/** 第九个操作:用反射访问类中的元素 */
//这种方式的程序扩展性强
//修改/获取属性的值
for(Field f: fields) {
try {
//实例化TestReflection对象(重新实例化是因为之前实例化的距离太远看不到)
obj = c2.newInstance();
//获取change属性
Field field = c2.getDeclaredField("change");
//赋值(如果可以的话)
field.set(obj, 142857);
//获取
if(f.getName() == "change") {
System.out.println("change = " + field.get(obj));
}
//访问私有属性
Field priField = c2.getDeclaredField("no");
//顺便改改
//首先要打破封装
priField.setAccessible(true);
priField.set(obj, 758241);
//获取
if(f.getName() == "no") {
System.out.println("no = " + priField.get(obj));
}
//解释一下为啥先输出no再输出change
//因为写类的时候no写在前面
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
//通过反射机制调用方法
//获取方法
try {
//设置名字
Field name = c2.getDeclaredField("name");
name.setAccessible(true);
name.set(obj, "testing");
//-------------------------------------------------------------------
Method method = c2.getDeclaredMethod("printString", String.class);
//调用方法
method.invoke(obj, "qwq");
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
//通过反射机制调用构造方法
//调用无参构造器创建对象咱都会
//要知道怎么调用有参数构造器
try {
Constructor cons = c2.getConstructor(String.class, int.class);
//然后常规操作new对象
try {
Object objTR = cons.newInstance("Alexander", 67);
//测试
if(objTR instanceof TestReflection) {
TestReflection trn = (TestReflection)objTR;
System.out.println("fields: " + trn.getName() + ", "
+ trn.getNo());
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
}
//通过反射机制访问注解
Annotation anno = c2.getAnnotation(Annotation.class);
//获取属性
String[] values = anno.value();
//哎是个数组,那遍历
for(String value: values) {
//用法和接口差不多
System.out.println("element -> " + value);
}
System.out.println("//===================================================");
/** 第十个操作:反编译 */
StringBuilder sb = new StringBuilder();
//反编译Annotation
sb.append(c2.getAnnotation(Annotation.class));
sb.append('\n');
//反编译Class
String classModifiers = Modifier.toString(c1.getModifiers());
sb.append(classModifiers + "class " + c1.getSimpleName() + " {\n");
//反编译Field
sb.append(" //Field");
for(Field f: fields) {
sb.append('\n');
sb.append(" ");
sb.append(Modifier.toString(f.getModifiers())
+ " " + f.getType().getSimpleName()
+ " " + f.getName());
//获取属性的值
try {
//获取序列化版本号
Field serField = c2.getDeclaredField("serialVersionUID");
//获取
serField.setAccessible(true);
if(f.getName() == "serialVersionUID") {
sb.append(" = " + serField.get(obj) + "L");
}
//获取change属性
Field field = c2.getDeclaredField("change");
//获取
if(f.getName() == "change") {
sb.append(" = " + field.get(obj));
}
//访问私有属性
Field priField = c2.getDeclaredField("no");
priField.setAccessible(true);
//获取
if(f.getName() == "no") {
sb.append(" = " + priField.get(obj));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
sb.append(';');
}
sb.append("\n\n");
//反编译Method
sb.append(" //Method\n");
for(Method m: methods) {
sb.append(" ");
//前面的部分
sb.append(Modifier.toString(m.getModifiers())
+ " " + m.getReturnType().getSimpleName()
+ " " + m.getName()
+ "(");
//打印实参列表
Class[] parameterTypes = m.getParameterTypes();
if(parameterTypes.length != 0) {//若长度不为零
for(int i = 0; i < parameterTypes.length - 1; i++) {
sb.append(parameterTypes[i].getSimpleName());
sb.append(", ");
}
//最后一个参数不需要加", "所以单独输出
sb.append(parameterTypes[parameterTypes.length - 1].getSimpleName());
//另外一种输出方法:实参列表都输出完之后调用
//sb.deleteCharAt(sb.length - 1);
//再调用一次
//sb.deleteCharAt(sb.length - 1);
//同样可以去掉", "
//别问为什么不用,问就是做笔记时候忘记了然后懒得改
}
sb.append(") {\n");
sb.append(" }\n\n");
}
//反编译Constructor
sb.append(" //Constructor\n");
for(Constructor c: constructors) {
sb.append(" ");
//前面
sb.append(Modifier.toString(c.getModifiers())
+ " " + c1.getSimpleName()
+ "(");
//实参列表
Class[] conPar = c.getParameterTypes();
for(Class cPar: conPar) {
sb.append(cPar.getSimpleName());
sb.append(", ");
}
sb.deleteCharAt(sb.length() - 1);
sb.deleteCharAt(sb.length() - 1);
sb.append(") {\n }\n");
}
sb.append('\n');
sb.append("}");
System.out.println(sb);
/** 第十一个操作:获取父类,父接口 */
//获取父类
Class superClass = c2.getSuperclass();
System.out.println("super class: " + superClass.getSimpleName());
//获取父接口
Class[] superInterfaces = c2.getInterfaces();
for(Class superInterface: superInterfaces) {
System.out.println("不好意思啊就一个接口: "
+ superInterface.getSimpleName());
}
}
}
//测试类(就不麻烦其他类了)
@Annotation({"class", "interesting"})
class TestReflection extends Timer implements Serializable{
private static final long serialVersionUID = 1L;
//静态代码块只在类加载时运行一次
static {
System.out.println("class TestReflection ready!!!");
}
private String name;
private int no;
@Annotation("field!")
public int change = 100;
public TestReflection() {
//newInstance()自动调用无参构造器
//测试下面内容时自行注释或解注释,不然很烦
// System.out.println("new TestReflection: " + this.toString());
}
public TestReflection(String name, int no) {
this.name = name;
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
private String returnString(String s1, String s2) {
return s1 + s2;
}
@Annotation("method!")
public void printString() {
System.out.println(returnString(name, ": hey my dear!"));
}
public void printString(String str) {
System.out.println(returnString(name, ": hey my dear! " + str));
}
}
注解源代码(笔记)部分
package learning;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//自定义注解
//加入元注解
@Target(value = {ElementType.METHOD, ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)//可以被反射
public @interface Annotation {
//关于注解
//效果去看learning.TestReflection
/**
* 注解,或者叫注释类型(不是注释,而是注释类型)
* 注解可以出现在各种地方
*
* 内置的注解
* Deprecated:
* 凡是用@Deprecated注释的程序元素,并不鼓励使用这种元素,通常因为危险或有更好的选择
* 表示某个元素已过时,向其他程序员传达信号,有更好的选择存在
* Override:
* 表示一个方法重写父类方法(谁都会)
* 只能注解方法,是给编译器参考的,和运行没有关系
* 如果带有这个注解的方法不是重写父类的方法,编译器报错
* SuppressWarnings:
* 指在注释元素中取消指定的编译器警告(谁都会)
*
* 元注解:指用于标识注解类型的注解
* 常见的有Target, Retention
* Target注解用于标注注解可以出现在哪些位置上
* Retention注解用于标注注解最终保存在哪里
* @Retention(RetentionPolicy.SOURCE):保存在Java源文件中
* @Retention(RetentionPolicy.CLASS):保存在class文件中
* @Retention(RetentionPolicy.RUNTIME):保存在class文件中且可以被反射
*
*/
//定义属性
//看起来是方法,但我们叫它属性
//当属性是value的时候属性名可以省略不写
//如果一个注解里有属性,则必须给属性赋值
//指定默认值后,这个属性可写可不写
//不是数组的属性类型可以是:byte short int long float double boolean char String Class
//属性也可以是上面类型的数组数组,枚举类型及其数组
//如果数组中只有一个元素,则大括号可以省略不写
String[] value() default "no!!!";
}
运行结果应该是这样的
class TestReflection ready!!!
full name: learning.TestReflection
simple name: TestReflection
c1和c2一样:true
is TestReflection: true
/F:/learning/bin/learning/use%20for%20testing%20reflection.properties
/F:/learning/bin/learning/use for testing reflection.properties
/F:/learning/bin/learning/use for testing reflection.properties
资源绑定器:learning.TestReflection
learning.TestReflection
learning.TestReflection
//===================================================
Field:
length: 1
length: 4
//-------------------------------------
private static final long learning.TestReflection.serialVersionUID
name: serialVersionUID
full type: long
simple type: long
modifiers number: 26
modifiers name: private static final
//-------------------------------------
private java.lang.String learning.TestReflection.name
name: name
full type: class java.lang.String
simple type: String
modifiers number: 2
modifiers name: private
//-------------------------------------
private int learning.TestReflection.no
name: no
full type: int
simple type: int
modifiers number: 2
modifiers name: private
//-------------------------------------
public int learning.TestReflection.change
name: change
full type: int
simple type: int
modifiers number: 1
modifiers name: public
//===================================================
Method:
length: 7
//-------------------------------------
public java.lang.String learning.TestReflection.getName()
name: getName
full return type: class java.lang.String
simple return type: String
modifiers number: 1
modifiers name: public
parameter types: null
//-------------------------------------
public void learning.TestReflection.setName(java.lang.String)
name: setName
full return type: void
simple return type: void
modifiers number: 1
modifiers name: public
parameter types: String
//-------------------------------------
public void learning.TestReflection.printString()
name: printString
full return type: void
simple return type: void
modifiers number: 1
modifiers name: public
parameter types: null
//-------------------------------------
public void learning.TestReflection.printString(java.lang.String)
name: printString
full return type: void
simple return type: void
modifiers number: 1
modifiers name: public
parameter types: String
//-------------------------------------
public int learning.TestReflection.getNo()
name: getNo
full return type: int
simple return type: int
modifiers number: 1
modifiers name: public
parameter types: null
//-------------------------------------
public void learning.TestReflection.setNo(int)
name: setNo
full return type: void
simple return type: void
modifiers number: 1
modifiers name: public
parameter types: int
//-------------------------------------
private java.lang.String learning.TestReflection.returnString(java.lang.String,java.lang.String)
name: returnString
full return type: class java.lang.String
simple return type: String
modifiers number: 2
modifiers name: private
parameter types: String String
//===================================================
Constructor:
//-------------------------------------
public learning.TestReflection(java.lang.String,int)
name: learning.TestReflection
modifiers number: 1
modifiers name: public
//-------------------------------------
public learning.TestReflection()
name: learning.TestReflection
modifiers number: 1
modifiers name: public
//===================================================
Annotation:
has @annotation: true
the annotation on TestReflection: @learning.Annotation({"class", "interesting"})
the annotation on printString: @learning.Annotation({"method!"})
//===================================================
no = 758241
change = 142857
testing: hey my dear! qwq
fields: Alexander, 67
element -> class
element -> interesting
//===================================================
@learning.Annotation({"class", "interesting"})
class TestReflection {
//Field
private static final long serialVersionUID = 1L;
private String name;
private int no = 758241;
public int change = 142857;
//Method
public String getName() {
}
public void setName(String) {
}
public void printString() {
}
public void printString(String) {
}
public int getNo() {
}
public void setNo(int) {
}
private String returnString(String, String) {
}
//Constructor
public TestReflection(String, int) {
}
public TestReflectio) {
}
}
super class: Timer
不好意思啊就一个接口: Serializable