java(19) - 反射机制

一.反射:

        反射机制就是java程序在运行时拥有自观能力,能知晓类中的所有属性和方法。

      通过反射能得到类中的任何属性和方法,也就是说反射可以打破类的封装特性,可以通过反射来调用私有方法。

      让我们看个小例子:

     

public class Test {
    public static void main(String[] args) throws Exception {
    	
    	
		
    	Class<?>  classType  = MethodTest.class;
    	
    	Method[]  method = classType.getDeclaredMethods();
    	
    	for(Method m :method){
    		
    		System.out.println(m);
    	}
    	
	}
}


public class MethodTest extends MethodTest2 {
        
	public MethodTest(){}
	   
	public void methodOne(){
		
	}
	private void methodTwo(){
		
	}
	private String methodThree(){
          return null;		
	}
	public int methodFour(){
		return 0;
	}
	
}


打印:

public void Reflection3.MethodTest.methodOne()
private void Reflection3.MethodTest.methodTwo()
private java.lang.String Reflection3.MethodTest.methodThree()
public int Reflection3.MethodTest.methodFour()

这个小例子为我们显示MethodTest类中的所有方法,其中包括了私有方法和普通方法。要想使用反射就必须获得待处理类的class对象。


除了我上面MethodTest.class获取Class对象的方法还有两种,加上我用的一共三种方式:

1).使用Class类的静态方法forName:Class.forName("java.lang.String");

例子:

public>
会打印出String中的所有方法。


2).就是使用我第一个例子中的方法。类.class的方法。


3).使用对象的getClass()方法。


例子:

public class Test {
    public static void main(String[] args) throws Exception {
    	
    	String str = "abc";
		
    	Class<?>  classType  = str.getClass();
    	
    	Method[]  method = classType.getDeclaredMethods();
    	
    	for(Method m :method){
    		
    		System.out.println(m);
    	}
    	
	}
}

这个将会打印出String类中所有的方法。



如何通过反射使用类中的public类型方法:

public class Test {
       
	  public int sum(int a,int b){
		  
		  return a + b;
	  }
	  
	  public String Course(String str){
		  return "课程名:" + str;
	  }
	  
	  public static void main(String[] args) throws Exception{
		
		  Class<?>  classType = Test.class;
		  //通过classType.newInstance()来返回Test的实例对象,只能调用无参构造。
		  Object obj = classType.newInstance();
		  //第一个参数指定类中的方法名称,第二个参数指定其方法的参数类型,为什么会有第二个参数,因为类中会有重载的方法,用此来进行区分。
		  Method sumMethod = classType.getMethod("sum",int.class,int.class);
		  
		  Object sum = sumMethod.invoke(obj,1,2);
		  
		  System.out.println((Integer)sum);
		
		  System.out.println("==========================================");
		  
		  Method  courseMethod = classType.getMethod("Course",String.class);
		  
		  Object course  =  courseMethod.invoke(obj,"Java");
		  
		  System.out.println(course);
		  
  	  }
	  
}


打印:

3
==========================================
课程名:Java


上面的例子中通过classType.newInstance()来获得Test的实例,但是这个方法只能调用无参的构造方法。使用方法时用通过invoke(传入方法存在类的实例,传入方法的参数)。

有参的构造方法使用格式:先获得Class对象,然后通过该对象获得相应的Constructor对象,再通过该Constructor对象的newInstance()方法生成。

如果想通过类的带参构造方法生成对象,只能使用下面例子中的格式。

例子:

public class Test {
      public static void main(String[] args) throws Exception {
		
    	  Class<?> classType = People.class;
    	  /*
    	   * Constructor con  = classType.getConstructor(new Class[]{});
    	   * Object obj = con.newInstance(new Object[]{});
    	   * 也可以创建不带参数的对象。
    	   */
    	  Constructor con  = classType.getConstructor(String.class);
    	  Object obj = con.newInstance("zhangsan");
    	  System.out.println(obj);
	}
}
class People {
    private String name;
    public People(){}
    public People(String name){
   	 this.name = name;
    }
    public String getName(){
   	 return name;
    }
} 


如何通过反射使用类中的属性和方法:

例子:

