Java反射
参考别人的一句话,反射是框架设计的灵魂。
什么是反射?
在运行的状态中,对于任意一个类,都可以知道他的属性和方法,对于任意一个对象都能够调用他的方法和属性,这种动态获取信息以及动态调用对象的方法的功能成为java的反射机制。
首先获取该类的字节码文件对象。而解剖使用的是Class类中的方法,所以要先获取到每一个字节码文件对应的Class对象。
通过类的字节码文件得到Class对象,再利用Class中的方法将类中的各个组成部分:属性、方法、构造方法映射为一个个对象。
Class没有公共的构造方法,Class对象是在加载类的过程中JVM通过调用类加载器中的defineClass方法自动构造的。不需要自己创建
反射的应用
获取Class对象的三种办法:
①通过类对象的getClass()方法
②任何数据类型都拥有的一个静态的class属性
③通过Class类的静态方法Class.forName(String className)
使用①方法是因为Java中的类都是Object的父类,这个方法来自Object。
使用③方法创建Class对象,传参className是该类的全限定名。
/**
* 反射复习1
* 通过三种方式获取Class对象
*/
public class Reflect1 {
/**
* 使用 类.class对象获取反射对象
* 输出 class com.entity.User
*/
@Test
public void testClass1(){
System.out.println(User.class);
}
/**
* 使用对象的getClass()方法获取反射对象
* 输出:class com.entity.User
*/
@Test
public void testClass2(){
User user=new User();
System.out.println(user.getClass());
}
/**
* 使用Class.forName获取反射对象
* 输出:class com.entity.User
*/
@Test
public void testClass3(){
try {
Class<?> aClass = Class.forName("com.entity.User");
System.out.println(aClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
从上面可以看出来,一个类只要一个Class对象。创建Class对象一般使用第三种方式。
获取构造方法
public class reflectConstructor {
/**
* 反射复习2
* 反射获取对象的构造方法并使用
*/
Class aClass;
/**
* 获取无参构造器
* @throws Exception
* 运行结果:无参构造器!
*/
@Test
public void getConstructorNoParam() throws Exception {
aClass=Class.forName("com.entity.User");//会有找不到类的异常
Constructor constructor = aClass.getConstructor();
User user = (User) constructor.newInstance();
}
/**
* 获取公有的有参构造方法
* @throws Exception
* 运行结果:有参构造器 age=2
*/
@Test
public void getConstructorHasParam() throws Exception {
aClass=Class.forName("com.entity.User");
Constructor constructor = aClass.getConstructor(Integer.class);
User user= (User) constructor.newInstance(2);
}
/**
* 获取受保护的有参构造方法
* 要使用setAccessible(true)方法忽略修饰符的检查
* @throws Exception
* 输出:
* protected com.entity.User(char)
* 受保护的构造器 chr=a
*/
@Test
public void getConstructorProtect() throws Exception{
aClass=Class.forName("com.entity.User");
Constructor constructor=aClass.getDeclaredConstructor(char.class);
System.out.println(constructor);
constructor.setAccessible(true);
User user= (User) constructor.newInstance('a');
}
/**
* 获取私有的有参构造方法和受保护的一样,要忽略修饰符的检查
* @throws Exception
* 输出:
* private com.entity.User(java.lang.String)
* 私有构造器 username=1211
*/
@Test
public void getConstructorPrivate() throws Exception{
aClass=Class.forName("com.entity.User");
Constructor constructor=aClass.getDeclaredConstructor(String.class);
System.out.println(constructor);
constructor.setAccessible(true);
User user= (User) constructor.newInstance("1211");
}
/**
* 获取所有的公有的无参构造器
* @throws Exception
* 输出:
* public com.entity.User(java.lang.Integer)
* public com.entity.User()
*/
@Test
public void getAllContructorsPublic() throws Exception{
aClass=Class.forName("com.entity.User");
Constructor[] constructors = aClass.getConstructors();
for (Constructor constructor:constructors){
System.out.println(constructor);
}
}
/**
* 获取所有的构造方法,包括私有、公有、受保护
* @throws Exception
* 输出:
* protected com.entity.User(char)
* private com.entity.User(java.lang.String)
* public com.entity.User(java.lang.Integer)
* public com.entity.User()
*/
@Test
public void getAllConstructors() throws Exception{
aClass=Class.forName("com.entity.User");
Constructor[] constructors = aClass.getDeclaredConstructors();
for (Constructor constructor:constructors){
System.out.println(constructor);
}
}
}
获取类的成员变量
/**
* 反射复习3 反射获取类的成员变量
*/
public class ReflectFiled {
Class aClass;
/**
* 获取类的公有的成员变量,并调用
* @throws Exception
* 输出:
* 无参构造器!
* I love you
*/
@Test
public void getFieldPublic() throws Exception {
aClass=Class.forName("com.entity.User");
Field username = aClass.getField("username");
User user= (User) aClass.getConstructor().newInstance();
username.set(user,"I love you");
System.out.println(user.username);
}
/**
* 获取类的私有成员变量并调用
* @throws Exception
* 输出:
* 无参构造器!
* 123123
*/
@Test
public void getFiledPrivate() throws Exception{
aClass=Class.forName("com.entity.User");
Field password=aClass.getDeclaredField("password");
password.setAccessible(true);//取消检查
User user= (User) aClass.getConstructor().newInstance();
password.set(user,"123123");
System.out.println(user.getPassword());
}
/**
* 获取类的受保护成员变量并调用
* @throws Exception
* 输出:
* 无参构造器!
* 12
*/
@Test
public void getFieldProtected() throws Exception{
aClass=Class.forName("com.entity.User");
Field age=aClass.getDeclaredField("age");
age.setAccessible(true);//取消检查
User user= (User) aClass.getConstructor().newInstance();
age.set(user,12);
System.out.println(user.getAge());
}
/**
* 获取类的所有公有的成员变量
* @throws Exception
* 输出:
* public java.lang.String com.entity.User.username
*/
@Test
public void getAllFieldsPublic() throws Exception{
aClass=Class.forName("com.entity.User");
Field[] fields = aClass.getFields();
for (Field field:fields){
System.out.println(field);
}
}
/**
* 获取类的所有的成员变量,包括公有和私有
* @throws Exception
* 输出:
* public java.lang.String com.entity.User.username
* private java.lang.String com.entity.User.password
* protected java.lang.Integer com.entity.User.age
*/
@Test
public void getAllFileds() throws Exception{
aClass=Class.forName("com.entity.User");
Field[] fields = aClass.getDeclaredFields();
for (Field field:fields){
System.out.println(field);
}
}
}
获取类的方法
public class ReflectMethod {
Class aClass;
/**
* 获取类的公有的方法getAge(),并获取成员变量age复制,使用得到的方法输出
* @throws Exception
* 输出:
* 无参构造器!
* 12
*/
@Test
public void getMethodPublic() throws Exception {
aClass=Class.forName("com.entity.User");
//第一个参数是方法名,第二个参数是方法的参数类型
Method getAge = aClass.getMethod("getAge", null);
User user= (User) aClass.getConstructor().newInstance();
Field field=aClass.getDeclaredField("age");
field.setAccessible(true);
field.set(user,12);
System.out.println(getAge.invoke(user,null));
}
/**
* 获取类的私有的方法并调用
* @throws Exception
* 输出:
* 无参构造器!
* things=watch TV,count=3
*/
@Test
public void getMethodPrivate() throws Exception {
aClass=Class.forName("com.entity.User");
Method printThings=aClass.getDeclaredMethod("printThings",String.class,Integer.class);
printThings.setAccessible(true);
User user= (User) aClass.getConstructor().newInstance();
printThings.invoke(user,"watch TV",3);
}
/**
* 获取类的所有的公有的方法,包含继承了的方法
* @throws Exception
* 输出:
* public java.lang.String com.entity.User.getPassword()
* public java.lang.Integer com.entity.User.getAge()
* public final void java.lang.Object.wait() throws java.lang.InterruptedException
* public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
* public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
* public boolean java.lang.Object.equals(java.lang.Object)
* public java.lang.String java.lang.Object.toString()
* public native int java.lang.Object.hashCode()
* public final native java.lang.Class java.lang.Object.getClass()
* public final native void java.lang.Object.notify()
* public final native void java.lang.Object.notifyAll()
*/
@Test
public void getMethodAllPublic() throws Exception{
aClass=Class.forName("com.entity.User");
Method[] methods = aClass.getMethods();
for (Method method:methods){
System.out.println(method);
}
}
/**
* 获取类的所有的方法,这里不含有继承的方法,只含有本类的方法,包括公有、私有、保护
* @throws Exception
* 输出:
* public java.lang.String com.entity.User.getPassword()
* public java.lang.Integer com.entity.User.getAge()
* private void com.entity.User.printThings(java.lang.String,java.lang.Integer)
* protected void com.entity.User.hello()
*/
@Test
public void getAllMethods() throws Exception{
aClass=Class.forName("com.entity.User");
Method[] declaredMethods = aClass.getDeclaredMethods();
for(Method method:declaredMethods){
System.out.println(method);
}
}
}
反射获取main方法
public class ReflectMain {
/**
* 反射获取类的main方法
* @throws Exception
* 输出:
* I love you
* so much
*/
@Test
public void getMain() throws Exception {
Class aClass=Class.forName("com.entity.User");
Method main = aClass.getMethod("main", String[].class);
//因为是静态的,所以Object可以传null
main.invoke(null,(Object) new String[]{"I love you", "so much"});
}
}
反射获取泛型
public class ReflectGenerics {
/**
* 反射去掉泛型,泛型会在编译的时候检查,编译之后就不存在了,所以可以利用java的字节流文件得到反射对象再填数据
* @throws Exception
* 输出:
* 2
* 10
* I love you so much
*/
@Test
public void getGenerics() throws Exception {
ArrayList<Integer> arrayList=new ArrayList<>();
arrayList.add(2);
arrayList.add(10);
Class clazz=arrayList.getClass();
Method add = clazz.getMethod("add", Object.class);
add.invoke(arrayList,"I love you so much");
for (Object object:arrayList){
System.out.println(object);
}
}
}