目录
1.反射机制有什么用?
通过反射可以操作字节码文件,有点类似于黑客可以读和修改字节码文件。
2.与反射有关的类在那个包下?
java.lang.reflect.*包下
3.与反射有关的类有哪些?
java.lang.Class
java.lang.reflect.Field
java.lang.reflect.Method
java.lang.reflect.Construct
4.如何获取一个类的字节码?
要想操作字节码文件就先获取字节码文件,如何获取字节码文件?
三种方式:
(1).通过Class中的静态方法class.forname(string name);如class.forname("java.lang.string");
(2)任何对象都有getclass()方法;如string a="123"; a.getclass();
(3)任何类型都有class属性,int.class
5.案例展示
package com.test;
import java.lang.reflect.Field;
public class TestMain {
@SuppressWarnings("deprecation")
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//第一种方式
Class c=Class.forName("com.test.User");
Object object=c.newInstance();
System.out.println(object);
//第二种方式
String string="abc";
Class c2= string.getClass();
Object object2= c2.newInstance();
System.out.println(object2);
//第三种方式
System.out.println(Integer.class);
}
}
6.获取class能干什么?
通过class的newinstance()方法来实例化对象
注意:默认情况下调用newinstance()无参构造方法,所以给定一无参构造是前提
要了解的有关反射field,反射method,反射construct 的知识点大部分是学习方法,所以下面这三部分内容的知识点均在代码中讲解,且下面的三个都要创建一个user类(不一定是user,也可以是其他的,或者是sun公司定义好的,那个用的顺手用哪个),包括上面那个案例也是用的user类,只是没有在上面给出
利用反射反编译field或method,又或者是construct,需要进行大量字符串拼接,这时候用string就不太合适了,一般用stringbuilder或stringbuffer,期末结束后会出一期关于string,stringbuffer,stringbuiler的文章
package com.test;
public class User {
private String nameString;
protected int age;
public String sexString;
int id;
public User() {
super();
}
public User(String nameString, int age, String sexString, int id) {
super();
this.nameString = nameString;
this.age = age;
this.sexString = sexString;
this.id = id;
}
public String getNameString() {
return nameString;
}
public void setNameString(String nameString) {
this.nameString = nameString;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSexString() {
return sexString;
}
public void setSexString(String sexString) {
this.sexString = sexString;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void work() {
System.out.println("nihao!");
}
public int sum(int a,int b) {
int z=a+b;
return z;
}
}
7.通过反射反编译field
package com.test;
import java.lang.reflect.Field;
import java.nio.file.WatchEvent.Modifier;
/*
* field 翻译为字段,其实就是属性/成员变量
*
* */
public class TestMain {
@SuppressWarnings("deprecation")
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Class c=Class.forName("com.test.User");
//调用的是newinstance()的无参构造方法,所以必须在user中有无参构造方法
Object object=c.newInstance();
//获取user中的属性的方法,并且可以通过下面的的length属性验证一下
Field[] fields = c.getFields();
/*
* 下面输出结果为1,咦,这是为什么呢?明明有四个属性啊,结果应该是4啊,
* 考虑一下是不是我们方法写错了,如果写错了的话,下面应该会报错啊,但为什么会有输出结果呢?
* 这个时候可以考虑一下它输出的这个“1”是什么呢?是只把第一个属性算进去吗,我们可以通过输出field【0】在验证一下
* 我可以提前告诉大家输出结果:public java.lang.String com.test.User.sexString,它既不是第一个,也不是最后一个
* 这个时候你是否会发现他们前面的修饰类型不一样,这时候我们就找到根因了,通过这个方法只能获取被public修饰的属性
* */
System.out.println(fields.length);
Field field=fields[0];
System.out.println(field);
//要想获取所有的属性就得通过下面这个方法,通过length属性验证一下
Field[] fields2 = c.getDeclaredFields();
System.out.println(fields2.length);//此时得到的结果就是4啦,接下来就是不如正题,如何给他反射出来呢
for(Field f:fields2) {
//获取属性的修饰列表
String string = java.lang.reflect.Modifier.toString(f.getModifiers());
//获取属性的类型
String type= f.getType().getSimpleName();
//获取属性的名字
String name = f.getName();
//输出验证一下
System.out.println(string+" "+type+" "+name);
}
System.out.println("下面是获取某个属性========================================================start");
/*如果只想获取某个属性,可以用下面这个方法,同样这个方法也只能是获取被public修饰的属性,
* 但可以打破封装,但这样就会给不发分子留下机会
* 不过打破封装之后就可以访问私有属性了
* 给一个对象赋值最重要的就是属性,对象,值三要素,缺一不可
*/
Field field2=c.getDeclaredField("nameString");
//打破封装,如果没有这句话是会报错的,大家可以把这句话删掉进行验证一下
field2.setAccessible(true);
//给这个属性赋值
field2.set(object, "zhang");
Object name = field2.get(object);
System.out.println(name);
//sex这个属性本身就是public类型的,可以直接进行赋值和读取
Field sex1 = c.getDeclaredField("sexString");
sex1.set(object, "女");
Object sex = sex1.get(object);
System.out.println(sex);
}
}
8.通过反射反编译method
在给出具体代码之前先说一下可变长参数
(1)可变长参数格式:类型 ...(一定是三个点)
(2)可变长参数需要注意的三个事项
- 参数可以有0~n个
- 可变长参数只能出现在参数里列表的末尾,而且可变长参数之能有一个
- 可变长参数可看作数组
(3)举例
在主方法里可以用sum()、或sum(1,4,6,3,2)或其他的都可以调用sum()方法
public static int sum(int ...args){
}
步入正题,将通过反射反编译出方法
package com.test;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class TestMain01 {
/*
* 获取方法和获取属性是一样的,就是照葫芦画瓢的事
* 唯一不同的就是获取参数列表
* */
@SuppressWarnings("deprecation")
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Class<?> class1=Class.forName("com.test.User");
//Object object=class1.newInstance();
//获取方法
Method[] method=class1.getDeclaredMethods();
for(Method m:method) {
//获取修饰列表
String list = Modifier.toString(m.getModifiers());
//获取返回值类型
String returnType = m.getReturnType().getSimpleName();
//获取函数名字
String nameString=m.getName();
//获取参数列表
Class<?>[] parameterTypes = m.getParameterTypes();
String nameString2="";
for(Class c:parameterTypes) {
nameString2=c.getSimpleName();
}
System.out.println(list+" "+returnType+" "+" "+nameString+"("+ nameString2+")");
}
System.out.println("获取某个方法==============================================start");
//下面要用到可变长参数
Object object=class1.newInstance();
Method method2=class1.getDeclaredMethod("sum", int.class,int.class);
Object integer=method2.invoke(object, 4,6);
System.out.println(integer);
}
}
9.利用反射反编译construct
package com.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
public class TestMain02 {
//利用反射反编译consrtuct,和前面一样也是照葫芦画瓢的事
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Class class1 = Class.forName("com.test.User");
//获取构造方法
Constructor[] constructor= class1.getDeclaredConstructors();
for(Constructor c:constructor) {
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(Modifier.toString(c.getModifiers()));
stringBuilder.append(" ");
stringBuilder.append(class1.getSimpleName());
stringBuilder.append("( ");
Class[] class2= c.getParameterTypes();
for(Class c1:class2) {
stringBuilder.append(c1.getSimpleName());
stringBuilder.append(",");
}
stringBuilder.deleteCharAt((stringBuilder.length()-1));
stringBuilder.append("){");
stringBuilder.append('\n');
stringBuilder.append("}");
System.out.println(stringBuilder);
}
System.out.println("获取某个构造方法=================================================start");
//获取有参构造
Constructor constructor2= class1.getDeclaredConstructor(String.class,int.class,String.class,int.class);
Object user1=constructor2.newInstance("张三",12,"男",100);
System.out.println(user1);
//获取无参构造
Constructor constructor3=class1.getDeclaredConstructor();
Object user2=constructor3.newInstance();
System.out.println(user2);
}
}
今天的故事到此结束!
写在文章末尾的话:坚持!加油!