认识Java反射机制

认识Java反射机制

     在正常情况下,必须知道一个类才可以实例化对象,但是在Java中也通过一个对象来找到其所在的类的信息,那么这实际上是Class类的功能。

package zyz.demo;
class X{ };
public class GetClassDemo01{
	public static void main(String args[]){
		X x = new X() ;	// 实例化X类的对象
		System.out.println(x.getClass().getName()) ;	// 得到对象所在的类的完整名字
	}
};   
 结果:zyz.demo.X

 

 

 

 

 

实例化Class类型对象

实例化Class类型对象的方法有三种:

第一种:通过forName()方法

第二种:类.class

第三种:对象.getClass()

 

package zyz.demo;
class X{
};
public class GetClassDemo02{
	public static void main(String args[]){
		Class<?> c1 = null ;		// 指定泛型
		Class<?> c2 = null ;		// 指定泛型
		Class<?> c3 = null ;		// 指定泛型
		try{
			// 以下的操作形式是在开发中最常用的一种形式
			c1 = Class.forName("org.lxh.demo15.getclassdemo.X") ;
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		c2 = new X().getClass() ;	// 通过Object类中的方法实例化
		c3 = X.class ;	// 通过类.class实例化
		System.out.println("类名称:" + c1.getName());// 得到类的名称
		System.out.println("类名称:" + c2.getName());// 得到类的名称
		System.out.println("类名称:" + c3.getName());// 得到类的名称
	}
};

 

一旦可以实例化Class类之后,就可以进行反射的进一步操作。

 

1、实例化对象

class Person{
	private String name ;	// name属性
	private int age ;		// age属性
	public void setName(String name){
		this.name = name ;
	}
	public void setAge(int age){
		this.age = age ;
	}
	public String getName(){
		return this.name ;
	}
	public int getAge(){
		return this.age ;
	}
	public String toString(){	// 覆写toString()方法
		return "姓名:" + this.name + ",年龄:" + this.age  ;
	}
};
public class Demo01{
	public static void main(String args[]){
		Class<?> c = null ;		// 声明Class对象
		try{
			c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Person per = null ;	// 声明Person对象
		try{
			per = (Person)c.newInstance() ;	// 实例化对象
		}catch(Exception e){
			e.printStackTrace() ;
		}
		per.setName("李兴华") ;		// 设置姓名
		per.setAge(30) ;				// 设置年龄
		System.out.println(per) ;	// 内容输出,调用toString()
	}
};

 

 

 

 

     通过以上的代码,可以发现,即使不使用关键字new对象也可以进行实例化操作,反射的作用。但是,在使用以上操作的时候有一点必须注意,在操作中类中必须存在无参构造方法。否则无法实例化。

 

     所以说,使用以上的方法实际上还是需要类中构造方法的支持,符合于对象的实例化需求。

如果要想调用有参,由必须按照以下的步骤进行:

1、通过Class类中的getConstructors()取得本类中的全部构造方法。

2、向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数。

3、之后通过Constructor实例化对象

package org.lxh.demo15.instancedemo ;
import java.lang.reflect.Constructor ;	// 导入反射机制包
class Person{
	private String name ;	// name属性
	private int age ;		// age属性
	public Person(String name,int age){
		this.setName(name) ;
		this.setAge(age);
	}
	public void setName(String name){
		this.name = name ;
	}
	public void setAge(int age){
		this.age = age ;
	}
	public String getName(){
		return this.name ;
	}
	public int getAge(){
		return this.age ;
	}
	public String toString(){	// 覆写toString()方法
		return "姓名:" + this.name + ",年龄:" + this.age  ;
	}
};
public class InstanceDemo03{
	public static void main(String args[]){
		Class<?> c = null ;		// 声明Class对象
		try{
			c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Person per = null ;	// 声明Person对象
		Constructor<?> cons[] = null ;
		cons = c.getConstructors() ;
		try{
			// 第一个数组
			per = (Person)cons[0].newInstance("李兴华",30) ;	// 实例化对象
		}catch(Exception e){
			e.printStackTrace() ;
		}
		System.out.println(per) ;	// 内容输出,调用toString()
	}
};

 

 

 

