java反射机制基础笔记



java-reflect专题

参考慕课网视频:

http://www.imooc.com/video/3736

1.class类的使用

1).万事万物都是对象,类是java.lang.Class的实例对象

注:java中基础类型和静态成员不是面向对象,但其对应的封装类型是面向对象!

2)Class类的实例对象表示方法有三种

package qianglih;

public class ClassDemo1 {
	public static void main(String[] args) {
		//Foo的实例对象如何表示
		Foo foo1=new Foo();
		//Foo这个类也是一个实例对象,Class类的实例对象,如何表示
		//Class的构造方法是私有的,不能通过new创建
		//第一种表示方式-->实际在告诉我们任何一个类都有一个隐含的实静态成员变量class
		Class c1=Foo.class;
		
		//第二种 已经知道该类的对象通过getClass方法
		Class c2 = foo1.getClass();
		/* 官网c1,c2表示了Foo类的类类型(class type)*/
		System.out.println(c1==c2);//true c1和c2都代表了Foo类的类类型,一个类只可能是Class类的一个实例对象
		
		//第三种
		Class c3=null;
		try {
			c3=Class.forName("qianglih.Foo");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.out.println(c2==c3);//true
		
		//我们完全可以通过类类型创建该类的对象--》通过c1,c2,c3创建Foo的实例对象
		try {
			Foo foo2=(Foo)c1.newInstance();
			foo2.print();//Foo
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}

	}

}
class Foo{
	void print(){
		System.out.println("Foo");
	}
	
	
}



2.动态加载类



Class.forName("qianglih.Foo");

不仅代表了类的类类型,还代表了动态加载类

编译和运行的说明:

动态加载类  运行时加载

通过new创建对象是静态加载,编译时就加载.
javac test.java  编译
java   test.java 运行
设计思想,静态加载就必须对每个对象进行编译,一个对象出错,所有的都不能编译,
使用动态加载,提取接口公共方法,既不用修改主类


3.获取方法信息

1)基本的数据类型 ,void关键字 都存在类类型

package qianglih;

public class ClassDemo2 {

	public static void main(String[] args) {
		Class c1=int.class;//int 的类类型
		Class c2=String.class;//String类的类类型,String类字节码
		Class c3=double.class;//c3和c4不是一回事,c3表示double这个类型的类类型,
		Class c4=Double.class;//c4表示Double这个类的类类型
		Class c5=void.class;
		System.out.println(c1.getName()+"****"+c1.getSimpleName());//int****int
		System.out.println(c2.getName()+"****"+c2.getSimpleName());//java.lang.String****String
		System.out.println(c3.getName()+"****"+c3.getSimpleName());//double****double
		System.out.println(c4.getName()+"****"+c4.getSimpleName());//java.lang.Double****Double
		System.out.println(c5.getName()+"****"+c5.getSimpleName());//void****void

	}

}

2)Class类的基本API操作

工具类:

package qianglih;

import java.lang.reflect.Method;

public class ClassUtil {
	/**
	 * 打印类的信息,包括类的成员函数,成员变量
	 * @param obj  该对象所属类的信息
	 */
	public static void printClassMessage(Object obj){
		/*
		 *  public final native Class<?> getClass();
		 *  本地方法,java声明,c实现,java调用
		 * 传递的是哪个子类的对象,c就是该子类的类类型
		 */
		//要获取类的信息,首先获取类的类类型
		Class c=obj.getClass();
		//获取类的名称
		System.out.println("类的名称是:"+c.getName());
		/*
		 * Method类,方法对象
		 * 万事万物都是对象,所以成员方法也是对象
		 * getMethods()方法获取的所以public方法,包括父类继承得来的
		 * getDeclaredMethods()获取的所以该类自己声明的方法,不问访问权限
		 */
		Method[] ms=c.getMethods();//c.getDeclaredMethods()
		for (int i = 0; i < ms.length; i++) {
			//得到方法的返回值类型的类类型
			Class returnTyp=ms[i].getReturnType();
			System.out.print(returnTyp.getName()+" ");
			//得到方法名
			System.out.println(ms[i].getName());
			//获取参数类型-->得到参数列表的类型的类类型、
			Class[] paramTypes=ms[i].getParameterTypes();
			for (Class class1 : paramTypes) {
				System.out.println(class1.getName()+" ");
			}
		}
		
	}
}

测试类

package qianglih;

public class ClassDemo3 {

	public static void main(String[] args) {
		String s="Hello";
		ClassUtil.printClassMessage(s);
		
		Integer n=1;
		ClassUtil.printClassMessage(n);

	}

}

运行结果,即可得到string和Integer里方法信息


4.获取成员变量和构造函数信息


成员变量和构造函数都是对象。
要获取一个类的信息,先获得他的类类型,在通过api获取filed和construct信息。

package qianglih;

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

