反射Reflection
反射是JAVA中的一种机制,被称为java语言的反射机制,允许我们在代码动态获取类型中的相关信息和相关操作(方法等)
1、Class类型,java.lang.Class类–是java反射的入口
Class类是对java中所有类型的抽象而得到的一个类,即Class类类型对象可以表示java中任意一种类型。
每种类型在其加载到内存后,内存中都会产生一个与之对应的Class类类型的对象(有且只有一个),用来代表该类型。
每个类型都有且只有一个Class类类型的对象与之对应,通过这个Class类类型的对象我们就能获取该类型中的相关信息和操作。
例如:
1)Class类类型对象表示基本类型
Class cInt=int.class;
//isPrimitive()判断是否是原始类型即基本数据类型
System.out.println(cInt.isPrimitive);
//获取类型名
System.out.println(cInt.getName);
//输出结果:
true
int
2)Class类类型对象表示类类型
Student stu=new Student();
//getClass()返回的是引用stu所指向的对象的实现类型的Class对象(获取Class类类型对象的一种方法)
Class cStu1=stu.getClass();
//直接通过类名.class获取Class类类型的对象(获取Class类类型的一种方法)
Class cStu2=Student.class;
;//都是Student类型,每种类型的Class类类型的对象只有一个
System.out.println(cStu1==cStu2)
//输出结果
true
Person p = new Student();
Class c1 = p.getClass();//c1表示Student类型
Class c2 = Person.class;//c2表示Person类型
//类型不同,他们的Class类类型对象也不同
System.out.println(c1 == c2);
输出结果
false
3)Class类类型的对象表示接口类型
Action a = new Student();
Class c1 = a.getClass();//c1表示Student类型,获取的是a引用所指向的对象类型的Class类型对象
Class c2 = Action.class;//c2表示Action类型
System.out.println(c1 == c2);
//isInterface判断是否是接口
System.out.println(c1.isInterface());
System.out.println(c2.isInterface());
输出结果:
false
false
true
4)Class类类型的对象表示数组类型
int[] a = new int[4];
Class c1 = a.getClass();
Class c2 = int[].class;
System.out.println(c1 == c2);//true
System.out.println(c1.isArray());//true
Class c3 = c1.getComponentType();//c3表示该数组是使用什么类型声明出来的
System.out.println(c3.getName());//int
Student[] a = new Student[4];
Class c1 = a.getClass();
Class c2 = Student[].class;
System.out.println(c1 == c2);//true
System.out.println(c1.isArray());//true
Class c3 = c1.getComponentType();//c3表示该数组是使用什么类型声明出来的
System.out.println(c3.getName());//com.nc.test.Student类的全限定名
2、获取一个类类型的Class对象的三种方式
注:使用较多的数类类型的Class类型对象
1)使用类类型的对象调用getClass方法;getClass是Object中的final修饰的方法,每个对象都可以调用而且不能重写
Student s=new Student();
Class c=s.getClass();//获取的是s所指的类类型对象的Class类型对象
2)使用类型获取Class类型对象
Class c =Student.class;
3)使用Class类中的静态方法forName方法获取Class类型对象
注:这种方法比较灵活,只需要一个String类型的参数就行,String类型的参数为类的全限定名(包名+类名);此方法需要抛出异常
Class c=Class.forName("com.nc.test.Studnet");
//com.nc.test为Student类所在的包名
注:每种类型只有一个Class类类型的对象与之对应,所有不管用哪种方法,获取同一个类型的Class类型对象,使用==判断都是相等的;因为内存地址相同。
3、反射机制中常见的类
java.lang包下:
Class 类 对java中所有类型抽象而得来的
Package类 对java中所有包抽象而得来的
java.lang.reflect包下:
Modifier 类 对java中所有修饰符抽象而得来的
Field 类 对java中所有属性抽象而得来的
Method 类 对java中所有方法抽象而得来的
Constructor 类 对java中所有构造器抽象而得来的
Array 类 提供了对数组对象的动态访问
ParameterizedType接口 在反射中表示参数化类型;例如:List<String> Point<Long,Long>等这种带泛型的类型
4、使用Class类型对象获取类中信息
1)获取该类所处的包的信信息;getPackage()方法获取包
Student s=new Student();
Class c=s.getClass();
System.out.println(c.getPackage().getName());//打印输出Class类型对象所对应Student类所在包的包名
2)获取该类的修饰符信息;getModifiers()获取修饰符
//每个修饰符对应一个int值
//如果有多个修饰符则int值相加
Student s = new Student();
Class c = s.getClass();
System.out.println(c.getModifiers());//获取Class类型对象对应的Student类的修饰符
System.out.println(Modifier.PUBLIC);//打印输出public修饰的int值
System.out.println(Modifier.FINAL);//打印输出fianl修饰的int值
3)获取该类的名字
Student s = new Student();
Class c = s.getClass();
System.out.println(c.getName());//获取Class类型对象所对应的类Student类的类名(全限定名:包名+类名)
4)获取该类的父类的Class类型对象
Student s = new Student();
Class c = s.getClass();
//superclass表示其父类型的Class对象
Class superclass = c.getSuperclass();
//打印输出父类的名字
System.out.println(superclass.getName());
例如:
Class c = Object.class;
Class superclass = c.getSuperclass();
System.out.println(superclass.getName());
//运行报错,因为Object没有父类
例如:
//判断c1是不是c2的子类型
//判断c3是不是c2的子类型
Class c1 = Student.class;
Class c2 = Person.class;
Class c3 = String.class
System.out.println(c2.isAssignableFrom(c1));//true
System.out.println(c2.isAssignableFrom(c3));//false
5)获取该类所实现的接口类型的Class类类型对象;getInterfaces()(接口是多实现,所有返回值是一个数组,存储接口的Class类类型的对象)
Student s = new Student();
Class c = s.getClass();
//获取
Class[] interfaces = c.getInterfaces();
for(Class clazz:interfaces){
System.out.println(clazz.getName());
}
例如:
//判断c1是不是c2的实现类
//判断c3是不是c2的实现类
Class c1 = Student.class;
Class c2 = Action.class;
Class c3 = String.class
System.out.println(c2.isAssignableFrom(c1));//true
System.out.println(c2.isAssignableFrom(c3));//false
6)获得该类中所有属性
注:
getDeclaredFields()方法返回类中声明的属性,包括私有的
getFields()方法只返回类中public修饰的属性,包括继承的
例如:
Student s=new Student();
Class c=s.getClass();
//获取Class类型对应的Student类中声明的所有属性包括私有的,存到属性类Field数组中
Field[] delaredField=c.getgetDeclaredFields();
//使用for循环遍历数组
for(Field f:delaredField){
// getModifiers()方法,获取属性的修饰符
System.out.println(f.getModifiers());
//getType()获取属性的类型
System.out.println(f.getType().getName());
//获取属性名
System.out.println(f.getName());
}
7)获得该类中所有的方法
注:
getDeclaredMethods()方法返回类中声明的方法,包括私有的
getMethods()方法只返回类中public修饰的方法,包括继承的
例如:
Student s = new Student();
Class c = s.getClass();
//获取Class类型对象所对应的类类型Student类中的所有方法,包括私有的,存到方法类Method的数组中
Method[] declaredMethods = c.getDeclaredMethods();
//使用for循环遍历Method数组
for(Method m:declaredMethods){
//getModifiers()获取方法的修饰符
System.out.println(m.getModifiers());
//getReturnType()获取方法返回值类型
System.out.println(m.getReturnType().getName());
//获取方法名
System.out.println(m.getName());
//getParameterTypes()获取方法的参数类型
System.out.println(Arrays.toString(m.getParameterTypes()));
//getExceptionTypes()获取方法的异常类型
System.out.println(Arrays.toString(m.getExceptionTypes()));
}
8)获取类中所有构造器
注:
getDeclaredConstructors()方法返回类中所有构造器
getConstructors()方法只返回类中public修饰的构造器
Student s = new Student();
Class c = s.getClass();
//getDeclaredConstructors()获取Class类型对象所对应的类类型Student类的所有构造器,存入构造器类Constructor的数组中
Constructor[] declaredConstructors = c.getDeclaredConstructors();
//循环遍历Constructor构造器类型的数组
for(Constructor con:declaredConstructors){
//getModifiers()获构造器的修饰符
System.out.println(con.getModifiers());
//获取构造器名
System.out.println(con.getName());
//getParameterTypes()获取构造器参数类型
System.out.println(Arrays.toString(con.getParameterTypes()));
//getExceptionTypes()获取构造器异常类型
System.out.println(Arrays.toString(con.getExceptionTypes()));
}
9)了解
—获得父类型中的泛型的真实类型
因为泛型类的泛型参数在编译期会被擦除,所以我们不能在运行期间直接拿到该泛型的实际类型,但是可以通过子类的Class对象来获取父类的泛型类型。
—获得类中的注解
使用反射也可以获得类中的注解.