java反射&python反射

作为一只主学java,次学python的猿,反射的梗,怎能不知道

一、反射是什么:

维基百科上给出的定义:在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。

以我浅薄的编程思想理解的反射:

  • 反射可以让我们在不打开程序文件的情况下,清楚的知道该程序的内部结构

  • 通过反射,我们可以在运行时获得程序或程序集中每一个类型成员和成员变量的信息

有种说法,Java并不是动态语言,但它却有一个非常突出的动态相关的机制,即:反射

二、反射的用途:

反射主要用于开发各种通用框架(比如Spring),通过 XML文件配置 JavaBean,Action。为了保证框架的通用性,他们可能根据配置文件加载不同的对象或类,调用不同的方法,这些都必需使用反射来实现。

举个例子:在不使用框架开发web应用中,连接数据库时需要使用反射加载数据库驱动

//反射加载mysql数据库驱动
Class.forName("com.mysql.jdbc.Driver");

三、Java中的反射

对于一个未知类,在编译时不需要知道任何事情,在运行时将确定所有的类信息

我们需要用到一个类时,可以使用import *;导入类,也可以使用反射(类完整路径.class或Class.forName(类完整路径))

列:类Run中加载类User

User.java

package com.reflect.pojo;
public class User {
}

Run.java:正常加载 import com.reflect.pojo.User;

package com.reflect.test;

import com.reflect.pojo.User;//导入User类
public class Run {
	User user=new User();
}

Run.java:反射加载 

package com.reflect.test;

public class Run {
	public static void main(String[] args) throws ClassNotFoundException {
		Class clazz0=com.reflect.pojo.User.class;//第一种反射方法:类名.class
		Class clazz1=Class.forName("com.reflect.pojo.User");//第二种反射方法:Class.forName(类名)
	}
}
  • Class类与java.lang.reflect类库一起对反射的概念进行了支持,该类库包括Field、Method以及Constructor类,这些类型的对象是由JVM运行时创建的,用来表示未知类中里对应的成员
  • 使用Constructor创建新的对象,用get()和set()方法读取和修改与Field对象相关联的字段
  • 使用invoke()方法调用与Method对象相关联的方法
  • 另外,可以调用getFields(),getMethods()和getConstructors()等很便利的方法,以返回表示字段,方法以及构造器的对象的数组

测试:

User.java

package com.reflect.pojo;
public class User {
	private String name;
	public String address;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
}

反射获取变量信息:

package com.reflect.test;

import java.lang.reflect.Field;
public class Run {
	Class clazz=com.reflect.pojo.User.class;//类名.class
	public static void main(String[] args) {
		new Run().run();
	}
	public void run() {
		//1、获得类的名称
		System.out.println("类的名称:" + clazz.getName());
		//2 获取所有 public 访问权限的变量,包括本类声明的和从父类继承的
		Field[] fields = clazz.getFields();
		print(fields,"所有public变量:");
		//3获取所有本类声明的变量
	    fields = clazz.getDeclaredFields();
	    print(fields,"所有变量:");
	   
	}
	public void print(Field[] fields,String msg) {
		System.out.println(msg);
		for(Field field:fields) {
			System.out.println("\t"+field);//变量访问权限与变量的类型以及变量名
			//field.getType().getName() 变量的类型
			//field.getName() 变量名
		}
	}
}

java反射&python反射_第1张图片

反射获取类的所有方法信息:

package com.reflect.test;

import java.lang.reflect.Method;
public class Run {
	Class clazz=com.reflect.pojo.User.class;//类名.class
	public static void main(String[] args) {
		new Run().run();
	}
	public void run() {
		//1 获取所有 public 访问权限的方法,包括自己声明和从父类继承的
	    Method[] methods = clazz.getMethods();
	    print(methods,"所有的public方法:");
	    //2获取所有本类的的方法(不问访问权限)
	    methods = clazz.getDeclaredMethods();
	    print(methods,"所有的方法:");
	}
	public void print(Method[] methods,String msg) {
		System.out.println(msg);
		for(Method method:methods) {
			System.out.println("\t"+method);//变量访问权限与变量的类型以及变量名
			//method.getReturnType().getName() 方法的类型
			//method.getName() 方法名
			/*
			 * Parameter[] parameters = method.getParameters();//参数集合
			 * parameters[0].getType().getName();//参数类型
			 * parameters[0].getName()//参数名
			 */
		}
	}
}

java反射&python反射_第2张图片

反射执行方法:(获得所有属性访问权setAccessible(true);)

	public void pubMethod(int i,String s) {
		System.out.println("pubMethod()执行 s="+s+"、i="+i);
	}
	private void priMethod(int i,String s) {
		System.out.println("priMethod()执行 s="+s+"、i="+i);
	}