public class ClassUtil {
	/**
	 * 打印类的信息,包括类的成员函数
	 * @param obj  该对象所属类的信息
	 */
	public static void printClassMessage(Object obj){
		/*
		 *  public final native Class<?> getClass();
		 *  本地方法,java声明,c实现,java调用
		 * 传递的是哪个子类的对象,c就是该子类的类类型
		 */
		//要获取类的信息,首先获取类的类类型
		Class c=obj.getClass();
		//获取类的名称
		System.out.println("类的名称是:"+c.getName());
		/*
		 * Method类,方法对象
		 * 万事万物都是对象,所以成员方法也是对象
		 * getMethods()方法获取的所以public方法,包括父类继承得来的
		 * getDeclaredMethods()获取的所以该类自己声明的方法,不问访问权限
		 */
		Method[] ms=c.getMethods();//c.getDeclaredMethods()
		for (int i = 0; i < ms.length; i++) {
			//得到方法的返回值类型的类类型
			Class returnTyp=ms[i].getReturnType();
			System.out.print(returnTyp.getName()+" ");
			//得到方法名
			System.out.println(ms[i].getName());
			//获取参数类型-->得到参数列表的类型的类类型、
			Class[] paramTypes=ms[i].getParameterTypes();
			for (Class class1 : paramTypes) {
				System.out.println(class1.getName()+" ");
			}
		}
		
	}

	/**
	 * 获取成员变量信息
	 * @param obj
	 */
	public static void printFieldMessage(Object obj) {
		/*
		 * 成员变量也是对象 java.lang.reflect.Filed
		 * Filed类封装了关于成员变量的操作
		 * getFileds()方法获取的是所有public的成员变量信息
		 * getDeclaredFileds()获取的是改类自己声明的成员变量信息
		 */
		Class c=obj.getClass();
		Field[] fs=c.getDeclaredFields();//c.getFields()
		System.out.println("成员表量:");
		for (Field field : fs) {
			//得到成员变量的类型的类类型
			Class fieldTyp=field.getType();
			String typName=fieldTyp.getName();
			String fieldName=field.getName();
			System.out.println(typName+" "+fieldName);
			
		}
	}
	/**
	 *打印对象的构造函数信息
	 * @param obj
	 */
	public static void printConMessage(Object obj){
		Class c=obj.getClass();
		/*
		 * 构造函数也是对象
		 * java.lang.Constructor封装了函数信息
		 * c.getDeclaredConstructors()获取所以piublic构造函数
		 * c.getConstructors()得到所以的构造函数
		 */
		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(")");
		}
	}
}

测试代码

package qianglih;

public class ClassDemo4 {
	public static void main(String[] args) {
		//ClassUtil.printClassMessage("hello");
		//ClassUtil.printFieldMessage("hello");
		ClassUtil.printConMessage("hello");
	}

}


5.方法反射的基本操作

1)如何获取某个方法

方法的名称和方法的参数列表才能唯一决定某个方法

2)方法反射的操作

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

方法的反射操作比较复查,先学会用,再来看有什么好处!

由对象直接操作方法改为先获取类类型,在获取方法对象,然后用方法对象通过invoke执行方法。

package qianglih;

import java.lang.reflect.Method;

public class MethodDemo1 {

	public static void main(String[] args) {
		//获取print(into,int)方法
		A a1=new A();
		Class c=a1.getClass();
		/*
		 * 获取方法 名称和参数列表来决定
		 */
		try {
			//c.getMethod("print", new Class[]{int.class,int.class});
			Method m=c.getMethod("print", int.class,int.class);
			//方法的反射操作 用m对象来进行方法调用
			//方法如果没有返回值类型,则方法null,有就返回相应的类型
			//a1.print(10,20);直接调用结果一样
			Object o=m.invoke(a1, 10,20);
			System.out.println("******************");
			Method m1=c.getMethod("print", String.class,String.class);
			o=m1.invoke(a1, "hello","WORLD");
			System.out.println("******************");
			Method m2=c.getMethod("print");
			o=m2.invoke(a1);
		} catch (Exception e) {
			e.printStackTrace();
		} 

	}

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


6.通过反射了解集合泛型的本质

1)通过Class,Method类认识泛型的本质

   * java中集合的泛型,是防止输入错误的,只在编译阶段有效,绕过编译就无效了。
   * 我们可以通过方法的反射来操作,绕过编译

package qianglih;

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

public class MethodDemo2 {

	public static void main(String[] args) {
		ArrayList list =new ArrayList();
		ArrayList<String> list1 =new ArrayList<String>();
		list1.add("hello");
		//list1.add(12);//出错
		Class c1=list.getClass();
		Class c2=list1.getClass();
		System.out.println(c1==c2);//true
		//反射的操作都是在编译之后的操作
		/*
		 * c1==c2结果返回true说明编译之后结合的泛型是去泛型的
		 * java中集合的泛型,是防止输入错误的,只在编译阶段有效,绕过编译就无效了
		 * 我们可以通过方法的反射来操作,绕过编译
		 */
		try {
			Method m=c2.getMethod("add", Object.class);
			m.invoke(list1, 100);
			System.out.println(list.size()+","+list);

			System.out.println(list1.size()+","+list1);
/*			for (String string : list1) {
				System.out.println(string);
			}*///不能这样操作了
/*			for (int i = 0; i < list1.size(); i++) {
				System.out.println(list1.get(i));
			}*/
		} catch (Exception e) {
			e.printStackTrace();
		} 


	}

}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值