JAVA反射

  1. 前言
    1. 一开始是不知道反射的,然后找了很多资料,看了一些视屏,基本上第一句话是,反射都是在运行状态才知道是什么对象/类,然后可以获取对象/类的构造方法,属性,等等....说的,感觉这东西什么都能拿到似的,很厉害,但在编译期却感觉什么都拿不到似的,连我作为一个开发者都不知道运行了哪个对象。所以搞得我特别混乱,什么是我看的见摸不着,但这东西却会时刻发出音响。搞了很久,差点就放弃了,后来看了一个视屏,跟着写了下,觉得理解了一点。ps:在1997年2月的时候,发布jdk1.1提出了内部类,反射,jar文件格式。搞得我现在还在学习以前人的思想!!

  2. 什么是反射?
    1. 什么是反射?这东西我前面都提到了吧,来,按照专业术语我跟你讲讲:
      1. 对于任意一个对象,都能够调用它的任意一个方法和属性
      2. 对于任意一个类,都能够知道这个类的所有属性方法
      3. 反射机制是在运行状态中
    2. 说了这么多,很神奇,反正我到现在都还是有点懵懵懂懂的,现在咱们把这个理念来抛弃,往下走。
  3. 反射能干啥
    1. 很多人都说,反射是一个非常重要的知识点,不懂,你以后什么都做不了,什么动态代理,什么增删改查,等等,你还真都做不了。听到这,我感觉十分的恐慌,心想:这么叼!不行,我得要去学学,不然工作咋搞。然后找啊找,找啊找,咦,发现了一些专业术语。来,咱们看看:
      1. 生成动态代理
      2. 在运行时调用任意一个对象的方法
      3. 在运行时判断任意一个类所具有的成员变量和方法
      4. 在运行时构造任意一个类的对象
      5. 在运行时判断任意一个对象所属的类
      6. 哇!这么多专业术语!把我搞得很慌啊,但是仔细一看可以总结成一句话:在运行时期我们可以对任意属性或者类进行操作。好!我很是不信,就开始我的掉头发之旅了(敲代码)
  4. 代码模块
    1. 首先,在我们写反射的代码之前,我们得要先写一个入口吧!不然,你连这个门都进不了。但很奇怪的是,不像我们之前new对象,然后调用方法。反射是直接获取Class对象,然后进行操作,这是为什么呢?来,我们往下看:
      package com.qsk.myInterface;
      
      public interface MyInterface {
      
      	void interfaceMethod();
      }
      
      //接口2
      package com.qsk.myInterface;
      
      public interface MyInterface2 {
      	void interfaceMethod2();
      }
      1. 创建两个接口
      2. //接口1
        package com.qsk.myInterface;
        
        public interface MyInterface {
        
        	void interfaceMethod();
        }
        
        //接口2
        package com.qsk.myInterface;
        
        public interface MyInterface2 {
        	void interfaceMethod2();
        }

         

      3. 创建两个类
      4. package com.qsk.entity;
        
        import com.qsk.myInterface.MyInterface;
        import com.qsk.myInterface.MyInterface2;
        
        public class Person implements MyInterface,MyInterface2 {
        
        	private int id;
        	private String name;
        	private int age;
        	public String message;
        
        	public int getId() {
        		return id;
        	}
        
        	public void setId(int id) {
        		this.id = id;
        	}
        
        	public String getName() {
        		return name;
        	}
        
        	public void setName(String name) {
        		this.name = name;
        	}
        
        	public int getAge() {
        		return age;
        	}
        
        	public void setAge(int age) {
        		this.age = age;
        	}
        
        	public Person(int id, String name, int age) {
        		this.id = id;
        		this.name = name;
        		this.age = age;
        	}
        
        	private Person(String name) {
        		super();
        		this.name = name;
        	}
        
        	public Person(int id) {
        		this.id = id;
        	}
        
        	public Person() {
        
        	}
        	
        	private void privateMethod(){
        		System.out.println("私有");
        	}
        	
        	private void privateTry(int id,String name){
        		System.out.println(id+"====="+name);
        	}
        
        	public static void statiMehod() {
        		System.out.println("Static  Method 。。。。");
        	}
        
        	public void interfaceMethod() {
        		// TODO Auto-generated method stub
        		System.out.println("Interface1  Method。。。。");
        	}
        
        	public void interfaceMethod2() {
        		// TODO Auto-generated method stub
        		System.out.println("Interface2  Method。。。。");
        	}
        
        }
        package com.qsk.entity;
        
        import com.qsk.myInterface.MyInterface;
        import com.qsk.myInterface.MyInterface2;
        
        public class Person implements MyInterface,MyInterface2 {
        
        	private int id;
        	private String name;
        	private int age;
        	public String message;
        
        	public int getId() {
        		return id;
        	}
        
        	public void setId(int id) {
        		this.id = id;
        	}
        
        	public String getName() {
        		return name;
        	}
        
        	public void setName(String name) {
        		this.name = name;
        	}
        
        	public int getAge() {
        		return age;
        	}
        
        	public void setAge(int age) {
        		this.age = age;
        	}
        
        	public Person(int id, String name, int age) {
        		this.id = id;
        		this.name = name;
        		this.age = age;
        	}
        
        	private Person(String name) {
        		super();
        		this.name = name;
        	}
        
        	public Person(int id) {
        		this.id = id;
        	}
        
        	public Person() {
        
        	}
        	
        	private void privateMethod(){
        		System.out.println("私有");
        	}
        	
        	private void privateTry(int id,String name){
        		System.out.println(id+"====="+name);
        	}
        
        	public static void statiMehod() {
        		System.out.println("Static  Method 。。。。");
        	}
        
        	public void interfaceMethod() {
        		// TODO Auto-generated method stub
        		System.out.println("Interface1  Method。。。。");
        	}
        
        	public void interfaceMethod2() {
        		// TODO Auto-generated method stub
        		System.out.println("Interface2  Method。。。。");
        	}
        
        }

         

      5. 好!现在咱们开始操作了,上面说了,咱们得要Class对象,不然连反射的门都进不了,然而得到一个类/属性的Class对象有3种方式,来让我们看看有哪三种吧!
      6. // 获取反射对象(反射入口):Class
        	public static void getReClass() {
        		// 1. Class.forName(全类名‘包名加类名’)
        		try {
        			Class<?> perClass1 = Class.forName("com.qsk.entity.Person");
        			System.out.println(perClass1);
        		} catch (ClassNotFoundException e) {
        			// TODO Auto-generated catch block
        			e.printStackTrace();
        		}
        
        		// 2. 类名.class
        		Class<?> perClass2 = Person.class;
        		System.out.println(perClass2);
        
        		// 3.对象.getClass()
        		Person person = new Person();
        		Class<?> perClass3 = person.getClass();
        		System.out.println(perClass3);
        	}

         

      7. 实验一下,看这三个获取的是什么吧!
      8. 哈!不出我所料,全部都是一样的,但有的人会说,第二个和第三个都知道,但第一个为什么要包名加类名呢?对于这个问题,咱们可以看看控制台输出的内容。全部都是包名加类名!所以第一个是要完整类名去查找Class,有的话就输出,没有就异常,所以有一个try/catch。
      9. 好!知道了Class怎么获取就好办了,咱们可以根据这个Class获取方法属性等等,接下来试试先
        1. ·获取方法
        2. // 获取方法
          	public static void getReMethod() {
          		// Class入口
          		Class<?> perClass = null;
          		try {
          			perClass = Class.forName("com.qsk.entity.Person");
          		} catch (ClassNotFoundException e) {
          			// TODO Auto-generated catch block
          			e.printStackTrace();
          		}
          		// 获取所有的公共的方法
          		// 1.本类 以及 父类、接口中的所有方法
          		// 2.符合访问修饰符规律
          		Method[] methods = perClass.getMethods();
          		for (Method method : methods) {
          			System.out.println(method);
          		}
          
          		System.out.println("===================");
          		// 获取当前类的所有方法
          		// 1.只能是当前类
          		// 2.忽略访问修饰符限制
          		Method[] declaredMethods = perClass.getDeclaredMethods();
          		for (Method method : declaredMethods) {
          			System.out.println(method);
          		}
          	}

        3. 获取所有接口
        4. // 获取所有接口
          	public static void getInterface() {
          		// Class入口
          		Class<?> perClass = null;
          		try {
          			perClass = Class.forName("com.qsk.entity.Person");
          		} catch (ClassNotFoundException e) {
          			// TODO Auto-generated catch block
          			e.printStackTrace();
          		}
          
          		Class<?>[] interfaceClasses = perClass.getInterfaces();
          		for (Class<?> class1 : interfaceClasses) {
          			System.out.println(class1);
          		}
          	}

           

        5. 获取所有的父类
        6. // 获取所有的父类
          	public static void getSuperClass() {
          		// Class入口
          		Class<?> perClass = null;
          		try {
          			perClass = Class.forName("com.qsk.entity.Person");
          		} catch (ClassNotFoundException e) {
          			// TODO Auto-generated catch block
          			e.printStackTrace();
          		}
          		Class<?> superClass = perClass.getSuperclass();
          		System.out.println(superClass);
          	}

           

        7. 获取所有的构造方法
        8. // 获取所有的构造方法
          	public static void getConstructer() {
          		// Class入口
          		Class<?> perClass = null;
          		try {
          			perClass = Class.forName("com.qsk.entity.Person");
          		} catch (ClassNotFoundException e) {
          			// TODO Auto-generated catch block
          			e.printStackTrace();
          		}
          		Constructor<?>[] constructers = perClass.getConstructors();
          		for (Constructor<?> constructor : constructers) {
          			System.out.println(constructor);
          		}
          
          	}

           

        9. 获取属性
        10. // 获取属性
          	public static void getAllField() {
          		// Class入口
          		Class<?> perClass = null;
          		try {
          			perClass = Class.forName("com.qsk.entity.Person");
          		} catch (ClassNotFoundException e) {
          			// TODO Auto-generated catch block
          			e.printStackTrace();
          		}
          		// 获取所有公共的属性
          		Field[] fields = perClass.getFields();
          		for (Field field : fields) {
          			System.out.println(field);
          		}
          
          		System.out.println("===================");
          
          		// 获取所有属性
          		// 1.只能是当前类
          		// 2.忽略访问修饰符限制
          		Field[] declaredFields = perClass.getDeclaredFields();
          		for (Field field : declaredFields) {
          			System.out.println(field);
          		}
          	}

           

        11. 获取当前反射所代表类(接口)的对象(实例)
        12. // 获取当前反射所代表类(接口)的对象(实例)
          	public static void getInstance() throws InstantiationException,
          			IllegalAccessException {
          		// Class入口
          		Class<?> perClass = null;
          		try {
          			perClass = Class.forName("com.qsk.entity.Person");
          		} catch (ClassNotFoundException e) {
          			// TODO Auto-generated catch block
          			e.printStackTrace();
          		}
          		Object perInstance = perClass.newInstance();
          		Person per = (Person) perInstance;
          		per.interfaceMethod();
          	}
        13. 呼~敲了这么多,感觉有点小累,但是想了想,拿起键盘开始总结:
          1. 我们可以看到获取一个类的所有方法/属性,和当前类的所有方法/属性是不同的,而不同点在:Declared(公告的,公然的,宣布) 这个单词上。在没加这个单词之前,我们可以获取所有的 public 方法/属性,甚至最大的类 Object 中的东西全给你搞过来了。但是加了 Declared 之后,我们只能获取本类的方法/属性,但直接忽略了访问修饰符的限制,连 private 的方法/属性都给你打印出来了。所以,如果我们需要本类的所有方法/属性的话,咱们就加上 Declared ,否则就不加。
          2. 像获取所有构造方法、父类、接口,我就不一 一详解了,否则得要敲死我,大同小异,主要来看看:newInstance(),这个东西我们后面主要用的是这个,这个和new不太同,在使用newInstance()方法的时候,必须保证这个类已经加载并且已经连接了。而且,new关键字能调用任何构造方法,newInstance()只能调用无参构造方法。最重要的是:如果我王者荣耀是王者段位,我要:ShenZhuanZi szz = new WangZhe(),但是呢,过了这个赛季,我就变成钻石了,我又要:ShenZhuanZi szz = new ZuanShi(),这样不贼麻烦,到时候我又上了个星耀又要改,不贼麻烦。但如果我搞了一个传子工厂的话,也就是工厂模式,我上王者,我就是王者,如果我掉到钻石了,我就是钻石了,不用去改,只需要改下我段位就行了:ShenZhuanZi szz = (wangZhe) szzClass.newInstance() ,这样,我就可以在不改变代码的情况下,换成另一个段位,到时候把东西放到配置文件里,再配合依赖注入的方法,就提高了软件的可伸缩性、可扩展性。
        14. 好!说了这么多东西,咱们就可以开始简单的操作一个类了!比如
          1. 操作类的属性
          2. // 操作属性
            	public static void demo02() throws InstantiationException,
            			IllegalAccessException, SecurityException, NoSuchFieldException,
            			NoSuchMethodException, IllegalArgumentException,
            			InvocationTargetException {
            		Class<?> perClass = null;
            		try {
            			perClass = Class.forName("com.qsk.entity.Person");
            		} catch (ClassNotFoundException e) {
            			// TODO Auto-generated catch block
            			e.printStackTrace();
            		}
            		Person per = (Person) perClass.newInstance();
            		Field idField = perClass.getDeclaredField("id");
            		// 访问的是private修饰的id,但是private是私有的
            		// 修改属性访问权限
            		// 使用反射时,如果因为访问修饰符限制造成异常,可以通过
            		// Field/Method/Constructor.setAccessible(true);打开权限
            		idField.setAccessible(true);
            		// 对象+设置的值
            		idField.set(per, 1);
            		System.out.println(per.getId());
            
            		System.out.println("=====================");
            
            		// 方法名,方法参数
            		Method declaredMethod = perClass.getDeclaredMethod("privateMethod",
            				null);
            		declaredMethod.setAccessible(true);
            		// 方法的调用:invoke()
            		// 对象+参数
            		declaredMethod.invoke(per, null);
            
            		Method declaredMethod2 = perClass.getDeclaredMethod("privateTry",
            				int.class, String.class);
            		declaredMethod2.setAccessible(true);
            		declaredMethod2.invoke(per, 2, "我我我");
            	}

             

          3. 这里咱们可以看到两个新的东西,一个是Accessible,一个是invoke。首先可以谈谈
            • Accessible 是个什么东西,这是一个类似打开权限的玩意,前面我们也说了,我们可以通过 Declared 来获取本类所有的 private 的方法/属性,但是私处给你看了(手动脸红)你就别动我了,但是,作为一个广大男性,咱们说过蹭蹭不进去,哪几个办的到的!这时候,为了为所欲为,咱们就可以Accessible(易接近,易相处)来打开你的心扉,设置为true(给点好处),然后我们就可以对私有的地方(属性/方法)为所欲为了。
            • invoke 没有 Accessible那么屌,invoke就相当于 set一样,第一个为类型,后面都是传过去的参数。
          4. 好,接下来我们可以写一个简单的txt文件,从里面进行反射,然后获取对象/方法
          5. classname=com.qsk.entity.Person
            methodname=interfaceMethod
          6. // 动态加载类名和方法
            	public static void demo04() throws FileNotFoundException, IOException,
            			SecurityException, NoSuchMethodException, IllegalArgumentException,
            			IllegalAccessException, InvocationTargetException,
            			InstantiationException {
            
            		Properties prop = new Properties();
            		prop.load(new FileReader("class.txt"));
            		String classname = prop.getProperty("classname");
            		String methodname = prop.getProperty("methodname");
            
            		Class<?> perClass = null;
            		try {
            			perClass = Class.forName(classname);
            		} catch (ClassNotFoundException e) {
            			// TODO Auto-generated catch block
            			e.printStackTrace();
            		}
            
            		Method method = perClass.getMethod(methodname);
            		method.invoke(perClass.newInstance());
            	}

             

          7. 来看看运行结果:
          8. 如果我们在txt中改成其他的呢,比如一开始写的 Studen,会怎么样呢
          9. classname=com.qsk.entity.Student
            methodname=sayHi

          10. 看,现在变成了这个了,我根本没有在代码里面改任何东西,就输出成了这样,所以,我们在编译的时候,我们完全不知道我们要给什么实现类,我们只有在运行的时候,看到了输出的东西,或者其他,我们才知道,哦!我们调用了这个类
          11. 接下来,再看一个例子
          12. public static void demo05() throws SecurityException,
            			NoSuchMethodException, IllegalArgumentException,
            			IllegalAccessException, InvocationTargetException,
            			InstantiationException {
            		ArrayList<Integer> list = new ArrayList<Integer>();
            		list.add(1);
            		Class<?> listClass = list.getClass();
            		Method method = listClass.getMethod("add", Object.class);
            		method.invoke(list, "张三...");
            		System.out.println(list);
            	}
            输出:

             

          13. 输出:
          14. 这里我们发现了反射可以越过泛型检查,管你之前是什么类型,在我这都可以插进去。虽然可以通过反射访问private等访问修饰符不允许访问的属性/方法,也可以忽略泛型的约束;但实际开发不建议这样使用,因此可能造成程序的混乱。就比如,某某是女的,我硬是把你当男的,要跟你睡,那别人不得报警啊
          15. 最后,我们可以通过反射写一个工具类,就是不管你是什么字段,给我类型,字段名,和插入的值,我就可以给你进行赋值
          16. package com.qsk.util;
            
            import java.lang.reflect.Field;
            
            public class PropertyUtil {
            	
            	//per.setXxx(value)
            	public static void setProperty(Object obj, String propertyName, Object value) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
            		Class<?> class1 = obj.getClass();
            		Field filed = class1.getDeclaredField(propertyName);
            		filed.setAccessible(true);
            		filed.set(obj, value);
            	}
            }

             

          17. 测试
          18. public static void demo06() throws SecurityException,
            			IllegalArgumentException, NoSuchFieldException,
            			IllegalAccessException {
            		Person per = new Person();
            		PropertyUtil.setProperty(per, "name", "zs");
            		PropertyUtil.setProperty(per, "age", 23);
            
            		Student stu = new Student();
            		PropertyUtil.setProperty(stu, "score", 10);
            		System.out.println(per.getName());
            		System.out.println(stu.getScore());
            	}
          19. 结果
          20. 看,我们成功的进行赋值操作,还可以读出来。
  5. 总结
    1. 其实我看了好多文章,我自己总结一下:写了这么多,我相信看了这个的,就可以自己总结了,反正我是总结不出来的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值