package com.reflect.test;

import java.lang.reflect.Method;
public class Run {
	Class clazz=com.reflect.pojo.User.class;//类名.class
	public static void main(String[] args) {
		new Run().run();
	}
	public void run(){
		//1执行public方法
		try {
			//获取方法
			Method pubM= clazz.getMethod("pubMethod",int.class,String.class);
			//使用 invoke 反射调用方法
			pubM.invoke(clazz.newInstance(),10,"public");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	    //2执行私有方法
		try {
			//获取私有方法
			Method priM= clazz.getDeclaredMethod("priMethod",int.class,String.class);
			//获取私有方法的访问权
			priM.setAccessible(true);
			//使用 invoke 反射调用私有方法
			priM.invoke(clazz.newInstance(),20,"private");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}

java反射&python反射_第3张图片

四、Python中的反射

我们需要一个模块,可以使用import *这种方式导入。现在需求是:我们动态输入一个模块名,实现随时访问到导入模块中的方法与变量

列:模块B获得模块A中的变量值的方法

A.py

# model:A.py
i=10
j=12

B.py :第一种 import A as a

# model:B.py
import A as a
print(a.i)
print(a.j)

B.py:第二种 反射__import__("A")

# model:B.py
str='A'
a=__import__(str)
print(a.i)
print(a.j)
  • 在Python使用反射就很简单了,不需要import任何库,直接就可以使用
  • __import__():将字符串转换成可以调用模块、模块方法的变量
  • hasattr(obj, name, /):检测obj里面是否包含了name属性(函数、方法……),hasattr()返回True或者False。
  • getattr(object, name[, default]):用来调用object.name
  • setattr(obj, name, value, /):设置一个obj.name = value
  • delattr(obj, name, /):删除obj.name

测试:

# model:A.py
i=12
j=13
def f():
	print('f()已执行')
def g(a,b):
	print('a+b=%d'%(int(a)+int(b)))
# model:B.py
str='A'
obj=__import__(str)
if hasattr(obj,'i'):#判断是否存在属性i
	print('getattr->i:%d'%(getattr(obj,'i',None)))#打印属性值
	setattr(obj,'i',21)#修改属性值
	print('修改i后getattr->i:%d'%(getattr(obj,'i',None)))#打印属性值
	delattr(obj,'i')#删除属性
	print('删除i后hasattr->i:%s'%(hasattr(obj,'i')))#判断是否存在属性i
#无参方法f()
if hasattr(obj,'f'):#判断是否存在函数f
	f=getattr(obj,'f',None)#获取函数引用
	f()#执行函数
#有参方法g(a,b)
if hasattr(obj,'g'):#判断是否存在函数g
	g=getattr(obj,'g',None)#获取函数引用
	parameter_count=g.__code__.co_argcount#获得参数个数
	parameter_name_list=g.__code__.co_varnames#获得所有变量的名字,包括方法内变量
	parameter_list=[]
	for i in range(parameter_count):
		parameter_list.append(input("方法需要参数%d个,参数%s:"%(parameter_count,parameter_name_list[i])))
	g(*parameter_list)#执行函数

java反射&python反射_第4张图片

五、最近学习Python中遇到的问题:

1、g=getattr(obj,'g',None)获取函数引用,函数g可能有参数(如:g(a,b...)),此时就不能直接调用g()执行函数,解决办法有

  • 如果知道参数个数,可直接调用g(a,b)(a,b该为对应的值即可)
  • 如果并不知道参数的个数,需要先获得参数的个数,然后循环输入对应的值,获取参数的个数要用到一个非常冷门的知识点
#方法中的self也会被记数,如g(self,a,b)有三个参数
parameter_count=g.__code__.co_argcount#获得参数个数

2、即便我们知道了参数的个数,但不知道参数应输入什么,解决办法是一般参数名即代表要输入的参数的类型,可以获得所有参数的名字,也是一个非常冷门的知识点:

#列:g(a,b):
#        c=1
#        d=2
#获取该方法的变量名会返回[a,b,c,d]
parameter_name_list=g.__code__.co_varnames#获得所有变量的名字,包括方法内变量

3、执行有参函数,添加参数可以使用*list:

def g(a,b,c):
	print(a+b+c)
list=[1,2,3]
g(*list)

最近学得太乱了,好多都是小细节,设计模式的单一职责可能是要告诉我们一篇博客应该只解释一种知识,但是我懒啊,我比较喜欢累计问题,统一记录。然后麻烦就来了,不说一些问题累计着累计着就不在了,就之后记录问题的排版,问题太多不知道该从哪一个开始,焦灼中慢慢就放弃了,忍不住爆一句:cao!然后继续新的学习

你可能感兴趣的:(编程技术)