Java反射原理

一、Class类的应用

1.类类型的对象该如何表示

public class Foo{
	public void say(){
		System.out.println("hello world");
	}
}
		
	
public class ClassDemo1{
	public static void main(String[] args){
		//Foo的实例对象
		Foo foo1 = new Foo();
		//Foo这个类本身也是一个实例对象
		//任何一个类都是Class类的实例对象
		//这个实例对象有三种表示方式
		
		//第一种方式,实际在告诉我们任何一个类都有一个隐含的静态成员变量
		Class clazz1 = Foo.class;
		
		//第二种方式,已知该类的对象,通过getClass方法得到
		Class clazz2 = foo1.getClass();
		
		//第三种表达方式,通过Class类的静态方法forName()加全限定名
		try{
			Class clazz3 = Class.forName("com.destiny.reflect.Foo");
		}catch(ClassNotFoundException e){
			e.printStackTrace();
		}
		
		//不管clazz1还是clazz2都代表了Foo类的类类型,一个类只可能是一个Class类的一个实例对象
		System.out.println(clazz1 == clazz2);
		//官方文档:clazz表示了foo类的类类型
		//万事万物皆对象,是Class类的对象,这个对象我们称之为该类的类类型
		
	
		//我们完全可以通过类的类类型创建该类的实例对象,即通过clazz创建Foo的实例对象
		Foo foo1 = clazz1.newInstance();
		foo1.say();
		
	}
}

编译:编译时期加载类是静态加载类
运行:运行时期加载类是动态加载类


public class Word{
	public static void start(){
		System.out.println("word......start");
	}
}

public class Office{
	public static void main(){
		//由于我们只有Word类而没有Excel类,因此本类在编译时无法通过
		//new创建对象属于静态加载类,在编译时期就需要加载所有可能使用到的类
		//通过动态加载类可以解决该问题
		if("word".equals(args[0])){
			Word w = new Word();
			w.start();
		}
		if("excel".equals(args[0])){
			Excel e = new Excel();
			e.start();
		}
	}
}


改进之后的例子:
public class OfficeBetter{
<span style="white-space:pre">	</span>public static void main(String[] args){
	<span style="white-space:pre">	</span>try{
			//动态加载类,在运行时刻加载
			Class clazz = Class.forName(args[0]);
			//通过类类型创建对象
			//使用Word与Excel的抽象接口OfficeAble
			OfficeAble oa = (OfficeAble)clazz.newInstance();
			oa.start();
		}catch(ClassNotFoundException e){
			e.printStackTrace();
		}	
	}
}

2.基本数据类型
类中存在的关键字都存在类类型


public class ClassDemo2{
	public static void main(String[] args){
		//int的类类型
		Class clazz1 = int.class;
		//String的类类型,String类字节码
		Class clazz2 = String.class;
		
		Class clazz3 = double.class;
		Class clazz4 = void.class;
				
		System.out.println(clazz2.getName());		//java.lang.String
		System.out.println(clazz2.getSimpleName());	//String
	}
}
		
public class ClassUtil{
	//打印类的信息,包括类的成员变量、成员函数
	public static void printClassMessage(Object obj){
		//要获取类的信息,首先要获取类的类类型
		//一直参数obj,是一个对象
		Class clazz = obj.getClass();
		System.out.println("类的名称是:"+clazz.getName());
		//Method是方法的对象
		//一个成员方法就是一个method对象
		//getMethods()方法获取的是所有public方法,包括从父类继承而来的
		//getDeclaredMethod()获取的是所有该类自己生命的方法,无视访问权限
		Method[] methods = clazz.getMethods();
		for(int i = 0; i < methods.length; ++i){
			//得到方法的返回值类型的类类型
			Class returnType = methods[i].getReturnType();
			//通过返回值的类类型打印返回值类型
			System.out.println(returnType.getName()+" ");
			//得到方法名称
			System.out.println(methods[i].getName()+"(");
			//获取参数类型===>得到的是参数裂变的类型的类类型
			Class[] paramTypes = methods[i].getParamTypes();
			
			for(Class clazz : paramTypes){
				System.out.println(class.getName()+",");
			}
			
			System.out.println(")");
		}
	}
}

3.成员变量的反射
成员变量也是对象


java.lang.reflect.Field
		Field类封装了关于成员变量的操作
		
		
		Field[] fields = clazz.getFields();
		//Field[] fields = clazz.getDeclaredFields();
		for(Field field : fields){
			//得到成员变量类型的类类型
			Class fieldType = field.getType();        
			String typeName = fieldType.getName();
			//得到成员变量的标识符
			String fieldName = field.getName();
		}


二、方法的反射操作

1.如何获取某个方法

一个方法的名称和其参数列表可以唯一决定一个方法

2.方法反射的操作

method.invoke(对象, 参数列表);

3.案例


public class A{
	public void print(int a, int b){
		System.out.println(a+b);
	}
			
	public String print(String a, String b){
		System.out.println(a.toUpperCase() +","+ b.toLowerCase());
	}
}

public class MethodDemo1{
	public static void main(String[] args){
		//获取print(int, int)方法
		//1.获取类的类类型
		A a = new A();
		Class clazz = a.getClass();
		//2.获取方法,名称和参数列表来决定
		//getMethod()获取的是public
		Method method = clazz.getMethod("print", new Class[]{int.class, int.class});
		Method method = clazz.getMethod("print", int.class, int.class);
		
		//方法的反射操作
		//用方法对象来进行调用
		//如果方法没有返回值,那么obj的值为null
		//如果方法有返回值,那么obj就是该方法的返回值,需要强制类型转换
		Object obj = method.invoke(a, new Object[]{10, 20});
		Object obj = method.invoke(a, 10, 20);
	}
}


三、通过Class, Method了解泛型的本质

反射的操作都发生在运行期


public class MethodDemo4{
	List list1 = new ArrayList();
	List<String> list2 = new ArrayList<String>();
	list2.add("hello");
	//list2.add(10);
	Class clazz1 = list1.getClass();
	Class clazz2 = list2.getClass();
	
	System.out.println(clazz1 == clazz2);
	//输出结果为true,说明编译之后的结果是去泛型化
	//即编译后,list2不再具有泛型
	//java中集合的泛型是防止错误输入,只在编译阶段有效,绕过编译泛型就不再发生作用
	//我们可以通过方法的反射绕过编译
	Method method = clazz2.getMethod("add", Object.class);
	//绕过编译执行add方法
	method.invoke(list2, 10);
	//添加成功,成功绕过泛型的限制
	System.out.println(list2.size);
}






评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值