Java反射

一、引言:

首先,要理解一句话“万事万物皆对象。”

比如一个类Foo:1)它的实例对象,new Foo()出来就可以;(2)那么这个Foo是不是对象呢?是的,Foo这个java.lang.Class的实例对象。那么它如何表示呢?new Class()就可以吗?

Class源码:


构造函数是私有的。只有JVM才能创建。

那么Class的实例对象Foo如何(用Class)表示呢?

二、创建Foo类的类类型

Class的实例对象Foo如何(用Class)表示方法:

(1)

Class c1=Foo.class;


(2)已经知道该类的对象通过getClass方法

Class c2 = foo1.getClass();

(3)

Class.forName()


注:

c1,c2,c3表示Foo类的类类型(class type

也就是说:Foo类的实例对象表示Foo类的实例对象

       Foo类的类类型表示Class类的实例对象。

三、通过类的类类型创建类的实例对象

即通过c1 or c2 or c3创建Foo的实例对象 

c1.newInstance();  //前提:Foo有无参构造方法
四、区分编译和运行时期加载类

我们说编译时刻加载类为静态加载类,而运行时刻加载类是动态加载类。

我们看一段代码:


在编译时期,new要加载需要的类也就是在编译时期,WordExcel都要加载。

那么存在一个问题,如果Word存在,Excel不存在,我只要用Word,是不可以的,因为编译时期Excel不过。我希望的是,Excel不要捣乱,用到你时你再加载也就是用哪个,哪个加载,不用就不加载,也就是我们所说的动态加载。

我们写一个能动态加载类类型的类:


获得类类型,并获得实例对象。但是获得谁的呢?

Word w = (Word)c.newInstance();
Excel e = (Excel)c.newInstance();

都不行。我们可以统一一下,比如实例一个他们俩都可以用的实例对象。


那么OfficeAble就是一个interface。让Word和Excel实现它就可以了。

五、万事万物皆对象

之所以再提这个是因为,通过上面我们知道,类的实例对象是对象,类本身也是对象。其实还有更广泛的:


void也有类类型。

也就是说只要在类里,基本类型、关键字==>都有类类型。

那么获取它们的类类型可以做什么呢?就要看Class类的API操作了。

六、Class类的基本API操作

package com.ali.reflect;

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

public class ClassUtil {

	public static void printClassMethodMessage(Object obj){
		//要获取类的信息  首先要获取类的类类型
		Class c = obj.getClass();//传递的是哪个子类的对象  c就是该子类的类类型
		//获取类的名称
		System.out.println("类的名称是:"+c.getName());
		
		/*
		 * 方法也是对象,是Method对象
		 * getMethods()方法获取的是所有的public的函数,包括父类继承而来的
		 * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
		 */
		Method[] ms = c.getMethods();
		for(int i = 0; i < ms.length;i++){
			//得到方法的返回值类型的类类型
			//如果返回值是String,那么 ms[i].getReturnType()得到的就是String.class,
			Class returnType = ms[i].getReturnType();
			System.out.print(returnType.getName()+" ");
			//得到方法的名称
			System.out.print(ms[i].getName()+"(");
			//获取参数类型--->得到的是参数列表的类型的类类型(int.class,String.class.....)
			Class[] paramTypes = ms[i].getParameterTypes();
			for (Class class1 : paramTypes) {
				System.out.print(class1.getName()+",");
			}
			System.out.println(")");
		}
	}
    /**
     * 获取成员变量的信息
     */
	public static void printFieldMessage(Object obj) {
		Class c = obj.getClass();
		/*
		 * 成员变量也是对象,是Field对象
		 * getFields()方法获取的是所有的public的成员变量的信息
		 * getDeclaredFields获取的是该类自己声明的成员变量的信息
		 */
		Field[] fs = c.getDeclaredFields();
		for (Field field : fs) {
			//得到成员变量的类型的类类型
			Class fieldType = field.getType();
			String typeName = fieldType.getName();
			//得到成员变量的名称
			String fieldName = field.getName();
			System.out.println(typeName+" "+fieldName);
		}
	}
	/**
	 * 打印对象的构造函数的信息
	 */
	public static void printConMessage(Object obj){
		Class c = obj.getClass();
		/*
		 * 构造函数也是对象,是Constructor对象
		 * getConstructors获取所有的public的构造函数
		 * getDeclaredConstructors得到所有的构造函数
		 */
		Constructor[] cs = c.getDeclaredConstructors();
		for (Constructor constructor : cs) {
			System.out.print(constructor.getName()+"(");
			//获取构造函数的参数列表--->得到的是参数列表的类类型
			Class[] paramTypes = constructor.getParameterTypes();
			for (Class class1 : paramTypes) {
				System.out.print(class1.getName()+",");
			}
			System.out.println(")");
		}
	}
}
通过上述代码可以知道,方法、成员变量、构造函数都是对象,有自己的类类型。

七、反射

那么我们就知道什么是反射操作了:

比如a1.print(10);这个方法是a1操作print(),那么反射就是print()这个方法对象来操作a1。

A a1 = new A();
Class c = a1.getClass();//获取Class类的实例对象
Method m = c.getMethod("print", int.class);//获取Method类的实例对象
Object o = m.invoke(a1, 10);//Method类的实例对象 操作 Class类的实例对象
八、扩展:通过反射了解集合泛型的本质
package com.ali.reflect;

import java.lang.reflect.Method;
import java.util.ArrayList;

public class MethodDemo4 {
	public static void main(String[] args) {
		ArrayList list1 = new ArrayList();
		ArrayList<String> list2 = new ArrayList<String>();
		list2.add("hello");
		//list2.add(20);错误的
		Class c1 = list1.getClass();
		Class c2 = list2.getClass();
		System.out.println(c1 == c2);//返回true
	}
}

list2.add(20)在编译期就会报错,但是当我们运行期加载c1 c2时,发现c1==c2为true,也就是说,编译之后,集合是去泛型的。

我们来验证一下,我们用通过方法反射来操作list2.add(20),使之绕过编译:

package com.ali.reflect;

import java.lang.reflect.Method;
import java.util.ArrayList;

public class MethodDemo4 {
	public static void main(String[] args) {
		ArrayList list1 = new ArrayList();
		ArrayList<String> list2 = new ArrayList<String>();
		list2.add("hello");
		//list2.add(20);错误的
		Class c1 = list1.getClass();
		Class c2 = list2.getClass();
		System.out.println(c1 == c2);//返回true
		try {
			Method m = c2.getMethod("add", Object.class);
			m.invoke(list2, 20);//绕过编译操作就绕过了泛型
			System.out.println(list2.size());//打印出来是2,也就是说,list2加上20这个int类型了。
		} catch (Exception e) {
		  e.printStackTrace();
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值