蔡香满屋
站在牛顿头上吃苹果

下面总结下Class常用的几种方法:

1.类中的方法:

1.int result = clazz.getModifiers(); // 获取类的修饰符(权限 特征)

每一个修饰符 用一个整数来进行表示

从0开始 ---0 1 2 4 8 16 32 64 129 256 512

0表示默认不写   1表示public  2表示private   4表示protected    8表示static 16表示final  32表示synchronized 64volatile

128表示transient  256表示native  512表示interface  1024表示abstract

2.String name = clazz.getName();  // 获取到的是包名.类名如testReflect.Person

3.String simpleName = clazz.getSimpleName();// 获取到的是类名Person

4.Package p = clazz.getPackage(); // 获取到的是包名 testReflect

5.Class sclazz = clazz.getSuperClass(); // 获取超类(父类)

6.Class[] classes = clazz.getModifiers(); 

7.Object obj = clazz.newInstance(); // 默认调用无参构造方法创建对象,如testReflect.Person@2a139a55

------------------------------------------------

2.Field类中的常用方法:

可以获取到属性的修饰符,返回值类型,属性名以及

8.属性值如以下这两个方法只能获取公有的属性,其中可以包含继承过来的父类属性:

Field f = clazz.getField("属性名);

Fields[] fs = clazz.getFields();

------------------------------

9.获取到的公有的和私有的属性方式,只能获取本类中的属性属性如:

Field f = clazz.getDeclaredField("name");

Fields[] f = clazz.getDeclaredFields();

获取到的私有属性进行操作该属性的方式如:

f.setAccessible(true); // 表示私有属性可以直接被修改。

获取私有的属性方式如:

创建java类如下:

public class Person {
	public String name; // public修饰表示该属性是公有的
	public int age; // public修饰表示该属性是公有
public String toString() { return "{" + name + "," + age + "}"; } }

如图:

为什么需要通过clazz.getField()获取到属性?

答:需要操作属性,一方面向里面存值或者另一方面从里面取值。

-------------------------

对比:

传统操作属性中的值的方式是:

对象 = new(); // 先创建对象空间,有了对象之后,对象空间里就有自己的一套元素(属性,方法)

于是就可以是使用对象.属性 = 值;

而我们使用反射机制创建对象方式是:

第一步:属性 = 类.getField();

第二步:属性.赋值(哪个对象,值);

总结:反射机制操作对象的步骤就好像跟传统方式的步骤相反似的。

例子如:

try {
			Class clazz = Class.forName("testReflect.Person");
			Person p = (Person)clazz.newInstance();
			Field nameField = clazz.getField("name");
			// 赋值
			nameField.set(p, "小蔡"); // p表示哪个对象要设置值,小蔡这个参数表示设置的值是什么
			System.out.println(p);
		} catch (Exception e) {
			e.printStackTrace();
		}

 传统访问属性中的值的方式是:

值 = 对象.属性

而反射机制中访问属性的方式是:

值 = 属性.取值(哪个对象)

如图效果:

 最后看下例子:

想要修改String类里面的值,也就是数组里面的值的实现方式:

代码如下:

public static void main(String[] args) {
		// 通过一个Class对象来操作Person.class类,
		// String里面的属性是private final char value[],也就是
		// String里面的属性是private final char[] value = {'a','b','c'}
		String str = new String("abc"); 
		System.out.println(str);
		// 反射的技术可以获取私有属性,可以操作私有属性,虽然不合理
		// 1.获取String类对应的那个Class
		Class clazz = str.getClass();
		// 2.通过claszz获取类中的value属性
		try {
			Field field = clazz.getDeclaredField("value");
			// 3.直接操作属性的值不可以设置私有属性,所以需要设置这个值为true
			field.setAccessible(true);
			// 4.获取value属性里面的值(内存地址)
			//String里面的属性是private final char[] value = {'a','b','c'},
			//注意:final表示是地址不让修改,而不是里面的值不让修改,我们可以找到地址找到真实的内容进行修改
			char[] temp = (char[])field.get(str);
			// 通过temp的地址引用 找到真实的String对象中的数组进行修改数组内的每一个元素
			temp[0] = '小';
			temp[1] = '菜';
			temp[2] = '好';
			System.out.println(temp);
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}

  输出:abc 

  小菜好

-----------------------------------------------------------------------------------

3.类中的方法:

int mm = m.getModifiers(); // 获取方法的修饰符(权限+特征)

Class mrt = m.getReturnType(); // 获取返回值数据类型

String mm = m.getName(); // 获取方法的名字

Class[] mpts = m.getParameterTypes(); // 获取方法参数列表的数据

Class[] mets = m.getExceptionTypes(); // 获取方法抛出异常的类型

同样如果该方法是private修饰的,则需要设置:

setAccessible(true); // 表示私有属性可以直接被修改。

获取到方法之后,如果操作方法呢?

使用方法.invoke(对象,执行方法需要传递的所有参数);

如:

// 获取Person对应的Class
Class clazz = Person.class;
Person p = (Person)clazz.newInstance();
// 通过clazz获取其中的方法,第一个参数是方法名,第二个是参数类型即Class<?>...
Method m = clazz.getMethod("eat", String.class);
m.invoke(p,"测试"); // 调用带参数地方法

首先创建Person类如下:

public class Person {
	public String name;
	public int age;
	
	public void eat() {
		System.out.println("我是吃的方法");
	}
	
	public void eat(String s, Integer a) {
		System.out.println("我是带参数的吃的方法");
	}
	
	public String toString() {
		return "{" + name + "," + age + "}";
	}
}

 然后实现如下:

// 获取Person对应的Class
		Class clazz = Person.class;
		// 通过clazz获取其中的方法,第一个参数是方法名,第二个是参数类型即Class<?>...
		try {
			Method m = clazz.getMethod("eat", String.class, Integer.class);
              int result = m.getModifiers(); // 方法修饰符(权限+特征)
              System.out.println(result); // 打印结果为1
              Class cl = m.getReturnType(); // 返回值数据类型
			System.out.println(cl); // 打印结果为void
			String name = m.getName(); // 获取方法的名字
			System.out.println(name); // 打印结果为eat
			Class[] mpts = m.getParameterTypes(); // 获取方法参数列表的类型
			for (Class mpt : mpts) {
			System.out.println(mpt.getName()); // 打印结果java.lang.String和java.lang.Integer
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

  其中getMethod实现如下:

@CallerSensitive
public Method getMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
Method method = getMethod0(name, parameterTypes, true);
if (method == null) {
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
}
return method;
}

  ------------------------------------------------------------------------------------------------------

构造方法(clazz.getConstructor(Class...参数类型)):

作用:因为

Class class = Class.forName(className);

Object object = class.newInstance(); // 只能调用无参构造函数

当一个对象中没有无参构造方式时,如果再想通过class.newInstance这样的方式是不行的,所以需要通过

Constructor conn = clazz.getConstructor(Class...参数类型)获取到有参构造函数,然后使用conn.newInstance()构造对象

posted on 2019-06-30 21:42  蔡香满屋  阅读(705)  评论(0)    收藏  举报