     但是,从实际角度看,如果要使用反射进行对象的实例化操作,最好在类中存在无参构造。

 

2、取得类所实现的全部接口

 

package org.lxh.demo15.classinfodemo ;
public class GetInterfaceDemo{
	public static void main(String args[]){
		Class<?> c1 = null ;		// 声明Class对象
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化对象
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Class<?> c[] = c1.getInterfaces() ;	// 以数组形式返回实现的全部接口
		for(int i=0;i<c.length;i++){
			System.out.println("实现的接口名称:" + c[i].getName()) ;	// 输出接口名称
		}
	}    
};
结果:实现的接口名称:org.lxh.demo15.China

 

3、取得父类

package org.lxh.demo15.classinfodemo ;
public class GetSuperClassDemo{
	public static void main(String args[]){
		Class<?> c1 = null ;		// 声明Class对象
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化对象
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Class<?> c2 = c1.getSuperclass() ;	// 取得父类
		System.out.println("父类名称:" + c2.getName()) ;
	}
};        
结果:父类名称:java.lang.Object

 

 

 

4、取得类中的全部构造方法

 

package org.lxh.demo15.classinfodemo ;
import java.lang.reflect.Constructor ;	// 导入构造方法的包
public class GetConstructorDemo01{
	public static void main(String args[]){
		Class<?> c1 = null ;		// 声明Class对象
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化对象
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Constructor<?> con[] = c1.getConstructors() ;	// 取得一个类中的全部构造
		for(int i=0;i<con.length;i++){
			System.out.println("构造方法:" + con[i]) ;	 // 输出构造,直接打印
		}   
}         	  
};   
结果:
构造方法:public org.lxh.demo15.Person()
构造方法:public org.lxh.demo15.Person(java.lang.String)
构造方法:public org.lxh.demo15.Person(java.lang.String,int)

  

 

 

     以上的操作确实取得了类中的构造方法,但是此时是通过对象直接打印取得的,肯定会调用Constructor类中的toString()方法。

     Constructor类中存在了以下的几个方法:

    取得修饰符:public int getModifiers()

    取得方法名称:public String getName()

    取得参数的类型:public Class<?>[] getParameterTypes()

package org.lxh.demo15.classinfodemo ;
import java.lang.reflect.Constructor ;	// 导入构造方法的包
public class GetConstructorDemo02{
	public static void main(String args[]){
		Class<?> c1 = null ;		// 声明Class对象
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化对象
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Constructor<?> con[] = c1.getConstructors() ;	// 取得一个类中的全部构造
		for(int i=0;i<con.length;i++){
			Class<?> p[] = con[i].getParameterTypes() ;		// 得到构造方法中的全部参数
			System.out.print("构造方法:" ) ;	 // 输出构造,直接打印
			System.out.print(con[i].getModifiers() + " ") ;	// 得到修饰符
			System.out.print(con[i].getName()) ;	// 取得构造方法的名字
			System.out.print("(") ;
			for(int j=0;j<p.length;j++){
				System.out.print(p[j].getName() + " arg" + i) ;
				if(j<p.length-1){
					// 判断此是否是最后一个参数
					System.out.print(",");	// 输出“,”
				}
			}
			System.out.println("){}") ;
		}
	}
};

 

 

 

运行结果:

构造方法:1 org.lxh.demo15.Person(){}

构造方法:1 org.lxh.demo15.Person(java.lang.String arg1){}

构造方法:1 org.lxh.demo15.Person(java.lang.String arg2,int arg2){}

此时,在操作之后,发现,所有的修饰符变成了数字。需要还原修饰符,改写上面的代码

package org.lxh.demo15.classinfodemo ;
import java.lang.reflect.Constructor ;	// 导入构造方法的包
import java.lang.reflect.Modifier ;	// 导入构造方法的包
public class GetConstructorDemo03{
	public static void main(String args[]){
		Class<?> c1 = null ;		// 声明Class对象
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化对象
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Constructor<?> con[] = c1.getConstructors() ;	// 取得一个类中的全部构造
		for(int i=0;i<con.length;i++){
			Class<?> p[] = con[i].getParameterTypes() ;		// 得到构造方法中的全部参数
			System.out.print("构造方法:" ) ;	 // 输出构造,直接打印
			int mo = con[i].getModifiers() ; // 得到所要的访问权限
			System.out.print(Modifier.toString(mo) + " ") ;	// 转换得到的修饰符
			System.out.print(con[i].getName()) ;	// 取得构造方法的名字
			System.out.print("(") ;
			for(int j=0;j<p.length;j++){
				System.out.print(p[j].getName() + " arg" + i) ;
				if(j<p.length-1){
					// 判断此是否是最后一个参数
					System.out.print(",");	// 输出“,”
				}
			}
			System.out.println("){}") ;
		}
	}
};

 

 

 

