Java中的反射机制

目录

1.反射机制有什么用?

2.与反射有关的类在那个包下?

3.与反射有关的类有哪些?

4.如何获取一个类的字节码?

5.案例展示

6.获取class能干什么?

7.通过反射反编译field

8.通过反射反编译method

9.利用反射反编译construct


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);
		}

}

今天的故事到此结束!

写在文章末尾的话:坚持!加油!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值