反射01

1.java提供了一套API
2.提供了检查一对对象内部结构的手段

3.反射的用途

1.java的动态执行  API

   a.动态加载类
  b.动态创建对象
  c.动态访问属性
  d.动态调执行方法
2.可以用于实现组件的“解耦”

   -可以实现现在组件和未来组件的耦合关系,调用未来的程序组件

重点掌握方法:

1.Class.forName(类名)

2.Method.invole(obj)

3.Class.newInstancea()

4.setAccessible(true)


利用反射可以实现一段程序与未来一个类之间耦合在一起,
这段程序就是与未来的类之间是松耦合的关系,也就是解除耦合了。
如:Eclipse可以开发任何未来的程序,解析任何未来的程序结构
      Eclipse的快捷菜单用到了哪些技术?
答:Eclipse利用反射技术实现快捷菜单,可以使用Eclipse被开发的类解耦。

动态加载类

 类只加载一次,即便多次调用forName方法

,类也只加载一次,forName返回值是同一个对象的引用

Class cls=Class.forName(String className);
package day01;

import java.util.Scanner;

/*
 * 动态加载类到内存中
 *  Class.forName(
 */
public class ClassForNameDemo02 {

	public static void main(String[] args) throws ClassNotFoundException  {
		Scanner in=new Scanner(System.in);
		System.out.println("输入类名");
		//输入的类名需要输入包名加类名(全限定名),例如:day01.Point (day01包下的Point类)
		String className=in.nextLine();
		//动态加载类
		//当类名错误的时候会抛出类没有找到的异常
		Class cls=Class.forName(className);
Class cls1=Class.forName(classname);
                 Class cls2=Class.forName(classname);
                  System.out.println(cls1==cls2); 
 

} }

  

API方法动态创建对象

  a.Instance实例(对象)

  b.创建cls代表的类型的实例

  c.cls类型上必须包含无参数据构造器(可以是默认构造器)

  d.newInstance就是调用这个无参构造器创建对象

  e.如果没有无参数构造器则抛出异常

package day01;

import java.util.Scanner;

/*
 * 动态加载类到内存中
 *  Class.forName(
 */
public class ClassForNameDemo02 {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException  {
        Scanner in=new Scanner(System.in);
        System.out.println("输入类名");
        //输入的类名需要输入包名加类名(全限定名),例如:day01.Point
        String className=in.nextLine();
        //动态加载类
        //当类名错误的时候会抛出类没有找到的异常
        Class cls=Class.forName(className);
        System.out.println(cls);

/*
* 若输入java.util.ArrayList 输出class java.util.ArrayList []
* ArrayList无元素toString则输出【】
*
*/

//利用反射API动态创建对象
        Object obj=cls.newInstance();
        System.out.println(obj);  //day01.Point@4aa298b7
        //此时Point类没有重写toString,但表示创建成功
        
        
        
    }
}

例如Eclipse中当我们输入对象名.时,下面提示的方法和变量,就是有利用反射原理。

 动态访问属性:

/*
* 在Field类型上定义了get方法,可以用于获取对象的属性值
* ,如果需要获取属性的值:
*
* -利用Class类型对象的方法,才能获取Field类型对象
* -obj.getClass();
* -Class.forName();
* -获取Field类型对象
* -调用get方法
*
*/

package day01;

import java.lang.reflect.Field;
import java.util.Scanner;