public class ReflectionTest {
	   //执行对一个对象的copy操作。
	   public Object copy(Object o) throws Exception{
		    Class<?> cs = Student.class;
			Object obj = cs.getConstructor(new Class[]{}).newInstance(new Object[]{});
			Field[] field = cs.getDeclaredFields();
			for(Field f:field){
				String name = f.getName();
				String firstLetter = name.substring(0,1).toUpperCase();
				//获得对应属性的set和get方法的字符串。
			    String getMethodName = "get"+firstLetter+name.substring(1);
			    String setMethodName = "set"+firstLetter+name.substring(1);
			    //获得对应属性的set和get方法。
			    Method getMethod = cs.getMethod(getMethodName,new Class[]{});
			    Method setMethod = cs.getMethod(setMethodName,new Class[]{f.getType()});
			    //获得属性的返回值。
			    Object value = getMethod.invoke(o,new Object[]{});
			    //添加到要返回的对象中去。
			    setMethod.invoke(obj,new Object[]{value});
	   }  
			return obj;
}
       public static void main(String[] args) throws Exception{
    	   Student t = new Student("zhangsan",1,2);
    	   ReflectionTest r =  new ReflectionTest();
    	   Student s = (Student)r.copy(t);
    	   System.out.println(s.getAge()+"   "+s.getName()+"    "+s.getNumber());
	   }
}
class Student {
	  public String name;
	  private  int number;
	  public int age;
	  
	  public Student(){}
	  public Student(String name,int age,int number){
		  this.age = age;
		  this.name = name;
		  this.number = number;
	  }
   	  public String getName() {
		return name;
	  }
	  public void setName(String name) {
		this.name = name;
	  }
	  public int  getNumber() {
		return number;
	  }
	  public void setNumber(int number) {
		this.number = number;
	  }
	  public int getAge() {
		return age;
	  }
	  public void setAge(int age) {
		this.age = age;
	  }
}


反射应用于数组:

例子:

public class Test {
      public static void main(String[] args) throws Exception {
    	  
		Class<?>  classType  = Class.forName("java.lang.String");
		//第一个参数设置数组的类型,第二个设置数组的大小。
		Object  array = Array.newInstance(classType,10);
		//第一个参数目标数组,第二个参数指定存放位置,第三个参数要存入的元素。
	    Array.set(array,5,"java");
     	//打印
	    System.out.println((String)Array.get(array,5));
	}
}
打印: java

对于多维数组的创建:

例子:

public class Test {
      public static void main(String[] args) throws Exception {
    	 //Integer.TYPE返回原生数据类型,Integer.class返回类的类型,第一个参数设置数组的类型,第二个设置数组的大小。
		Object array = Array.newInstance(Integer.TYPE,3,3,3);
		
		Object array2 = Array.get(array,2);
		
 		array2 = Array.get(array2,2);
		
 		Array.setInt(array2,2,10);
		
	    int[][][]  a  =  (int[][][])array;
     	//打印
	    System.out.println(a[2][2][2]);
	}
} 
打印: 10



使用反射调用类中的私有方法:

例子:

public class PrivateTest {
       public static void main(String[] args) throws Exception{
		
    	   A a  = new A();
    	   
    	   Class<?>  classType = a.getClass();
    	   
    	   Method method = classType.getDeclaredMethod("getHello",String.class);
    	   
    	   method.setAccessible(true);//压制Java的访问权限
    	   
    	   String str  = (String)method.invoke(a,"java");
    	   
    	   System.out.println(str);
	  }
}
class A{
	private String getHello(String str){
		return "你好!"+str;
	}
}
打印:你好!java



如何访问私有属性:

public class Reflection2 {
	public static void main(String[] args) throws Exception{
		Private2 p = new Private2();
		Class<?> cs = p.getClass();
	    Field f = cs.getDeclaredField("name");
		f.setAccessible(true);//压制Java对方问修饰符的检查
		f.set(p,"lisi");
		System.out.println(p.getName());
	}
}
class Private2 {
	private String name ;
	public String getName(){
		return name;
	}
}

打印:lisi


通过子类获得父类的Class对象:


public class Test {
  public static void main(String[] args) {
	   
	  Class<?> classType = Child.class;
	  System.out.println(classType);
	  classType = classType.getSuperclass();
	  System.out.println(classType);
	  classType = classType.getSuperclass();
	  System.out.println(classType);
  }
}

class Child extends Parent{
	
}
class Parent{
	
}

打印:

class Reflection1.Child
class Reflection1.Parent
class java.lang.Object








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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值