java反射(2)

所谓的反射机制就是java语言在运行时拥有一项自观的能力。

通过这种能力可以彻底的了解自身的情况为下一步的动作做准备。

Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。

在JDK在主要实现反射机制类都位于java.lang.reflect包中:

1.Class类:代表一个类

2.Field类:代表类的成员变量(成员变量也称为类的属性)

3.Method类:代表类的方法。

4.Constructor类:代表类的构造方法。

5.Array类

后面四个看看API就明白了



这里主要说下Class类

Class是Reflection故事起源。针对任何您想探勘的class,唯有先为它产生一个Class object。

Class对象怎样产生的?

根据API解释

Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class object。注意Class并没有public constructor。


怎么得到Class对象?

在我上一篇博客上反射(1)也有提到。

这里再说一下:

一般有三种方式得到Class对象

1、利用每个类都有的getClass()方法(java.lang.Object),

如String str = "xx";

Class c1 = str.getClass();

c1.getName();得到java.lang.String

2、利用static method------Class.forName()(最常被使用)

如Class c2 = Class.forName ("java.lang.String");

c2.getName();得到java.lang.String


3、类名.class方法

Class c3 = String.class;

c3.getName();得到java.lang.String


1)对于一些基本类型数据还可以通过.TYPE的方式,且看下面代码


package com.testclass;

import java.lang.reflect.Method;

public class Reflection {
	public static void main(String args[])
	{	
		try {
			/**
			 * 我们的程序中的每个类都有一个相应的Class对象.每当新的类被编译
			 * 完成,就会产生一个Class对象存储与相同的.class文件内.执行期间
			 * 当你想要产生该class的对象是,JVM便会检查该型别的Class对象是  
			 * 否被加载.如果没被加载,JVM会根据名称找到.class文件并加载它
			 * 
			 * java中每个class都有一个相应的Class对象,当编写好一个类,编译完成后,
			 * 在生成的.class文件中,就产生一个Class对象,用来表示
			 * 这个类的类型信息。获得Class实例的三种方式
			 */
			//1、使用Class的静态方法forName(),用类的名字获取一个Class实例
			Class c = Class.forName("com.testclass.TestOne");
			System.out.println(c.getName());//输出com.md5.TestOne
			
			TestOne test = (TestOne)c.newInstance();//产生这个class类对象的一个实例,调用该类的无参的构造方法,作用等同于new TestOne();
			/**
			 * 有异常处理
			 * newInstance创建对象实例的时候会调用无参的构造函数,
			 * 所以必需确保类中有无参数的构造函数,否则将会抛出java.lang.InstantiationException异常。
			 */
			
			System.out.println("=====================================================");
			
			//2、利用对象调用getClass()方法获取该对象的的Class实例,对象实现存在
			TestOne  test2 = new TestOne();
			Class c2 = test2.getClass();
			System.out.println(c2.getName());//输出com.md5.TestOne
			Method[] m = c2.getDeclaredMethods();//得到TestOne中的所有类型的自定义的方法,
//			Method[] m = c2.getMethods();//得到TestOne中的public类型的方法,不仅仅是自定义的,还有继承于Object类的
			System.out.println("TestOne中的所有方法");
			for(Method m2 : m)
			{
				System.out.println(m2);
			}
			
			System.out.println("======================================================");
			//3-1、运用.class方式获取Class实例(类)			
			Class c3 = TestOne.class;
			System.out.println(c3.getName());//输出com.md5.TestOne
			
			
			//3-2 运用.class的方式获取Class实例(基本类型)
			Class c4 = int.class;
			System.out.println("基本类型Class实例:"+c4.getName());//输出int
			
			//3-3运用.class的方式获取Class实例(封装类型类型)
			Class c5 = Integer.TYPE;//获取的是这个Integer类型
			System.out.println(c5.getName());//输出int
			
			
			Class c6 = Integer.class;//获取的是这个Integer的Class对象
			System.out.println(c6.getName());//输出java.lang.Integer
			
			
		} catch (ClassNotFoundException e) {//如果包下不存在相应的com.md5.TestOne的.class文件,会抛出异常
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		catch (InstantiationException e) {
			e.printStackTrace();
		} 
		catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//使用一般方法构造实例
		TestOne two = new TestOne();//静态块只会被加载一次,第二次创建对象,不会再加载静态块,只执行构造方法
	}
	
}

class TestOne{
	static {
		System.out.println("静态块执行");
	}
	public TestOne(){
		System.out.println("构造方法执行");
	}
	void getTest()
	{
		
	}
	public void getTest2()
	{
		
	}
	
}

2)对于method方法还可以输出方法的参数等信息、

package com.testclass;

import java.lang.reflect.Method;

public class Reflection2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		try {
			Class c = Class.forName("com.testclass.Test2");
			Method[] m = c.getDeclaredMethods();

			for(Method method : m)
			{
				Class[] pre = method.getParameterTypes();
				/**
				 * 按照声明顺序返回 Class 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型。
				 * 如果底层方法不带参数,则返回长度为 0 的数组
				 */
				for(Class cc : pre)
				{
//					System.out.println(cc);//输出所有参数类型
					System.out.println(cc.getName());//输出所有参数类型,这样输出更好
				}
			}
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
//		Class c = Integer.class;
//		System.out.println(c);//输出class java.lang.Integer
		
//		Class c = int.class;
//		System.out.println(c);//输出int

	}

}

class Test2
{
	public void getTest(Integer a,int b)
	{
		
	}
	
}


3)利用反射可以验证一个对象是否属于这个类

package com.testclass;

public class Reflection3 {
	public static void main(String[] args) {
		try {
			Class c = Class.forName("com.testclass.Test2");//!!!
			
			String s = "";
			System.out.println(c.isInstance(s));//输出false
			System.out.println(c.isInstance(new Test2()));//输出true
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}

4)反射在框架中用的很多,工厂模式,当你不断的new 就不断的分配内存空间,当你new到一定程度没有空间的时候,不就出问题了。一般都不考虑用new来构造实例,除非特殊情况。

new是不在内存中有了空间的分配,当知道类型的时候可以new,当不知道类型的时候,不能new


还要明白在java里面任何class都要装载在虚拟机上才能运行。Class.forName就是装载类用的(和new 不一样,要分清楚)。

Class.forName("oracle.jdbc.driver.OracleDriver");只有加载了数据库驱动(就是加载这个.class文件)之后,才能用DriverManager。

DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl","xxx","xxx");


5)利用反射,动态加载类

要动态加载类,必须有个接口或者是抽象类(A),反射所加载的类是A的实现类或者是子类,否则动态加载的类毫无意义可言。

AA a = (AA)(Class.forName("xxx.xxx.xxx.AAImplClass").newInstance());//其中的forName中的类路径可以动态的传进来


7)数组对象的反射(这个还在研究中)

int[] a = new int[2];
int[]b = new int[5];
System.out.println(a.getClass().getName());//输出结果 [I
System.out.println(b.getClass().getName());输出结果 [I



6)此外,我们还可以在servlet中发现发射的影子

有时我们会奇怪,当我们把一个form表单提交给一个servlet处理时,我们并没有创建这个servlet对象,但是怎么呢调用其中的方法的呢?

当一个request请求传递给web服务器后,web服务器利用发射机制创建相应servlet对象,这个对象调用init方法将这个对象实例加载内存中(init方法只调用一次),然后就可以用这个实例调用servlet中的各种方法





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EmineWang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值