注:主要记录自教学视频《兄弟连_马剑威_JAVA基础》的反射章节
类的生命周期:
第一:通过javac 将java源文件生成 .class文件
第二步:java命令
分为三个阶段:装载、链接、初始化
反射:Reflection
类信息 --> 对象
对象 --> 类信息
2、Class类--类信息
Class类是一切的反射根源
类名、属性、构造方法、方法
得到Class类的对象有三种方式:
1、Object类的getClass() 方法
2、类.class
3、通过Class类的forname方法,放入类的全路径
package zhan;
public class Person {
private int age;
private char sex;
private String name;
public Person(int age, char sex, String name) {
super();
this.age = age;
this.sex = sex;
this.name = name;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Person [age=" + age + ", sex=" + sex + ", name=" + name + "]";
}
public int getAge() {
return age;
}
public char getSex() {
return sex;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public void setSex(char sex) {
this.sex = sex;
}
public void setName(String name) {
this.name = name;
}
private void say(){
System.out.println("my name is "+name);
}
}
package zhan;
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Person p1=new Person(18, '男', "小白");
Person p2=new Person(19, '女', "小黑");
//一个Class对象代表着一份字节码,相同类型的对象得到的字节码对象是同一个
//创建Class 对象的方式一:
System.out.println("创建Class对象的方式一:");
Class personClass1 = p1.getClass();
Class personClass2=p2.getClass();
System.out.println(personClass1==personClass2);
System.out.println("创建Class对象的方式二:");
Class personClass3= Person.class;
System.out.println(personClass1==personClass3);
System.out.println("创建Class对象的方式三:");
Class personClass4 =Class.forName("zhan.Person");//此处为类完整限定名称
System.out.println(personClass1==personClass4);
System.out.println(" personClass1:"+personClass1.toString()+" , personClass4:"+personClass4.toString());
}
}
结果为:
创建Class对象的方式一:
true
创建Class对象的方式二:
true
创建Class对象的方式三:
true
personClass1:class zhan.Person , personClass4:class zhan.Person
类的加载过程:
首先将Person类所对应的class文件通过类加载器 ClassLoader加载到内存当中,
注意,这个类只会加载一次;在内存中存这个类的字节码只会存一份,以class类型存在
当后面实例化过个类对象时,都是对同一份class 的引用
2、Class类
使用Class类进行对象的实例化操作
调用无参构造进行实例化:
public T newInstance() throws InstantiationException,IllegalAccessException
调用有参构造进行实例化
public Constructor<?>[] getConstructors() throws SecurityException
//--------通过类信息实例化对象-----------------
System.out.println("----通过类信息实例化对象----");
System.out.println("--调用无参构造方法:");
//调用无参构造方法
try {
//调用此方法时要注意,如果类中没有无参构造方法,将会报异常 InstantiationException
Person p3= (Person) personClass4.newInstance();
System.out.println(p3);
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace(); =
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//调用有参构造方法
System.out.println("--调用有参构造方法:");
Constructor[] cs=personClass4.getConstructors();//返回构造方法对象,当前类的所有构造方法
for (Constructor constructor : cs) {
System.out.println(constructor.toString());
System.out.println(constructor.getName());
}
输出结果:
----通过类信息实例化对象----
--调用无参构造方法:
Person [age=0, sex=, name=null]
--调用有参构造方法:
public zhan.Person(int,char,java.lang.String)
zhan.Person
public zhan.Person()
zhan.Person
System.out.println("--获取指定参数类型的构造方法:");
try {
Constructor c1=personClass4.getConstructor(int.class,char.class,String.class);
Person p4=(Person) c1.newInstance(17,'女',"小花");
System.out.println(p4);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
输出:
--获取指定参数类型的构造方法:
Person [age=17, sex=女, name=小花]
3、通过Class类取得类信息
- 取得类所在包
- 取得一个类的方法
- 取得一个类中的全部属性
getMethods() 方法不能得到私有的方法
getDeclaredMethods() 方法可以获得
System.out.println("----通过类信息----");
System.out.println("--包信息:" + personClass4.getPackage().getName());
System.out.println("--类信息:" + personClass1.getName());
Method[] methods = personClass4.getMethods();//只能获取public 的方法,包括超类及超接口继承中的公共方法
for (Method method : methods) {
System.out.println("方法:"+method.getName());
}
//返回method对象的一个数组,这些对象反映此class
//对象表示的类或接口声明的所有方法
//包括公共、保护、默认和私有方法,但不包括继承的方法
Method[] methods2 =personClass4.getDeclaredMethods();
for (Method method : methods2) {
System.out.println("declared 方法: "+Modifier.toString(method.getModifiers())+" "+method.getName());
}
输出:
----通过类信息----
--包信息:zhan
--类信息:zhan.Person
方法:toString
方法:getName
方法:setName
方法:setAge
方法:getSex
方法:getAge
方法:setSex
方法:wait
方法:wait
方法:wait
方法:equals
方法:hashCode
方法:getClass
方法:notify
方法:notifyAll
declared 方法: public toString
declared 方法: public getName
declared 方法: public setName
declared 方法: public setAge
declared 方法: public getSex
declared 方法: public getAge
declared 方法: public setSex
declared 方法: private say
通过 getFields() 和 getDeclaredFields() 获取类的属性
System.out.println("--获取公有属性信息");
Field[] fields=personClass4.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
System.out.println("--获取私有属性信息");
Field[] fields2=personClass4.getDeclaredFields();
for (Field field : fields2) {
System.out.println(Modifier.toString(field.getModifiers())+" "+field.getName());
}
输出:
--获取公有属性信息
--获取私有属性信息
private age
private sex
private name
-----Field 补充,Field.get()方法
public Object get(Object obj) ,API解释
返回指定对象的特定属性field的值
- 如果该属性是静态(static)的,则 obj参数被忽略
- 否则,obj 是实例属性
public class LocationInfo {
private int lon=100;
static int lonstatic=101;
public void setLon(int lon) {
this.lon = lon;
}
public static void setLonstatic(int lonstatic) {
LocationInfo.lonstatic = lonstatic;
}
}
public class Main {
public static void main(String[] args) {
try {
Field field = LocationInfo.class.getDeclaredField("lon");
field.setAccessible(true);
LocationInfo locInfo1 = new LocationInfo();
locInfo1.setLon(111);
LocationInfo locInfo2 = new LocationInfo();
locInfo2.setLon(222);
int x1 = (Integer) field.get(locInfo1); System.out.println(x1);
int x2 = (Integer) field.get(locInfo2); System.out.println(x2);
Field fieldstatic = LocationInfo.class.getDeclaredField("lonstatic");
int y1 = (int) fieldstatic.get(locInfo1); System.out.println(y1);
int y = (int) fieldstatic.get(new User()); System.out.println(y);
int z = (int) fieldstatic.get(""); System.out.println(z);
int w = (int) fieldstatic.get(null); System.out.println(w);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
输出:
111
222
101
101
101
101
可以看到对于静态 static 修饰的属性,不管 obj 传入什么类型,输出都是一样的
4、通过Class类调用属性或方法
1、调用类中的方法
- 调用类中的方法,传入实例化对象,以及具体的参数内容
- public Object invoke(Object obj,Object ... args)
2、直接调用属性
- 取得属性
- public Object get(Object obj)
- //设置属性 ,等同于使用“=”完成操作
- public void set(Object obj,Object value)
- //让属性对外部可见
- public void setAccessible(boolean flag)
eg:
System.out.println("-------------调用方法和属性---------------");
Person p5= new Person();
try {
Method setNameMethod=personClass4.getMethod("setName", String.class);
//调用方法
setNameMethod.invoke(p5, "小花");//相当于 p5.setName("小花");
System.out.println(p5);
//访问私有方法
Method sayMethod = personClass4.getDeclaredMethod("say");
sayMethod.setAccessible(true);//忽略检查访问修饰符
sayMethod.invoke(p5);
//调用属性
Field ageField =personClass4.getDeclaredField("age");
ageField.setAccessible(true);//忽略检查访问修饰符
ageField.set(p5, 5);//或者 ageField.setInt(p5, 5); 给P5的age属性赋值为5
System.out.println(p5);
System.out.println("age = "+ageField.get(p5));//获取p5的age属性
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
输出:
-------------调用方法和属性---------------
Person [age=0, sex= , name=小花]
my name is 小花
Person [age=5, sex= , name=小花]
age = 5
5、动态代理
- 所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联
- java 动态代理主要是使用 java.lang.reflect 包中的两个类。
- public Object invoke(Object obj,Method method,Object[] obs) --invoke:调用
- 其中第一个参数 obj 指的是代理类,method是被代理的方法,obs 是指被代理的方法的参数组,此方法由代理类来实现。
- protected Proxy(InvocationHandler h);
- static Class getProxyClass(ClassLoader loader,Class[] interfaces);
- static Object newProxyStance(ClassLoader loader,Class[] interfaces,InvocationHander h)
- 动态代理其实是运行时生成class,所以,我们必须提供一组 interface ,然后告诉他class已经实现了这些interface,而且在生成Proxy的时候,必须给他提供一个hander,让他来接管实际的工作
/**
* 要代理的主题接口
*/
public interface Subject {
public void miai();// 相亲
}
/**
*被代理类
*/
public class Person implements Subject{
private String name;
public Person(String name){
this.name =name;
}
@Override
public void miai() {
System.out.println(name+"正在相亲中...");
}
}
/**
* 动态代理类
*/
public class DynaProxy implements InvocationHandler {
private Object target;
public DynaProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj=null;
before();
obj =method.invoke(target, args);//真正调用业务方法,相当于调用 miai方法
after();
return obj;
}
//相亲之后要做的事情
private void after() {
System.out.println("本次相亲结束..");
}
//相亲之前要做的事情
private void before() {
System.out.println("为代理人匹配如意郎君");
}
}
/*
接口 InvocationHandler
InvocationHandler 是代理实例的调用处理程序实现的接口
每一个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke方法。
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
参数:
proxy - 在其上调用方法的代理实例
method - 对应于在代理实例上调用的接口方法的 Method 实例。Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。
*/
4、测试
public class Test {
public static void main(String[] args) {
Person p = new Person("小白");
DynaProxy dynaProxy = new DynaProxy(p);
// Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类
//动态生成代理对象(类加载器,被代理接口,InvocationHandler)
Subject s = (Subject) Proxy.newProxyInstance(p.getClass()
.getClassLoader(), p.getClass().getInterfaces(), dynaProxy);
s.miai();
}
}
输出结果:
为代理人匹配如意郎君
小白正在相亲中...
本次相亲结束..