 运行结果:

构造方法:public org.lxh.demo15.Person(){}

构造方法:public org.lxh.demo15.Person(java.lang.String arg1){}

构造方法:public org.lxh.demo15.Person(java.lang.String arg2,int arg2){}

 

5、取得类中的全部方法

package org.lxh.demo15.classinfodemo ;
import java.lang.reflect.Method ;	// 导入构造方法的包
import java.lang.reflect.Modifier ;	// 导入构造方法的包
public class GetMethodDemo{
	public static void main(String args[]){
		Class<?> c1 = null ;		// 声明Class对象
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化对象
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Method m[] = c1.getMethods() ;	// 取得全部方法
		for(int i=0;i<m.length;i++){
			Class<?> r = m[i].getReturnType() ;	// 得到返回值类型
			Class<?> p[] = m[i].getParameterTypes() ;	// 取得全部参数的类型
			int xx = m[i].getModifiers() ;	// 得到修饰符
			System.out.print(Modifier.toString(xx) + " ") ;	// 输出修饰符
			System.out.print(r + " ") ;
			System.out.print(m[i].getName()) ;
			System.out.print("(") ;
			for(int j=0;j<p.length;j++){
				System.out.print(p[j].getName() + " " + "arg" + j) ;
				if(j<p.length-1){
					System.out.print(",") ;
				}
			}
			Class<?> ex[] = m[i].getExceptionTypes() ;	// 取出异常
			if(ex.length>0){ // 判断是否产生异常
				System.out.print(") throws ") ;
			}else{
				System.out.print(")") ;
			}
			for(int j=0;j<ex.length;j++){
				System.out.print(ex[j].getName()) ;
				if(j<p.length-1){
					System.out.print(",") ;
				}
			}
			System.out.println() ;
		}
	}
};

 

 

运行结果:

public void sayChina()

public class java.lang.String sayHello(java.lang.String arg0,int arg1)

public void setAge(int arg0)

public int getAge()

public class java.lang.String getName()

public void setName(java.lang.String arg0)

public final void wait() throws java.lang.InterruptedException

public final void wait(long arg0,int arg1) throws java.lang.InterruptedException,

public final native void wait(long arg0) throws java.lang.InterruptedException

public native int hashCode()

public final native class java.lang.Class getClass()

public boolean equals(java.lang.Object arg0)

public class java.lang.String toString()

public final native void notify()

public final native void notifyAll()

 

     在一般的开发工具中经常看见随笔提示功能,实际上此功能就是利用以上的程序完成的。

 

6、取得类中的属性

package org.lxh.demo15.classinfodemo ;
import java.lang.reflect.Field ;	// 导入构造方法的包
import java.lang.reflect.Modifier ;	// 导入构造方法的包
public class GetFieldDemo{
	public static void main(String args[]){
		Class<?> c1 = null ;		// 声明Class对象
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化对象
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		{	// 本类属性
			Field f[] = c1.getDeclaredFields() ;	// 取得本类中的属性
			for(int i=0;i<f.length;i++){
				Class<?> r = f[i].getType() ;	// 得到属性类型
				int mo = f[i].getModifiers() ;	// 得到修饰符的数字
				String priv = Modifier.toString(mo) ; // 还原修饰符
				System.out.print("本类属性:") ;
				System.out.print(priv + " ") ;	
				System.out.print(r.getName() + " ") ;	// 得到属性类型
				System.out.print(f[i].getName()) ;	// 输出属性名称
				System.out.println(" ;") ;
			}
		}
		{	// 公共属性
			Field f[] = c1.getFields() ;	// 取得本类中的公共属性
			for(int i=0;i<f.length;i++){
				Class<?> r = f[i].getType() ;	// 得到属性类型
				int mo = f[i].getModifiers() ;	// 得到修饰符的数字
				String priv = Modifier.toString(mo) ; // 还原修饰符
				System.out.print("公共属性:") ;
				System.out.print(priv + " ") ;	
				System.out.print(r.getName() + " ") ;	// 得到属性类型
				System.out.print(f[i].getName()) ;	// 输出属性名称
				System.out.println(" ;") ;
			}
		}
	}
};

 

 

运行结果:

本类属性:private java.lang.String name ;

本类属性:private int age ;

公共属性:public static final java.lang.String NATIONAL ;

公共属性:public static final java.lang.String AUTHOR ;

 

7、通过反射调用类中的方法

    

package org.lxh.demo15.invokedemo ;
import java.lang.reflect.Method ;
public class InvokeSayChinaDemo{
	public static void main(String args[]){
		Class<?> c1 = null ;
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化Class对象
		}catch(Exception e){}
		try{
			Method  met = c1.getMethod("sayChina") ;	// 找到sayChina()方法
			met.invoke(c1.newInstance()) ;	// 调用方法
		}catch(Exception e){
			e.printStackTrace() ;
		}
	}
};

 

 

 

