目录
一、反射定义及用途
1.定义
Java反射机制是指是在运行期中,对于任意一个类,都能够得到这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。
根据类名,就可以通过该类的newInstance()方法创建对象。
1.1 获取当前类的Class对象的方式有三种:
1.直接根据当前类名.class获取
2.通过getClass()方法获取
3.通过Class.forName()获取
//Class对象的三种获取方式
//1.通过类名访问
Class c1=String.class;
//2.通过 getClass()方法访问
String s="";
Class c2=s.getClass();
//3,.通过Class的静态方法forName(类名)访问
Class c3=Class.forName("java.lang.String");
//得到相同的Class对象
System.out.println("c1="+c1.hashCode());
System.out.println("c2="+c2.hashCode());
System.out.println("c3="+c3.hashCode());
以上三种情况得到的是同一个Class对象。
1.2 通过类的newInstance()方法创建对象
//利用反射机制创建对象
Object o1=c1.newInstance();
Object o2=c2.newInstance();
Object o3=c3.newInstance();
虽然c1、c2、c3本质都是String的Class对象,但是创建出来的o1、o2、o3是三个不同的对象。
2.用途
在服务器端,往往需要根据客户的请求,动态调用某一个对象的特定方法或者为属性赋值。
Java 反射机制主要提供了以下功能,这些功能都位于java.lang.reflect 包。
(1)在运行时判断任意一个对象所属的类。
(2)在运行时构造任意一个类的对象。
(3)在运行时判断任意一个类所具有的成员变量和方法。
(4)在运行时调用任意一个对象的方法。
(5)生成动态代理。
二、反射的常用类及其方法
1.Class类
(1)理解
Class类是利用反射机制操作创建对象和后续操作的前提类。class(包括interface)的本质是数据类型(Type)。class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时,将其加载进内存。每加载一种class,JVM就为其创建一个Class类型的实例,并关联起来。
class(包括interface)的本质是数据类型(Type)。class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时,将其加载进内存。每加载一种class,JVM就为其创建一个Class类型的实例,并关联起来。
Class类的构造方法是私有的,也就是说我们自己不能创建Class示例,仅由Java虚拟机(JVM)可以创建,class(包括interface)的本质是数据类型(Type)。class是由JVM在执行过程中动态加载的。因此,JVM持有的每个Class实例都指向一个数据类型(class或interface)。
一个Class实例包含了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段(成员变量)等。
(2)Class常用方法:
类型 | 访问方法 | 返回值类型 | 说明 |
包路径 | getPackage() | Package对象 | 获取该类的存放路径 |
类名称 | getName() | String对象 | 获取该类的名称 |
继承类 | getSuperclass() | Class对象 | 获取该类继承的类 |
实现接口 | getInterfaces() | Class型数组 | 获取该类实现的所有接口 |
构造方法 | getConstructors() | Constructor型数组 | 获取所有权限为public的构造方法 |
构造方法 | getDeclaredConstructors() | Constructor对象 | 获取当前对象的所有构造方法 |
方法 | getMethods() | Methods型数组 | 获取所有权限为public的方法 |
方法 | getDeclaredMethods() | Methods对象 | 获取当前对象的所有方法 |
成员变量 | getFields() | Field型数组 | 获取所有权限为public的成员变量 |
成员变量 | getDeclaredFields() | Field对象 | 获取当前对象的所有成员变量 |
(3)具体代码实现:
public class ClassDemo2 {
public static void main(String[] args) {
Class c1=Person.class;
Class c2=Integer[].class;//数组类
Class c3=List.class;
Class c4=DayOfWeek.class;//枚举类
printClassInfo(c1);
printClassInfo(c2);
printClassInfo(c3);
printClassInfo(c4);
}
public static void printClassInfo(Class c) {
//类名
System.out.println("类(接口)的名称:"+c.getSimpleName());
System.out.println("完全限定名:"+c.getName());
System.out.println("类(接口)的类型名称:"+c.getTypeName());
//父类
Class superClass=c.getSuperclass();
System.out.println("类的父类:"+superClass);
//实现的接口
Class[] interfaceClass=c.getInterfaces();
System.out.println("当前类实现的接口:");
for(Class c1:interfaceClass) {
System.out.println(c1);
}
//package包
Package p=c.getPackage();
if(p!=null) {
System.out.println("类所在的包名称:"+p.getName());
}
//判断类型
System.out.println("是否为接口:"+c.isInterface());
System.out.println("是否为数组:"+c.isArray());
System.out.println("是否为枚举:"+c.isEnum());
System.out.println("是否为基本类型:"+c.isPrimitive());
System.out.println();
}
}
2.Constructor类
(1)理解
它包含一个构造方法的所有信息,可以创建一个实例。Constructor对象是一个构造方法,调用结果总是返回实例。
(2)Constructor常用方法
方法名及参数 | 说明 |
getConstructor(Class...) | 获取某个public的Constructor |
getDeclaredConstructor(Class...) | 获取某个定义的Constructor |
getConstructors() | 获取所有public的Constructor |
getDeclaredConstructors() | 获取所有定义的Constructor |
(3)具体代码实现:
Example实体类:
public class Example {
public Example() {
System.out.println("Example的无参构造方法被加载!");
}
public Example(int a) {
System.out.printf("Example的有1个参数的构造方法被加载: a=%d\n ",a);
}
public Example(int a,double b) {
System.out.printf("Example的有2个参数的构造方法被加载:a=%d,b=%.2f\n",a,b);
}
private Example(String s) {
System.out.printf("Example的私有的有参构造方法被加载!s=%s\n",s);
}
protected Example(float f) {
System.out.println("Example的受保护的有参构造方法被加载");
}
}
ConstructorDemo类:
public class ConstructorDemo {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
Class class1=Example.class;
//1.调用无参构造
Example e1=(Example)class1.newInstance();
Constructor[] conStrArray=class1.getConstructors();
System.out.println("Example的公有构造方法如下:");
for(Constructor c:conStrArray) {
System.out.println(c);
}
//调用有参构造
//2.一个参数有参构造
Constructor c2=class1.getConstructor(int.class);
Example e2=(Example)c2.newInstance(1);
System.out.println(e2);
//3.2个参数有参构造
Constructor c3=class1.getConstructor(int.class,double.class);
Example e3=(Example)c3.newInstance(1,2.778685);
System.out.println(e3);
}
}
结果:
3.Field类
(1)理解:字段(成员变量)类。
(2) Field类方法
方法名 | 说明 |
Field getField(name) | 根据字段名获取当前类中某个public的field(包括父类) |
Field getDeclaredField(name) | 根据字段名获取当前类中定义的某个field(不包括父类) |
Field[] getFields() | 获取所有public的field(包括父类) |
Field[] getDeclaredFields() | 获取当前类中定义的所有field(不包括父类) |
(3)具体代码实现:
Order类:
public class Order extends Product{
private String password;
public int no;
public String sex;
protected String name;
public String getPassword() {
return password;
}
public int getNo() {
return no;
}
public String getSex() {
return sex;
}
public String getName() {
return name;
}
public void setPassword(String password) {
this.password = password;
}
public void setNo(int no) {
this.no = no;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Order [password=" + password + ", no=" + no + ", sex=" + sex + ", name=" + name + "]";
}
public int dosth() {
Random rand=new Random();
return rand.nextInt(100);
}
public int dosth(int a) {
Random rand=new Random();
return rand.nextInt(a);
}
}
FieldsDemo类 :
public class FieldsDemo {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
Class c1=Order.class;//获取Class类型对象
//1.得到所有public访问字段(成员变量):getFields()方法
System.out.println("所有访问字段:");
Field[] zd=c1.getFields();
//2.得到所有的成员变量:getDeclaredFields()方法
Field[] allzd=c1.getDeclaredFields();
for(Field f: allzd) {
System.out.println("------------------");
System.out.println("成员变量名称:"+f.getName());
System.out.println("成员变量类型:"+f.getType());
System.out.println("成员变量的访问修饰符(int值):"+f.getModifiers());
System.out.println("成员变量的访问修饰符:"+Modifier.toString(f.getModifiers()));
}
//3.设置具体的某个字段的值set()
Field field1=c1.getDeclaredField("name");//根据字段名来创建字段对象
if(!field1.isAccessible()) {
field1.setAccessible(true);
}
//通过反射创建对象
Object obj=c1.newInstance();
//进行赋值
field1.set(obj,"刀马旦");
System.out.println(obj);
}
}
结果:
4.Method类
(1)理解:通过Class实例获取所有方法。
(2)Method类方法:
方法名 | 说明 |
Method getMethod(name, Class...) | 获取某个public的Method(包括父类) |
Method getDeclaredMethod(name, Class...) | 获取当前类的某个Method(不包括父类) |
Method[] getMethods() | 获取所有public的Method(包括父类) |
Method[] getDeclaredMethods() | 获取当前类的所有Method(不包括父类) |
(3)具体代码实现:
MethodsDemo类
public class MethodsDemo {
public static void main(String[] args) {
//拿到Class对象
Class class1=Order.class;
//拿到所有方法
System.out.println("该类所有方法如下:");
System.out.println("--------------");
Method[] methodArray=class1.getMethods();
//拿到当前类重写的所有方法
Method[] methods=class1.getDeclaredMethods();
for(Method m:methods) {
System.out.println("方法的访问修饰符:"+Modifier.toString(m.getModifiers()));
System.out.println("方法名:"+m.getName());
System.out.println("方法返回值类型:"+m.getReturnType());
//获取当前方法所有参数
Parameter[] params=m.getParameters();
for(Parameter param:params) {
System.out.println("参数名称:"+param.getName());
System.out.println("参数类型"+param.getType());
System.out.println("---------------");
}
}
}
}
结果:
总结:
1.JVM在执行Java程序的时候,并不是一次性把所有用到的class全部加载到内存,而是第一次需要用到class时才加载。
2.通过getConstructor(传入参数类型的不同)得到有参或者无参(不传参)构造方法。
3.得到所有public访问字段(成员变量):getFields()方法
得到所有的访问字段(成员变量):getDeclaredFields()方法
4.获取所有public的Method(包括父类):getMethods() 方法
获取当前类的所有Method(不包括父类):getDeclaredMethods()方法