java反射
通过Class实例获取class信息的方法称为反射、。
3种获取Class实例的方法:
//1
Class clazz = String.class;
//2
String s="s";
Class clazz = s.getClass();
//3
Class clazz = Class.forName("java.lang.String")
Class实例比较和instanceof的差别.经过代码的对比可以发现 instanceof是会比较子类的。
Integer是Number的子类,在instanceof比较是属于一个类型的。
Class实例是精确的匹配类型。
Integer n = new Integer(12);
boolean b1 = n instanceof Integer;//true
boolean b2 = n instanceof Number;//true
boolean b3 = n.getClass == Integer.class;//true
boolean b4 = n.getClass == Number.class;//true
jvm是动态的加载class,我们可以在运行的时候去判断加载的class。
一下就是相关测试 以及部分说明注释
package reflection;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
public class Test1 {
public static void main(String[] args) throws Exception{
//反射基础信息
baseInfo();
//无参构造方法调用生成的
Class<Student> clazz = Student.class;
Student student = (Student) clazz.newInstance();
student.setGrade("1115");
/**
* 访问字段
*/
FieldInfo(student, clazz);
/**
* 访问方法
*/
MethodInfo(clazz, student);
/**
* 调用构造方法
*/
ConstructorInfo();
/**
* 获取继承的关系
*/
ExtendInfo();
/**
* 注解
*/
AnnotationInfo();
/**
* 泛型
*
* 为什么使用泛型?
* 泛型就是定义一种模板。实现重用,不需要单独编写。
*
* 泛型T不能用于静态方法
* 要使用就要新增一个<K>
* 泛型可以同时定义多个
*
* java泛型是采用擦拭法实现的
* 擦拭法局限性
* 1.无法持有基本类型
* 2.不能获取、判断带泛型的class对象
* 3.不能实例化T
* 4.泛型方法要防止重复定义
*
* 子类可以获取父类的泛型类型<T>
*
* extends通配符
* <? extends Number>
* 方法内部!!!
* set方法是无法调用的
* get方法是可以的
* 例外set(null)
*
*
* super通配符
* <? super Number>
* 方法内部!!!
* set方法是可以调用的
* get方法是无法调用的
* 例外object o=get()
*
* ? 无限定通配符
* get方法是无法调用的
* 例外object o=get()
* set方法是无法调用的
* 例外set(null)
*
*/
}
private static void AnnotationInfo() {
System.out.println();
System.out.println("---------输出6 注解------------");
System.out.println("Report是不是注解:"+Report.class.isAnnotation());
System.out.println("Student是不是注解:"+Student.class.isAnnotation());
/**
* 判断是不是使用了
* isAnnotationPresent()
*/
System.out.println("这个类是不是使用了Report注解:"+Student.class.isAnnotationPresent(Report.class));
/**
* 获取注解
* getAnnotation()
* getAnnotations()
* getDeclaredAnnotation()
* getDeclaredAnnotations()
* 和之前的解释差不多
* class,method,field,Constructor都有这个方法
* 特殊一点的是方法参数注解的获取是一个二维数组
*/
System.out.println("注解:"+Student.class.getAnnotation(Report.class));
System.out.println("---------输出6 注解------------");
}
private static void ExtendInfo() {
System.out.println();
System.out.println("---------输出5 继承关系------------");
/**
* 获取父类
* 1.object 的父类是null
* 2.interface 的父类是null
*/
Class<? super Student> sup = Student.class.getSuperclass();
System.out.println("普通类:"+sup);
System.out.println("object类:"+Object.class.getSuperclass());
System.out.println("interface:"+Runnable.class.getSuperclass());
/**
* 获取当前类直接实现的interface
* 1.不包括间接实现的interface
* 2.没有interface的class返回空数组
* 3.interface返回继承的interface
*
* 如果要获取所有的话,需要做一个递归
*/
System.out.println("Integer实现interface的个数:"+Integer.class.getInterfaces().length);
System.out.println("Math实现interface的个数:"+Math.class.getInterfaces().length);
System.out.println("List实现interface的个数"
+ "(他是一个interface,返回的是他继承的interface):"
+List.class.getInterfaces().length);
//判断向上转型是否成立
System.out.println("Integer能否转成Number:"+Integer.class.isAssignableFrom(Number.class));
System.out.println("Number能否转成Integer:"+Number.class.isAssignableFrom(Integer.class));
System.out.println("---------输出5 继承关系------------");
}
private static void ConstructorInfo() throws NoSuchMethodException {
Class<Integer> intclazz = Integer.class;
//
/**
* 1.Constructor是当前类的,是不可能获取到父类的
* 2.私有的方法也可以通过m.setAccessible(true);强制执行,当然也可能失败
*/
//public的构造方法
intclazz.getConstructor(String.class);
//所有的public的构造方法
intclazz.getConstructors();
//所有的public的构造方法
intclazz.getDeclaredConstructor(String.class);
//所有的public的构造方法
intclazz.getDeclaredConstructors();
}
private static void MethodInfo(Class<Student> clazz, Student student)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
//获取某个public的方法 包括父类
clazz.getMethod("setName", String.class);
//获取所有public的方法 包括父类
Method[] methods = clazz.getMethods();
//获取某个public的方法 不包括父类
clazz.getDeclaredMethod("setGrade", String.class);
//获取所有public的方法 不包括父类
Method[] declaredMethods = clazz.getDeclaredMethods();
System.out.println();
System.out.println("---------输出4 访问方法------------");
//System.out.println("父类私有方法"+clazz.getMethod("setSex", String.class));
System.out.println("父类有参方法"+clazz.getMethod("setName", String.class));
System.out.println("子类无参方法"+clazz.getMethod("getGrade"));
for(Method m : methods) {
System.out.println();
System.out.println("name="+m.getName());
System.out.println("ReturnType="+m.getReturnType());
System.out.println("Parameter="+m.getParameters());
System.out.println("ParameterType="+m.getParameterTypes());
System.out.println("Modifiers="+m.getModifiers());
//通过Modifier判断作用范围
System.out.println("is public:"+Modifier.isPublic(m.getModifiers()));
System.out.println("is privagte:"+Modifier.isPrivate(m.getModifiers()));
}
//System.out.println("父类方法"+clazz.getDeclaredMethod("setName", String.class));
System.out.println("子类方法"+clazz.getDeclaredMethod("setGrade", String.class));
for(Method m : declaredMethods) {
System.out.println();
System.out.println("name="+m.getName());
System.out.println("ReturnType="+m.getReturnType());
System.out.println("Parameter="+m.getParameters());
System.out.println("ParameterType="+m.getParameterTypes());
System.out.println("Modifiers="+m.getModifiers());
/**
* 多说两句 ,
* 1.私有的方法也可以通过m.setAccessible(true);强制执行,当然也可能失败
* 2.如果父类的方法,在子类也做了实现,并且作用于子类时,那么即使用从父类获取的方法也是实现子类的方法
* 保证了多态的正确性
* Method m = person.class.getMethod("hello");
* m.invoke(new Student());
*
* 其实就是以下的代码
* Person p = new Student();
* p.hello();
*/
}
//调用方法
Method m = clazz.getMethod("getGrade");
System.out.println("输出grade:"+m.invoke(student));
Method m2 = clazz.getMethod("setGrade", String.class);
//修改grade
m2.invoke(student, "我又把这个改了");
System.out.println("输出修改后的grade:"+m.invoke(student));
System.out.println("---------输出4 访问方法------------");
}
private static void FieldInfo(Student student, Class<Student> clazz) throws NoSuchFieldException, IllegalAccessException {
//获取某个public的field 包括父类的
clazz.getField("name");
//获取当前类的某个field 不包括父类
clazz.getDeclaredField("grade");
//获取所有public的field 包括父类
Field[] fileds = clazz.getFields();
//获取当前类的所有field
Field[] declaredFileds = clazz.getDeclaredFields();
System.out.println();
System.out.println("---------输出3 访问字段------------");
System.out.println("getField父类public字段:"+clazz.getField("name"));
//System.out.println("getField父类private字段:"+clazz.getField("sex"));
System.out.println("getField子类public字段:"+clazz.getField("grade"));
System.out.println("getField子类private字段:"+clazz.getField("age"));
//System.out.println("getDeclaredField父类public字段:"+clazz.getDeclaredField("name"));
//System.out.println("getDeclaredField父类private字段:"+clazz.getDeclaredField("sex"));
System.out.println("getDeclaredField子类public字段:"+clazz.getDeclaredField("grade"));
System.out.println("getDeclaredField子类private字段:"+clazz.getDeclaredField("age"));
System.out.println("获取所有public的field 包括父类:");
for(Field f : fileds) {
System.out.println();
System.out.println("name="+f.getName());
System.out.println("Type="+f.getType());
System.out.println("Modifiers="+f.getModifiers());
}
System.out.println("获取field不包括父类:");
for(Field f : declaredFileds) {
System.out.println();
System.out.println("name="+f.getName());
System.out.println("Type="+f.getType());
System.out.println("Modifiers="+f.getModifiers());
//通过Modifier判断作用范围
System.out.println("is public:"+Modifier.isPublic(f.getModifiers()));
System.out.println("is privagte:"+Modifier.isPrivate(f.getModifiers()));
if("grade".equals(f.getName())) {
//私有的不能获取值 输出的是grade的值
System.out.println("获取值="+f.get(student));
//获取完之后通过set 修改值
f.set(student, "2019");
}else {
//通过强制访问来获取private的字段
/**
* 但是也是可能会失败的,
* 如果设置了SecurityManager,SecurityManager的规则会阻止就强制读取
* 通常情况下自己写的类没有这个问题
* SecurityManager应用场景
当运行未知的Java程序的时候,该程序可能有恶意代码(删除系统文件、重启系统等),
为了防止运行恶意代码对系统产生影响,需要对运行的代码的权限进行控制,这时候就要启用Java安全管理器。
这里就不过的介绍了,有兴趣的同学可以看我其他的博客,会专门写一章进行讲解
*/
f.setAccessible(true);
System.out.println("获取值="+f.get(student));
}
}
//获取一下刚刚设置的值
System.out.println("第二次获取值="+clazz.getDeclaredField("grade").get(student));
System.out.println("---------输出3 访问字段------------");
}
private static void baseInfo() {
Class<String> clazz = String.class;
//完整类名
String fname = clazz.getName();
//类名
String sname = clazz.getSimpleName();
//包名
String pkg = clazz.getPackage().getName();
System.out.println("---------输出1------------");
System.out.println("完整类名:"+fname);
System.out.println("类名:"+sname);
System.out.println("包名:"+pkg);
System.out.println("---------输出1------------");
//是否接口
//clazz.isInterface();
//是否枚举
//clazz.isEnum();
//是否数组
//clazz.isArray();
//是否基本类型
//clazz.isPrimitive();
System.out.println();
System.out.println("---------输出2------------");
System.out.println("类是String");
System.out.println("是否接口:"+clazz.isInterface());
System.out.println("是否枚举:"+clazz.isEnum());
System.out.println("是否数组:"+clazz.isArray());
System.out.println("是否基本类型:"+clazz.isPrimitive());
System.out.println("---------输出2------------");
}
}
student类
package reflection;
@Report(value = "")
public class Student extends Person{
public String grade;
private String age;
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public void hello() {
System.out.println("Student hello");
}
}
person类
package reflection;
public class Person {
public String name;
public String age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSex() {
return sex;
}
private void setSex(String sex) {
this.sex = sex;
}
public void hello() {
System.out.println("person hello");
}
}
report自定义注解
package reflection;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @interface 必须
* 定义一个注解
*
* @Target 是一个元注解 必须
* 定义注解可以用于源码那些位置
* ElementType这个参数自己详细去看吧,
* 无非就是作用于类,方法,构造方法,字段,方法参数
*
* @Retention 必须
* 定义注解的生命周期
* RetentionPolicy这个参数自己详细去看吧,
* 编译期,运行期,class文件
*
*@Repeatable
*定义注解是否可以重复
*
*@Inherited
*定义子类是否可以使用父类定义的注解
*仅针对@Target是type的
*仅针对class
*对interface继承无效
*/
//@Inherited
//@Repeatable(Reports.class)
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Report {
int type() default 0;
String level() default "info";
String value();
}