黑马程序员-反射

---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ---------------------

Java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class

获取类的字节码的方式(3种):

1、Class类中的forName()方法:

Eg

String className=”java.lang.String ”;
 Class clazz=Class.forName(className);

2、类名.class   eg:Person.class

3、Object类中的getClass()方法(对象.getClass())

使用过程中主要使用第一种

  

         Class中有九个预定义的基本类型的字节码,分别是:byte.class,short.class,int.class,long.class,char.class,float.class,double.class,boolean.class,void.class

     可以用Class中的isPrimitive()方法来判断是否是基本类型的字节码,另外

   Int.class==Integer.class(输出结果:false)

   Int.class==Integer.TYPE(输出结果:true)

     还可以判断一份字节码文件是否是数组字节码文件,int[].class.isArray();

反射概念:反射就是把一个java类中的各个成分解析成相应的java

列如:一个java类包含成员变量、方法、构造方法、包等信息,在Class类中显然提供了一系列的方法来获取这些成员对应的一个实例对象,这些实例对象对应的类分别为FieldMethodContructorPackage等等

  列如:在System类中有两个静态方法,分别是:System.exit()System.getProperties();那么这两个方法分别为Method类的实例 

    得到一个类中的所有构造方法:

Constructor[] con1=Class.forName("java.lang.String").getConstructors();

得到一个类中某个构造方法:

Constructor con2=Class.forName("java.lang.String").getConstructor(String.class);

利用反射的方法创建一个String对象:
Constructor con2=Class.forName("java.lang.String").getConstructor(String.class);

String str=(String)con2.newInstance("abc");

   关于反射无参构造方法:

     Constructor com3=Class.forName("java.lang.String").getConstructor();

String s1=(String) com3.newInstance();

  也可以直接:

String s2=(String) Class.forName("java.lang.String").newInstance();

Field

  一个Field类的对象代表了一个类中的一个成员变量

  Field类中的知识点:

定义一个Point类,然后在FieldReflect类中对Point类进行反射

Point 

public class Point {

	private int x;
	public int y;

	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}

}

FieldReflect

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class FieldReflect {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		Class clazz = Class.forName("Point");
		Constructor con = clazz.getConstructor(int.class, int.class);
		Point point = (Point) con.newInstance(1, 2);
		Field field1 = clazz.getField("x");
		Field field2 = clazz.getField("y");
		int x = (int) field1.get(point);
		int y = (int) field2.get(point);
		System.out.println(x + "          " + y);

	}

}

输出结果:

这是因为xprivate,所以造成错误,那么有没有办法可以解决呢?

修改如下(field.getDeclaredField(),又叫暴力访问)

  Field field1=clazz.getDeclaredField("x");

field1.setAccessible(true);

实例:给出一个对象,将这个对象中的所有是字符串的字段值修改

Original

package ModifyString;

public class original {

	private String str1 = "basketball";
	private String str2 = "ball";
	private String str3 = "badminton";

	public String toString() {
		return str1 + "        " + str2 + "      " + str3;
	}
}

ReflectTest

package ModifyString;

import java.lang.reflect.Field;

public class ReflectTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		Class clazz = Class.forName("ModifyString.original");
		Field[] fields = clazz.getDeclaredFields();
		original or = (original) clazz.newInstance();
		for (Field field : fields) {
			field.setAccessible(true);
			if (field.getType() == java.lang.String.class) {
				String str = (String) field.get(or);
				String newstr = str.replace('a', 'b');
				field.set(or, newstr);
			}
		}
		System.out.println(or);

	}

}

获取指定Class中的方法:(类的方法而不是对象的方法)

String str="abc";

Method method=String.class.getMethod("charAt"int.class);

System.out.println(method.invoke(str, 1));

如果invoke()的第一个参数为null,说明加载的是个静态方法,后面的参数代表传给该方法的参数

现在我想来反射main()方法,那么我们为什么要反射main()方法,它有什么用处呢?

  就是我在定义一个类(A类)时,在类中(A类)完全没有说明要调用哪个类(假如要调用B类)中的main()方法,完全是在启动A类时,通过传入的参数来决定的(传入哪个类的类名,就调用哪个类)


package ReflectMain;

import java.lang.reflect.Method;

public class ReflectMain {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		String className = args[0];
		Method mainMethod = Class.forName(className).getMethod("main",
				String[].class);
		mainMethod.invoke(null, (Object) new String[] { "abc", "def", "hgi" });
		// 注意此处代码,可以写成(Object)new String[]{"abc","def","hgi"}也可以写成new
		// Object[]{new String{“abc”,”def”,”hgi”}}但不可以写成new
		// String[]{“abc”,”def”,”hgi”}

	}

}

class TestMain {
	public static void main(String[] args) {
		for (String arg : args) {
			System.out.println(arg);
		}
	}
}

数组的反射:

具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象

代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class

基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用,非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用

 

判断一个Object对象是不是数组?



---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值