java反射机制(初学者福利)
前言
最近在学习Java的反射机制,看了很多网上的资料,感觉有点深,初学者理解起来有点困难,干脆把自己理解的写了些总结,希望能对初学反射机制的童鞋有些帮助,如果有不对的地方,还望各位侠士不吝指出.
注:部分内容来源于网络
一.什么是反射
网络上的定义是:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制.
我们通常写的程序都是静态的代码,就是编译之后就能够确定执行顺序的就是静态,而动态是需要程序在运行的时候才知道是如何执行的是便动态,这是我对于动态的理解.换句话说就是我们对想要获取的类在编译期间是完全不了解的,只有在运行的时候才知道.
二.有什么功能
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。(好长啊,总之就是在运行时获取类的所有属性和方法,然后可以任意调用用里边的方法和属性)
三.Java为我们提供了这些反射机制中的类:
java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
很多反射中的方法,属性等操作我们可以从这四个类中查询。
四.具体功能实现
1.获取类
这里我以获取Person类为例
package reflect;
public class Person {
private String name;
private int age;
public Person(){
System.out.println("无参构造器");
}
public Person(String name, int age) {
System.out.println("有参构造器");
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
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;
}
}
//设置的全局变量
//person类 全类名(路径, 我是放在src目录下的reflect目录里边)
private static String str = "reflect.Person";
/**
* 反射机制的三种获取类的方法
* @throws ClassNotFoundException
*/
@Test
public void testGetClass() throws ClassNotFoundException {
Class cla = null;
//1.通过 类名.class 直接获得
cla = Person.class;
System.out.println("通过类名:" + cla);
//2.通过 对象的getClass()方法获取, 这个使用的少(一般传的是Object, 不知道是什么类型的时候采用)
Object object = new Person();
cla = object.getClass();
System.out.println("通过对象的getClass获取:" + cla);
//3.通过全类名获取, 用的比较多, 但可能抛出ClassNotFoundException异常
cla = Class.forName(str);
System.out.println("通过全类名:" + cla);
}
结果:
通过类名:class reflect.Person
无参构造器
通过对象的getClass获取:class reflect.Person
通过全类名:class reflect.Person
2.利用newInstance创建对象
/**
* Class类的newInstance()方法,创建类的一个对象。
*
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
@Test
public void testNewInstance() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class clazz = Class.forName(str);
//使用Class类的 newInstance()方法 创建类的一个对象
//实际调用的类的那个 无参数的构造器(这就是为什么写的类的时候,要写一个无参数的构造器,就是给反射用的)
//一般的,一个类若声明了带参数的构造器,也要声明一个无参数的构造器
Object object = clazz.newInstance();
System.out.println(object);
}
结果:
无参构造器
Person{name='null', age=0}
这里有一个点需要注意,调用的类(这里是Person类)一定一定一定要有无参构造方法(为了避免重载构造方法后忘记写无参构造方法,最好在类创建的时候就写出来)
下面是重载无参构造方法后(没有无参构造方法)执行的结果:
Error:(32, 25) java: 无法将类 reflect.Person中的构造器 Person应用到给定类型;
需要: java.lang.String,int
找到: 没有参数
原因: 实际参数列表和形式参数列表长度不同
3.获取类里边属性:分为所有的属性和指定的属性
/**
* 获取类的所有属性
* @throws ClassNotFoundException
*/
@Test
public void testGetDeclaredFields() throws ClassNotFoundException {
Class clazz = Class.forName(str);
//获取所有的属性
Field[] fields = clazz.getDeclaredFields();
//定义可变长的字符串,用来存储属性
//通过追加的方法,将每个属性拼接到此字符串中
StringBuffer strB = new StringBuffer();
//最外边的public Class 类
strB.append(Modifier.toString(clazz.getModifiers()) + " class " + clazz.getSimpleName() +"{\n");
//里边的每一个属性
for(Field field: fields){
strB.append("\t");//空格
strB.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
strB.append(field.getType().getSimpleName() + " ");//属性的类型的名字,例如int, String
strB.append(field.getName()+";\n");//属性的名字
}
strB.append("}");
System.out.println(strB.toString());
}
结果:
public class Person{
private String name;
private int age;
}
/**
* 获取类的指定属性
* @throws ClassNotFoundException
* @throws NoSuchFieldException
* @throws IllegalAccessException
* @throws InstantiationException
*/
@Test
public void testGetDeclaredFiled() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
//1.获取类
Class clazz = Class.forName(str);
//2.获取age属性
Field age = clazz.getDeclaredField("age");
System.out.print(Modifier.toString(age.getModifiers()) + " " + age.getType().getSimpleName() + " " + age.getName() + "\n");
//3.获取name属性
Field name = clazz.getDeclaredField("name");
System.out.print(Modifier.toString(name.getModifiers()) + " " + name.getType().getSimpleName() + " " + name.getName() + "\n");
//实例化这个类
Object obj = clazz.newInstance();
//打破封装
//使用反射机制可以打破封装性,导致了java对象的属性不安全
age.setAccessible(true);
//给obj对象的age属性赋值 18
age.set(obj, 18);
System.out.println(age.get(obj));
}
结果:
private int age
private String name
无参构造器
18
4.获取类里其他内容的相关方法
在这里就不再一一演示下面这些方法的使用,大家可以自己去code看看
方法关键字 | 含义 |
---|---|
getDeclaredMethods() | 获取所有的方法 |
getReturnType() | 获得方法的放回类型 |
getParameterTypes() | 获得方法的传入参数类型 |
getDeclaredMethod("方法名",参数类型.class,……) | 获得特定的方法 |
构造方法关键字 | 含义 |
---|---|
getDeclaredConstructors() | 获取所有的构造方法 |
getDeclaredConstructor(参数类型.class,……) | 获取特定的构造方法 |
父类和父接口 | 含义 |
---|---|
getSuperclass() | 获取某类的父类 |
getInterfaces() | 获取某类实现的接口 |
总结
这篇主要是介绍了如何使用反射机制,反射机制原理我将在下一篇中再和大家一起探讨(还在学习中,233),毕竟用轮子比造轮子简单.
我刚开始看反射机制时也不是太懂,然后我就反复看,最重要的是反复code,然后反复理解,逐渐对反射机制的掌握就加深了,先熟练使用轮子后再去学习如何造轮子总是最快的(学习其他知识也是一样).