     如果现在要调用的方法中存在了参数,则必须设置参数的类型及内容。

package org.lxh.demo15.invokedemo ;
import java.lang.reflect.Method ;
public class InvokeSayHelloDemo{
	public static void main(String args[]){
		Class<?> c1 = null ;
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化Class对象
		}catch(Exception e){}
		try{
			Method  met = c1.getMethod("sayHello",String.class,int.class) ;	// 找到sayHello(String name,int age)方法
			String rv = null ;
			rv = (String)met.invoke(c1.newInstance(),"李兴华",30) ;	// 调用方法
			System.out.println(rv) ;
		}catch(Exception e){
			e.printStackTrace() ;
		}
	}
};

 

 

 

8、通过反射调用类setter及getter

     SetterGetter方法是一个标准的属性的访问方法,如果一个类的属性被封闭,则必须通过settergetter方法设置和取得,实际上此方法的操作之所以要这样规定,主要原因是由于反射机制可以给予支持的。

package org.lxh.demo15.invokedemo ;
import java.lang.reflect.Method ;
public class InvokeSetGetDemo{
	public static void main(String args[]){
		Class<?> c1 = null ;
		Object obj = null ;
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化Class对象
		}catch(Exception e){}
		try{
			obj = c1.newInstance() ;
		}catch(Exception e){}
		setter(obj,"name","李兴华",String.class) ;	// 调用setter方法
		setter(obj,"age",30,int.class) ;	// 调用setter方法
		System.out.print("姓名:") ;
		getter(obj,"name") ;
		System.out.print("年龄:") ;
		getter(obj,"age");
	}
	/**
		Object obj:要操作的对象
		String att:要操作的属性
		Object value:要设置的属性内容
		Class<?> type:要设置的属性类型
	*/

 

 

 

9、通过反射调用属性

     观察,以上的操作中是否需要类的settergetter方法支持呢?证明以上的操作调用与settergetter无关,但是为了保证程序的安全性,最好还是通过settergetter方法完成调用。

package org.lxh.demo15.invokedemo ;
import java.lang.reflect.Field ;
public class InvokeFieldDemo{
	public static void main(String args[]) throws Exception{
		Class<?> c1 = null ;
		Object obj = null ;
		c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化Class对象
		obj = c1.newInstance() ;
		Field nameField = null ;
		Field ageField = null ;
		nameField = c1.getDeclaredField("name") ;	// 取得name属性
		ageField = c1.getDeclaredField("age") ;	// 取得name属性
		nameField.setAccessible(true) ;	// 此属性对外部可见
		ageField.setAccessible(true) ;	// 此属性对外部可见
		nameField.set(obj,"李兴华") ;	// 设置name属性内容
		ageField.set(obj,30) ;			// 设置age属性内容
		System.out.println("姓名:" + nameField.get(obj)) ;
		System.out.println("年龄:" + ageField.get(obj)) ;
	}
};

 

 

 

10、通过反射操作数组

     反射机制不光只能用在类中,也可以应用在任意的引用数据类型上,当然,这就包含了数组,数组使用Array类完成。

     Class类中存在以下一个方法:

public Class<?> getComponentType()

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值