作为一只主学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(类名)
}
}
测试:
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() 变量名
}
}
}
反射获取类的所有方法信息:
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()//参数名
*/
}
}
}
反射执行方法:(获得所有属性访问权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();
}
}
}
四、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)
测试:
# 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)#执行函数
五、最近学习Python中遇到的问题:
1、g=getattr(obj,'g',None)获取函数引用,函数g可能有参数(如:g(a,b...)),此时就不能直接调用g()执行函数,解决办法有
#方法中的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!然后继续新的学习