public class ClassForNameDemo2 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, 
IllegalAccessException, NoSuchFieldException, SecurityException {
	System.out.println("请输入限定名");
	Scanner scan=new Scanner(System.in);
	//加载类
	String str=scan.nextLine();
	Class cls=Class.forName(str);
	
	System.out.println("请输入属性名");
	
	String fieldName=scan.nextLine();
	/*
	 * 查找类中的属性
	 * getDeclaredFields 带s的则获取全部属性(成员变量),
	 * 不加s的获取的是指定名字的一个属性
	 * 找到就返回属性fid,找不到就抛异常
	 */
	Field fld=cls.getDeclaredField(fieldName);
	System.out.println(fld);
	
	
	//加载对象
	Object obj=cls.newInstance();   //动态获取对象
	//动态访问属性
			/*
			 * 在Field类型上定义了get方法,可以用于获取对象的属性值
			 * ,如果需要获取属性的值:
			 * 
			 * -利用Class类型对象的方法,才能获取Field类型对象
			 *   -obj.getClass();
			 *   -Class.forName();
			 *   -获取Field类型对象
			 *   -调用get方法
			 *   属性名是用户运行期间输入的,输入哪个属性
			 *   名这段程序就会输出哪个属性的值
			 *   也就意味着,程序和属性之间是松耦合关系
			 *   
			 */   
	  Object val=fld.get(obj);//因为输入的属性类型不确定,故用object接收
	  
	  System.out.println(val);//获取obj对象中的FieldName值
	
	
	
	
}
}

访问的属性如果为不可见(私有加跨包)属性(被private修饰的属性),则抛java.lang.IllegalAccessException异常。

解决该问题的方法:调用setAccessible(true)方法(故private修饰的属性外部不能访问不正确,利用反射可以访问私有属性)

注:无论是私有属性还有私有方法,都可以利用反射API进行调用,在调用之前使用fld.setAccessible(true);该方法执行之后可以打开原来私有的访问权限。不仅仅如此,该方法还可以打开任何不可见的属性/方法的访问权限。

package day01;

import java.lang.reflect.Field;
import java.util.Scanner;

public class FieldGetDemo {
public static void main(String[] args) throws ClassNotFoundException,
InstantiationException, IllegalAccessException,
NoSuchFieldException, SecurityException {
	
	System.out.println("输入限定名");
	Scanner scan=new Scanner(System.in);
	String forName=scan.nextLine();
	System.out.println("请输入属性名");
	String fieldName=scan.nextLine();
	
	Class cls=Class.forName(forName);
	Object obj=cls.newInstance();//动态创建对象
	
	Field fl=cls.getDeclaredField(fieldName);//动态访问属性
	fl.setAccessible(true);
	//如果访问的是私有属性在获取对象值之前用该对象调用setAccessible方法,传入的
	//参数为true,则可以访问私有属性
	Object val=fl.get(obj);
	System.out.println(fl);
	System.out.println(val);
	
	scan.close();
	
}
}

  

利用反射访问对象的方法
访问方法的核心API

使用步骤
1.获取Class对象,才能利用其方法找到Method对象
-Class.forName(类名)
2.Method getDeclaredMethod(方法名)根据方法名找到Method对象
-Method
3.得到包含方法的对象obj
-cls.newInstances()
4.准备参数(调取的方法有参数)
method.invoke(obj)该方法的返回值为该方法的返回值,如果方法没有返回值,则返回值为null

 package day01import java.lang.reflect.Method;

import java.util.Scanner;

/**
 * 利用反射API动态的执行对象的方法
 * @author TEDU
 *
 */
public class InvokeMethodDemo {
public static void main(String[] args) 
	throws Exception{
		/*
		 *利用反射API动态执行对象的方法 
		 */
		Scanner scan=new Scanner(System.in);
		System.out.print("输入类型:");
		String className=scan.nextLine();
		System.out.println("请输入方法名:");
	    String methodName=scan.nextLine();
	//动态加载类
	Class cls=Class.forName(className);
	
	//在类cls中找到需要执行的methodName方法
	//如果方法名错误,将抛出没有找到的方法异常
	Method method=cls.getDeclaredMethod(methodName);
	System.out.println("method:"+method);
	//动态创建对象
	Object obj=cls.newInstance();
	//执行invoke时, obj对象一定包含制定的mothod的对象,否则将抛出异常
	Object value=method.invoke(obj);//输出的是方法的返回值
	System.out.println("value:"+value);

//public int day01.Point.run()输出的是全限定名 } }

  

cls.getDeclaredMethod在当前cls类型上查找当前类中声明的方法
-getDeclaredMethod只查询当前类中的方法
cls.getMethod 在当前cls类型以及全部继承的方法中查找声明的共有方法
-查询当前类和父类中的继承的方法

原文地址:https://www.cnblogs.com/chenzhiwei/p/9517015.html