Java基础之反射(一):反射入门

什么叫JAVA反射(Reflection)?

谈到反射,我们首先了解下动态语言。

“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。

从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。


尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。

这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。

换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),

并生成其对象实体、或对其fields设值、或唤起其methods

这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。

Reflection和introspection是常被并提的两个术语。


那在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?

答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。


JAVA反射提供了那些功能

  • 在运行时判断任意一个对象所属的类。

  • 在运行时构造任意一个类的对象。

  • 在运行时判断任意一个类所具有的成员变量和方法。

  • 在运行时调用任意一个对象的方法。
Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其 modifiers(诸如public, static 等等)、 superclass(例如Object)、实现之 interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改变fields内容或调用methods。


JAVA反射会用到哪些类

在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:
  • Class类:代表一个类。

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

  • Method类:代表类的方法。

  • Constructor 类:代表类的构造方法。

  • Array类:提供了动态创建数组,以及访问数组的元素的静态方法

JAVA反射我们怎么用

Class是Reflection起源,针对任何你想探勘的class,唯有先为它产生一个Class Object,接下来才能经由后者唤醒
为数十多个的Reflection APIs

1、如何获得获得一个类以及类的相关信息
	/**
	 * 通过一个对象获得完整的包名和类名 
	 * @param args
	 */
	public static void main(String[] args) {
		Demo demo=new Demo();
		
		System.out.println(demo.getClass().getName());
		
		System.out.println(Demo.class.getName());
		
		System.out.println(Demo.class.getSimpleName());
	}
打印结果:
com.reflect.Demo
com.reflect.Demo
Demo


这个例子告诉我们既可以通过对象调用getClass方法获取类的信息,也可以直接类.class的形式。


2、我们所常见的Class.forName(" ");
	public static void main(String[] args) {
		Class<?> demo1=null;
		Class<?> demo2=null;
		Class<?> demo3=null;
		try 
		{
			demo1=Class.forName("com.reflect.Demo");
		} 
		catch (ClassNotFoundException e) 
		{
			e.printStackTrace();
		}
		demo2=new Demo().getClass();
		demo3=Demo.class;
		System.out.println("类名称"+demo1.getName());
		System.out.println("类名称"+demo2.getName());
		System.out.println("类名称"+demo3.getName());
	}
打印结果:
类名称com.reflect.Demo
类名称com.reflect.Demo
类名称com.reflect.Demo


记住这是第三种获得类的方式,给定完整的字符串名的类或接口,返回一个类对象。

3、通过一个类去实例化它的对象,不采取new的方式
	public static void main(String[] args) {
		Class<?> demo = null;
		try 
		{
			demo = Class.forName("com.reflect.Person");
		} 
		catch (ClassNotFoundException e) 
		{
			e.printStackTrace();
		}		
		
		Person person = null;
		try 
		{
			person = (Person)demo.newInstance();
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		} 
		person.setName("jay");
		person.setAge(11);
		System.out.println(person);
	}
打印结果:
[jay||11]

这里我们应该看到了newInstance方法,调用它就能返回一个类的实例对象,注意的是,定义的类必须提供一个无参的构造方法才能通过此方法去实例化。
如果没有提供呢,我们是不是就没法通过反射的方式实例化了呢,当然不会,请看下一个示例。

4、实例化一个无参构造方法的类
	public static void main(String[] args) {
		Class<?> demo = null;
		try 
		{
			demo = Class.forName("com.reflect.Person");
		} 
		catch (ClassNotFoundException e)
		{
			e.printStackTrace();
		}		
		
        try
        {
        	Person person = (Person)demo.getConstructor(new Class[]{String.class}).newInstance(new Object[]{"Rollen"});
        	System.out.println(person);
        }
        catch(Exception e)
        {
        	e.printStackTrace();      
        }
	}
打印结果:
[Rollen||0]

因为构造方法的参数个数及类型都是未知的,所以这里用到的是传数组的方式。

5、得到一个类的所有接口
	public static void main(String[] args) {
		Class<?> demo=null;
		try
		{
			demo=Class.forName("com.reflect.People"); 
		}
		catch (Exception e) 
		{
			e.printStackTrace();
		} 
		//保存所有的接口        
		Class<?> intes[]=demo.getInterfaces(); 
		
		for (int i = 0; i < intes.length; i++) 
		{
			System.out.println("实现的接口   "+intes[i].getName());  
		}
	}
打印结果:
实现的接口   com.reflect.China

6、得到一个类的父类
	public static void main(String[] args) {
        Class<?> demo=null;         
        try
        {             
        	demo=Class.forName("com.reflect.People");         
        }
        catch (Exception e) 
        {             
        	e.printStackTrace();         
        }         
        //取得父类         
        Class<?> temp=demo.getSuperclass();         
        System.out.println("继承的父类为:   "+temp.getName()); 
	}
