JAVA反射总结

      清明三天看了两天的java反射的知识,也敲了些代码,总觉得有点乱。还没去深入了解过反射的作用,不过先写个总结。

     Java反射机制:

  Java反射机制是在运行状态中,对于任何一个类,都能知道这个类的所有属性和方法,包括private的和public的。而对于任何一个对象,都能调用这个对象的任何一个方法和属性。

获取class的实例

    首先,要获取class的实例,有4种方法

先创建一个Person类:

</pre><pre>
public class Person {
	public String name;
	private int age;

	public Person() {
	}

	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return this.age;
	}

	public String getName() {
		return this.name;
	}

	public void show() {
		System.out.println("我是一个人!");

	}

	private void show2() {
		System.out.println("你也是一个人!");
	}

}


1.调用运行时类本身的class属性:

Class clazz=Person.class;


2.通过运行时类对象获取:

Person p=new Person();
		Class clazz=p.getClass();

3.通过Class的静态方法获取:

String className ="Person";
		Class clazz=Class.forName(className);
   方法3体现了反射的动态性,要注意的一点是类名要写完整,即加上包名。示例中的Person类在default package下,所以省略了包名。

4.通过类加载器

ClassLoader classLoader = this.getClass().getClassLoader();
	Class clazz=classLoader.loadClass(className);//className见方法3;

     通过以上几种方法获取Class实例后,我们就可以进行如下的一系列操作:

1.创建对应的运行时类的对象;

2.获取对应的运行时类的完整结构(属性,方法,构造器,代码块,父类,包名);

3.调用对应的运行时类的指定结构(属性,方法,构造器);

4.反射的应用:动态代理;


创建对象:

//1.创建clazz对应的运行时类person类的对象
	Class<Person> clazz=Person.class;
	Person p=	clazz.newInstance();//上面两行相当与创建一个对象  new Person();
        创建运行时类的对象,其实就是调用类的空参的构造器。所以以后咱们在写类的时候,最好都写一个空参的构造器,一个是便于反射的时候调用newInstance()方法,还有一个就是如果没有空参构造器,其子类会报错。而且创建成功还需要构造器的权限足够。

获取属性:

Class clazz=Person.class;
		Field f1=clazz.getField("show");//得到show方法
		Field[] field=	clazz.getFields();
	//用getField()方法只能得到public属性的参数,也可以得到父类中的public属性值
	for(int i=0;i<field.length;i++){
		System.out.println(field[i]);
	}
	
	//可获取所有的属性,但只能是运行时类本身的所有属性
	Field[] fields=clazz.getDeclaredFields();
	for(int i=0;i<fields.length;i++){
		System.out.println(fields[i]);
	}
	}

获取 属性的权限修饰符,  变量类型,  变量名:

Class clazz=Person.class;
		Field[] fields=clazz.getDeclaredFields();
		for(Field f: fields ){
			//1.获取权限修饰符,如public,private
			System.out.print(Modifier.toString( f.getModifiers() )+" ");
			//2.获取变量类型,如string,int
			System.out.print(f.getType()+"   ");
			//3.获取属性名
			System.out.print(f.getName()+"   ");
		System.out.println();
		
	}
   f.getModifiers()返回的是一个int值,代表不同的权限修饰符。0代表默认,1代表public,2代表private。Modifier有个静态方法Modifier.toString()将int值转成权限修饰符

获取类的所有构造器:

Class clazz=Person.class;
	Constructor[] con=	clazz.getDeclaredConstructors();
	for(int i=0;i<con.length;i++){
		System.out.println("第"+i+"个构造器"+con[i].getName());
		//得到构造器的形参
		Class[] pa=	con[i].getParameterTypes();
		for(Class m:pa){
			System.out.print(m+"    ");
		}
		System.out.println();
	}

获取方法的完整结构:

Class clazz=Person.class;<pre name="code" class="java"><span style="white-space:pre">	</span>//1.获取运行时类及其父类中所有的public方法
<span style="white-space:pre">	</span>Method[] methods=	clazz.getMethods();
	for(Method me:methods){
		System.out.println(me);
	}

	// 获取方法的 注解,权限修饰符,返回值 方法名 形参列表 异常等等
	Method [] methods2= clazz.getDeclaredMethods();//获取类本身的所有方法
	for(Method m:methods2){
		//1.注解
	Annotation[] a=m.getAnnotations();//得到方法的注解
		for(Annotation an:a){
			System.out.println(an+" ");
		}
		
	//2.权限修饰符
	System.out.println("权限是"+Modifier.toString(m.getModifiers()));
	
	//3.返回值类型
	System.out.println("返回值类型是"+m.getReturnType());
	
	//4.方法名
	System.out.println(m.getName());
	
	//5.形参列表
	Class[] c=m.getParameterTypes();System.out.print("形参列表:");
	for(Class cl:c){
		System.out.print(cl.getName()+" ");
	}
	//6,异常
	Class[] ex= m.getExceptionTypes();
	if(ex.length>0) System.out.print("throws");
	for(int i=0;i<ex.length;i++){
		System.out.println(ex[i].getName()+" "+i+" ");}
	System.out.println();
	}



调用运行时类指定的方法:

Class clazz=Person.class;
		Method m1=clazz.getMethod("show");//若方法无形参,就去掉形参名parameterTypes
	//方法是一般的,所以需要对象
		Person p=(Person) clazz.newInstance();
		m1.invoke(p);//<span style="color:#ff0000;">让p调用该方法</span>
<span style="color:#ff0000;">//该方法有返回值,返回值就是前面show方法的返回值</span>
		
		Method m2=clazz.getMethod("toString");
		Object obj=m2.invoke(p);
		System.out.println(obj);
		
		//static方法调用
		Method m3=clazz.getMethod("info");
		m3.invoke(Person.class);

调用运行时类指定的属性

Class clazz=Person.class;
		
		//1.获取指定的属性
	Field name=	clazz.getField("name");
		//2.创建运行时类的对象
		Person p=(Person) clazz.newInstance();
		System.out.println(p);
		//3.将运行时类的对象的指定的属性赋值
		name.set(p, "Bruce");
		System.out.println(p);
		
		
		Field age=clazz.getDeclaredField("age");
		<span style="color:#ff0000;">age.setAccessible(true);//少了这一行不能直接赋值</span>
		//默认类型的参数,如id,可以不加这句话,但为了保险起见,可以加上
		age.set(p, 20);
		System.out.println(p);
   这里需要注意的是,如果调用的属性权限修饰符为private,需要加setAccessible(true)方法,否则会报异常。

调用指定的构造器:

Class clazz=Person.class;
		Constructor con=clazz.getConstructor(String.class,int.class);
		//后面表示形参的类型,根据类型可确定构造器
		con.setAccessible(true);
	Object obj=	con.newInstance("dsad",20);//创建一个对象,name=dsad,age=20
	System.out.println(obj);

总结:不管调用方法或者是属性,都是get方法同时也都需要创建一个对象。

    如果是属性,则是getField(属性名),然后调用field.set(属性名,值)方法设置值。

    如果是方法,则是getMethod(方法名),然后调用method.invoke(对象名)。

    但需要注意的是,如果是private属性或者private方法,需要getDeclaredField()或者getDeclaredMethod()方法,而且需要加setAccessible(true)方法。


        同时,还有通过反射获取一些其他的东西:

    获取运行时类的父类:

Class clazz=Person.class;
	Class superClass=	clazz.getSuperclass();
    获取带有泛型的父类:

Class clazz=Person.class;
	Type ty= clazz.getGenericSuperclass();
    获取父类的泛型(在JDBC中有用):

Class clazz=Person.class;
		//先获取带泛型的父类
		Type ty= clazz.getGenericSuperclass();
		//强制转型
		ParameterizedType pt=	(ParameterizedType)ty;
	Type[] tp=	pt.getActualTypeArguments();
		//for(Type t:tp)
		System.out.println("泛型是"+tp[0]);

Class clazz=Person.class;
		Class[] cl=clazz.getInterfaces();//4.获取实现的接口
		for(int i=0;i<cl.length;i++)
			System.out.println(cl[i]);
		
		Package pa=clazz.getPackage();//5.获取所在的包
			System.out.println(pa);
		
		
		Annotation[] an=	clazz.getAnnotations();	//6.获取注解
		for(int i=0;i<an.length;i++){
			System.out.println(an[i]);
		}

反射的应用:动态代理:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值