java反射

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();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值