打印结果:
继承的父类为:   java.lang.Object

7、得到一个类的所有构造方法
	public static void main(String[] args) {
        Class<?> demo = null; 
        try
        {
        	demo = Class.forName("com.reflect.People");         
        }
        catch (Exception e) 
        {
        	e.printStackTrace();    
        }
        Constructor<?>cons[]=demo.getConstructors();         
        for (int i = 0; i < cons.length; i++) 
        {
        	System.out.println("构造方法:  "+cons[i]);   
        } 
	}
打印结果:
构造方法:  public com.reflect.People(java.lang.String)
构造方法:  public com.reflect.People()


8、得到所有构造方法的修饰类型及参数类型
	public static void main(String[] args){
		Class<?> demo = null;
		try 
		{
			demo = Class.forName("com.reflect.People");
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		Constructor<?> cons[] = demo.getConstructors();
		for (int i = 0; i < cons.length; i++) 
		{
			Class<?> p[] = cons[i].getParameterTypes();
			System.out.print("构造方法:  ");
			// 权限修饰符
			int mo = cons[i].getModifiers();
			System.out.print(Modifier.toString(mo) + " ");
			//构造方法名字
			String consName=cons[i].getName();
			System.out.print(consName+"(");
			for (int j = 0; j < p.length; ++j) 
			{
				//参数类型名字
				String typeName=p[j].getName();
				System.out.print(typeName + " arg" + i);
				if (j < p.length - 1) 
				{
					System.out.print(",");
				}
			}
			System.out.println("){}");
		}
	}
打印结果:
构造方法:  public com.reflect.People(java.lang.String arg0){}
构造方法:  public com.reflect.People(){}


9、得到属性的修饰符,及类型和名字
	public static void main(String[] args) {
		Class<?> demo = null;
		try 
		{
			demo = Class.forName("com.reflect.People");
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		System.out.println("===============本类属性========================");
		// 取得本类的全部属性
		Field[] field = demo.getDeclaredFields();
		for (int i = 0; i < field.length; i++) 
		{
			// 权限修饰符
			int mo = field[i].getModifiers();
			String priv = Modifier.toString(mo);
			// 属性类型
			Class<?> type = field[i].getType();
			//属性字段名字
			String name=field[i].getName();
			System.out.println(priv + " " + type.getName() + " "+ name + ";");
		}
		System.out.println("===============实现的接口或者父类的属性========================");
		// 取得实现的接口或者父类的属性
		Field[] filed1 = demo.getFields();
		for (int j = 0; j < filed1.length; j++) 
		{
			// 权限修饰符
			int mo = filed1[j].getModifiers();
			String priv = Modifier.toString(mo);
			// 属性类型
			Class<?> type = filed1[j].getType();
			//属性字段名字
			String name=filed1[j].getName();
			System.out.println(priv + " " + type.getName() + " "+ name + ";");
		}
	}
打印结果:
===============本类属性========================
private java.lang.String sex;
===============实现的接口或者父类的属性========================
public static final java.lang.String name;
public static final int age;


10、通过反射的方式调用某个对象的方法
	public static void main(String[] args) {
		Class<?> demo = null;
		try 
		{
			demo = Class.forName("com.reflect.People");
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		try 
		{
			// 调用Person类中的sayChina方法
			Method method = demo.getMethod("sayChina");
			method.invoke(demo.newInstance());
			// 调用Person的sayHello方法
			method = demo.getMethod("sayHello", new Class[]{String.class, int.class});
			method.invoke(demo.newInstance(), new Object[]{"Rollen", 20} );
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
	}
打印结果:
hello ,china
Rollen  20


11、通过反射操作属性
正常情况下,我们是不可以直接操作其它某个对象的私有属性,但是反射可以做到
	public static void main(String[] args) throws Exception {
        Class<?> demo = null;       
        
        Object obj = null;  
        
        demo = Class.forName("com.reflect.People");  
        
        obj = demo.newInstance();     
        
        Field field = demo.getDeclaredField("sex");   
        
        field.setAccessible(true);   
        
        field.set(obj, "男");    
        
        System.out.println(field.get(obj)); 
	}
打印结果:


12、通过反射取得并修改数组的信息
	public static void main(String[] args) {
        int[] temp={1,2,3,4,5};  
        
        Class<?>demo=temp.getClass().getComponentType();  
        
        System.out.println("数组类型: "+demo.getName()); 
        
        System.out.println("数组长度  "+Array.getLength(temp));  
        
        System.out.println("数组的第一个元素: "+Array.get(temp, 0));  
        
        Array.set(temp, 0, 100);         
        
        System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0)); 
        
	}
打印结果:
数组类型: int
数组长度  5
数组的第一个元素: 1
修改之后数组第一个元素为: 100


你可能感兴趣的:(java,反射,reflection)