幸运飞艇豹子_Java反射的常见用法

  • 时间:
  • 浏览:1

    反射的常见用法有三类,第一类是“查看”,比如输入某个类的属性措施 等信息,第二类是“装载“,比如装载指定的类到内存里,第三类是“调用”,比如通过传入参数,调用指定的措施 。

1 查看属性的修饰符、类型和名字

    通过反射机制,我们歌词 我们歌词 我们歌词 能从.class文件里看了指定类的属性,比如属性的修饰符,属性和类型和属性的变量名。通过下面的ReflectionReadVar.java,我们歌词 我们歌词 我们歌词 看演示下具体的做法。    

1	import java.lang.reflect.Field;
2	import java.lang.reflect.Modifier;
3	class MyValClass{
4		private int val1;
5		public String val2;
6		final protected String val3 = "Java";

    我们歌词 我们歌词 我们歌词 在第3行定义了4个多多 MyValCalss的类,并在第4到第6行里,定义了4个多多 属性变量。    

8	public class ReflectionReadVar {
9		public static void main(String[] args) {
10			Class<MyValClass> clazz = MyValClass.class;
11			//获取这个

类的所有属性
12	        Field[] fields = clazz.getDeclaredFields();
13		    for(Field field : fields) {
14		    	   //输出修饰符	    	   System.out.print(Modifier.toString(field.getModifiers()) + "\t");
15		    	   //输出属性的类型
16		       System.out.print(field.getGenericType().toString() + "\t");
17		    	   //输出属性的名字
18		    	   System.out.println(field.getName());
19		      }
20		}
21	}

    在main函数的第10行里,通过MyValClass.class,得到了Class<MyValClass>类型的变量clazz,在这个 变量中,存储了MyValClass这个 类的许多信息。

    在第12行里,通过了clazz.getDeclaredFields()措施 得到了MyValClass类里的所有属性的信息,并把什么属性的信息存入到Field数组类型的fields变量里。

    通过了第13行的for循环依次输出了什么属性信息。具体来讲,通过第14行的代码输出了该属性的修饰符,通过第16行的代码输出了该属性的类型,通过第18行的代码输出了该属性的变量名。这段代码的输出如下,从中我们歌词 我们歌词 我们歌词 能看了各属性的信息。

          1      private    int val1

          2      public class java.lang.String   val2

          3      protected final   class java.lang.String   val3   

2 查看措施 的返回类型,参数和名字

    通过ReflectionReadFunc.java,我们歌词 我们歌词 我们歌词 能通过反射机制看了指定类的措施 。    

1	import java.lang.reflect.Constructor;
2	import java.lang.reflect.Method;
3	class MyFuncClass{
4		public MyFuncClass(){}
5		public MyFuncClass(int i){}
6		private void f1(){}
7		protected int f2(int i){return 0;}
8		public String f2(String s) {return "Java";}

    在第3行定义的MyFuncClass这个 类里,我们歌词 我们歌词 我们歌词 定义了4个多多 构造函数和三个措施 。 

10	public class ReflectionReadFunc {
11		public static void main(String[] args) {
12			Class<MyFuncClass> clazz = MyFuncClass.class;
13	        Method[] methods = clazz.getDeclaredMethods();
14	        for (Method method : methods) 
15	        { System.out.println(method); }
16	        //得到所有的构造函数
17	        Constructor[] c1 = clazz.getDeclaredConstructors();
18	        //输出所有的构造函数
19	        for(Constructor ct : c1)
20	        { System.out.println(ct);  }
21		}
22	}

    在main函数的第12行,我们歌词 我们歌词 我们歌词 同样是通过了类名.class的措施 (也本来MyFuncClass.class的措施 )得到了Class<MyFuncClass>类型的clazz对象。

    在第13行里,是通过了getDeclaredMethods措施 得到了MyFuncClass类的所有措施 ,并在第14行的for循环里输出了各措施 。在第17行里,是通过了getDeclaredConstructors措施 得到了所有的构造函数,并通过第19行的循环输出。

    本代码的输出结果如下所示,其中第1到第3行输出的是类的措施 ,第4和第5行输出的是类的构造函数。    

1	private void MyFuncClass.f1()
2	protected int MyFuncClass.f2(int)
3	public java.lang.String MyFuncClass.f2(java.lang.String)
4	public MyFuncClass()
5	public MyFuncClass(int)

    不过在实际的项目里,我们歌词 我们歌词 我们歌词 一般还会仅仅“查看”类的属性和措施 ,在更多的状况里,我们歌词 我们歌词 我们歌词 是通过反射装载和调用类里的措施 。

3 通过forName和newInstance措施 加载类

    在前文JDBC操作数据库的代码里,我们歌词 我们歌词 我们歌词 看了在创建数据库连接对象(Connection)完后 ,须要通过Class.forName("com.mysql.jdbc.Driver");的代码来装载数据库(这里是MySQL)的驱动。

    不还会 了说,Class类的forName措施 最常见的用法本来装载数据库的驱动,以至于不少人会错误地认为这个 措施 的作用是“装载类”。

    真是 forName措施 的作用仅仅是返回4个多多 Class类型的对象,它一般会和newInstance措施 配套使用,而newInstance措施 的作用才是加载类。

    通过下面的ForClassDemo.java这段代码,我们歌词 我们歌词 我们歌词 来看下综合使用forName和newInstance这个 个多 措施 加载对象的措施 。    

1	class MyClass{
2		public void print()
3		{	System.out.println("Java");	}
4	}
5	public class ForClassDemo {
6		public static void main(String[] args)	{
7	        //通过new创建类和使用类的措施

8			MyClass myClassObj = new MyClass();
9			myClassObj.print();//输出是Java
10			//通过forName和newInstance加载类的措施

	
11			try {
12				Class<?> clazz = Class.forName("MyClass");
13				MyClass myClass = (MyClass)clazz.newInstance();
14				myClass.print();//输出是Java
15			} catch (ClassNotFoundException e) {
16				e.printStackTrace();
17			} catch (InstantiationException e) {
18				e.printStackTrace();
19			} catch (IllegalAccessException e) {
20				e.printStackTrace();
21			}		
22		}
23	}

    在第1行定义的MyClass这个 类里,我们歌词 我们歌词 我们歌词 在其中的第2行定义了4个多多 print措施 。

    Main函数的第8和第9行里,我们歌词 我们歌词 我们歌词 演示了通过常规new的措施 创建和使用类的措施 ,通过第9行,我们歌词 我们歌词 我们歌词 能输出“Java”这个 字符串。

    在第12行,我们歌词 我们歌词 我们歌词 通过Class.forName("MyClass")措施 返回了4个多多 Class类型的对象,请注意,forName措施 的作用全部都是“加载MyClass类”,本来返回4个多多 暗含 MyClass信息的Class类型的对象。这里我们歌词 我们歌词 我们歌词 是通过第13行的newInstance措施 ,加载了4个多多 MyClass类型的对象,并在第14行调用了其中的print措施 。

    既然forName措施 的作用仅仅是“返回Class类型的对象”,不能了在JDBC偏离 的代码里,缘何我们歌词 我们歌词 我们歌词 能通过Class.forName("com.mysql.jdbc.Driver");代码来装载MySQL的驱动呢?在MySQL的com.mysql.jdbc.Driver驱动类暗含 如下的一段静态初始化代码。   

1	static {
2	try {
3	   java.sql.DriverManager.registerDriver(new Driver());
4	} catch (SQLException e) {
5	throw new RuntimeException(“Can’t register driver!”);
6	}
7	}

    也本来说,我们歌词 我们歌词 我们歌词 调用Class.forName措施 后,会通过执行这段代码会新建4个多多 Driver的对象,并调用第3行的DriverManager.registerDriver把刚创建的Driver对象注册到DriverManager里。

    在上述的代码里,我们歌词 我们歌词 我们歌词 看了了除了new之外,我们歌词 我们歌词 我们歌词 还能通过newInstance来创建对象。

    真是 这里说“创建”之本来准确,真是 说通过new和newInstance我们歌词 我们歌词 我们歌词 都能得到4个多多 可用的对象,但newInstance的作用真是 是通过Java虚拟机的类加载机制把指定的类加载到内存里。

    我们歌词 我们歌词 我们歌词 在工厂模式中,4个多多劲会通过newInstance措施 来加载类,但这个 措施 不能了是通过调用类的无参构造函数来加载类,不可能 我们歌词 我们歌词 我们歌词 在创建对象时须要传入参数,不能了就得使用new来调用对应的带参的构造函数了。

4 通过反射机制调用类的措施

    不可能 我们歌词 我们歌词 我们歌词 通过反射机制来调用类的措施 ,不能了就得补救4个多多 现象,第一,通过什么措施 来调?第二,何如传入参数,第三,何如得到返回结果?

    通过下面的CallFuncDemo.java代码,我们歌词 我们歌词 我们歌词 将通过反射来调用类里的措施 ,在其中我们歌词 我们歌词 我们歌词 能看下上述4个多多 现象的补救措施 。    

1	import java.lang.reflect.Constructor;
2	import java.lang.reflect.InvocationTargetException;
3	import java.lang.reflect.Method;
4	class Person {
5		private String name;
6		public Person(String name) 
7	    {this.name = name;}
8		public void saySkill(String skill) {
9		  System.out.println("Name is:"+name+",skill is:" + skill);
10		}
11		public int addSalary(int current) 
12	    {	return current + 400;}
13	}

    在第4行里,我们歌词 我们歌词 我们歌词 定义了4个多多 Person类,在其中的第6行里,我们歌词 我们歌词 我们歌词 定义了4个多多 带参的构造函数,在第8行里,我们歌词 我们歌词 我们歌词 定义了4个多多 带参但无返回值得saySkill措施 ,在第11行里,我们歌词 我们歌词 我们歌词 定义了4个多多 带参但会 返回int类型的addSalary措施 。    

14	public class CallFuncDemo {
15		public static void main(String[] args) {
16			Class c1azz = null;
17			Constructor c = null;
18			try {
19				c1azz = Class.forName("Person");
20				c = c1azz.getDeclaredConstructor(String.class);
21				Person p = (Person)c.newInstance("Peter");
22				//output: Name is:Peter, skill is:java
23				p.saySkill("Java");
24				// 调用措施

,须要传递对象实例,共同传递参数值
25				Method method1 = c1azz.getMethod("saySkill", String.class);
26				//不可能

没返回值,还会能了直接调
27				//输出结果是Name is:Peter, skill is:C#
28	            method1.invoke(p, "C#");             
29	            Method method2 = c1azz.getMethod("addSalary", int.class);
400	            Object invoke = method2.invoke(p, 400);
31	            //输出400
32				System.out.println(invoke);
33			} catch (ClassNotFoundException e) {
34				e.printStackTrace();
35			} catch (NoSuchMethodException e1) {
36				e1.printStackTrace();
37			} catch (InstantiationException e) {
38				e.printStackTrace();
39			} catch (IllegalAccessException e) {
40				e.printStackTrace();
41			} catch (InvocationTargetException e) {
42				e.printStackTrace();
43			}
44		}
45	}

    在第19行里,我们歌词 我们歌词 我们歌词 通过Class.forName得到了4个多多 Class类型的对象,其暗含 晒 了Person类的信息。在第20行里,通过传入String.class参数,得到了Person类的带参的构造函数,并通过了第21行的newInstance措施 ,通过这个 带参的构造函数创建了4个多多 Person类型的对象。本来在第23行里调用了saySkill措施 。这里我们歌词 我们歌词 我们歌词 演示通过反射调用类的构造函数来创建对象的措施 。

    在第25行里,我们歌词 我们歌词 我们歌词 通过了getMethod措施 ,得到了带参的saySkill措施 的Method类型的对象,本来通过第28行的invoke措施 调用了这个 saySkill措施 ,这里第4个多多 参数是由哪个对象来调用,通过第三个参数,我们歌词 我们歌词 我们歌词 传入了saySkill措施 的String类型的参数。

    用同样的措施 ,我们歌词 我们歌词 我们歌词 在第29和400行通过反射调用了Person类的addSalary措施 ,不可能 这个 措施 有返回值,本来我们歌词 我们歌词 我们歌词 在400行用了4个多多 Object类型的invoke对象来接收返回值,通过第32行的打印励志的话 ,我们歌词 我们歌词 我们歌词 能看了400这个 执行结果。