注解和反射

注解和反射

注解

  • 所有框架的底层

内置注解举例

@Override

@SupressWarnnig

@Deprecated

元注解

  • 注解的注解

    @Target	作用对象
    
    @Retention	作用级别(SOURCE<CLASS<RUNTIME)
    
    @Documented	是否包含将注解生成在javadoc中
    
    @inherited	子类继承父类中该注解
    

自定义注解

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

	//注解的参数:参数类型 参数名();
	//注解可以显式赋值,如果没有默认值,就必须给注解赋值
	String param1() default "";

	int param2() default 0;

	//如果默认值为-1,代表该参数不存在
	int param3() default -1;

	String[] params();
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
	String value();
}

如何去读取注解?

  • 反射

反射机制

哪些类型可以有Class对象?

  1. 各种类(外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类)
  2. 接口
  3. 数组
  4. 注解
  5. 枚举
  6. 包装类(基本数据类型)
  7. void
  8. Object
  9. Class

类是如何加载的?

  1. 加载到内存,从方法区的类的信息加载到堆中,对应一个java.lang.class对象

  2. 链接,正式为类变量(static)分配内存并设置对应的初始值

  3. 初始化

    <clint>() {

    ​ 静态代码块

    ​ 静态变量赋值

    }

java.lang.class在从方法区到堆中生成

什么时候会发生类的初始化?

  1. 类的主动引用(一定会发生类的初始化)

    • 初始化main方法所在的类
    • new一个类的对象
    • 调用类的静态成员(除了final常量)和静态方法
    • 反射调用
    • 当初始化一个类,如果其父类没有被初始化,则会初始化它的父类
  2. 类的被动引用(不会发生类的初始化)

    • 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化

      Son.b (b是父类中的静态变量)
      
    • 通过数组定义类引用,不会触发此类的初始化

      Student[] arr = new Student[2];
      
    • 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

      Son.M	(M为该类的静态常量)
      

类加载器的作用

  • *.java->Java编译器->*.class->类加载器->字节码校验器->解释器->操作系统

  • 类加载器作用:将类(class)装载进内存。

    • 引导类加载器(rt.jar)
    • 扩展加载器
    • 系统加载器
  • 如何获取类加载器?

    public class Test {
    
    
    	public static void main(String[] args) throws ClassNotFoundException {
    
    		//获取系统类加载器
    		ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    		System.out.println(systemClassLoader);
    
    		//获取系统类加载器的父类加载器->拓展类加载器
    		ClassLoader parent = systemClassLoader.getParent();
    		System.out.println(parent);
    
    		//获取扩展类加载器的父类加载器->根加载器
    		ClassLoader parent1 = parent.getParent();
    		System.out.println(parent1);
    
    		//测试当前类由哪个类加载器加载
    		ClassLoader classLoader = Class.forName("com.tiko.Test").getClassLoader();
    		System.out.println(classLoader);
    
    		//测试JDK内置的类是由哪个加载器加载的
    		ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
    		System.out.println(classLoader1);
    
    		//如何获取系统类加载器可以加载的路径
    		String property = System.getProperty("java.class.path");
    		System.out.println(property);
    	}
    }
    
  • 双亲委派机制->多重检测,保证安全性

创建运行时类对象

获取运行时类的完整结构

  • 通过反射获取运行时类的完整结构

    public class Test {
    	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
    
    		User user = new User();
    		Class c1 = user.getClass();
    
    		System.out.println(c1.getName());
    
    		System.out.println(c1.getSimpleName());
    
    		Field[] fields = c1.getFields();
    		for (Field field : fields) {
    			System.out.println(fields);
    		}
    
    		Field[] declaredFields = c1.getDeclaredFields();
    		for (Field declaredField : declaredFields) {
    			System.out.println(declaredField);
    		}
    
    		Field name = c1.getDeclaredField("name");
    		System.out.println(name);
    
    		Method[] declaredMethods = c1.getDeclaredMethods();
    		for (Method declaredMethod : declaredMethods) {
    			System.out.println(declaredMethod);
    		}
            
            Constructor constructor = c1.getConstructor(String.class, int.class);
    		System.out.println(constructor);       
            //和其他方法,略去
    	}
    }
    

有了Class对象,能做什么?

通过Class对象来创建对象

public class Test {
	public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
		Class aClass = Class.forName("com.tiko.User");

		Object o = aClass.newInstance();//本质上是调用无参构造器

		System.out.println(o);
	}
}
public class Test {
	public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

		//使用构造器创建对象
		Class aClass = Class.forName("com.tiko.User");

		Constructor constructor = aClass.getConstructor(String.class, int.class);

		User zhangsan = (User)constructor.newInstance("zhangsan", 12);
		System.out.println(zhangsan);
	}
}

通过反射调用方法

  • invoke()
public class Test {
	public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

		//使用构造器创建对象
		Class aClass = Class.forName("com.tiko.User");

		Constructor constructor = aClass.getConstructor(String.class, int.class);

		User user1 = (User)constructor.newInstance("zhangsan", 12);

		//使用反射获取方法
		Method setName = aClass.getMethod("setName", String.class);

		//调用方法
		setName.invoke(user1, "张三");
		System.out.println(user1.getName());
	}
}

通过反射操作属性

public class Test {
	public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

		//使用构造器创 建对象
		Class aClass = Class.forName("com.tiko.User");

		Constructor constructor = aClass.getConstructor(String.class, int.class);

		User user1 = (User)constructor.newInstance("zhangsan", 12);

		Field name = aClass.getDeclaredField("name");

		name.set(user1,"zhangsan");
		System.out.println(user1.getName());//无法为private修饰,进行直接修改。若想修改,得关闭权限检测
	}
}
  • setAccessible()
public class Test {
	public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

		//使用构造器创建对象
		Class aClass = Class.forName("com.tiko.User");

		Constructor constructor = aClass.getConstructor(String.class, int.class);

		User user1 = (User)constructor.newInstance("zhangsan", 12);

		Field name = aClass.getDeclaredField("name");

        //关闭安全检测
		name.setAccessible(true);
		name.set(user1,"zhangsan");//若想修改,得关闭权限检测
		System.out.println(user1.getName());
	}
}

性能对比分析

  • 性能:普通调用>关闭检测的反射调用>反射
public class Test {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {

		//普通方式
		test1();

		//反射方式
		test2();

		//反射方式,且关闭检测
		test3();
	}

	public static void test1() {
		User user = new User();

		long start = System.currentTimeMillis();
		for (int i = 0; i < 100000000; i++) {
			user.getName();
		}
		long stop = System.currentTimeMillis();

		System.out.println(stop-start);

	}

	public static void test2() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {

		User user = new User();

		Class<?> aClass = Class.forName("com.tiko.User");

		Method getName = aClass.getMethod("getName", null);

		long start = System.currentTimeMillis();
		for (int i = 0; i < 100000000; i++) {
			getName.invoke(user, null);
		}
		long stop = System.currentTimeMillis();

		System.out.println(stop-start);
	}


	public static void test3() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {

		User user = new User();

		Class<?> aClass = Class.forName("com.tiko.User");

		Method getName = aClass.getMethod("getName", null);
		getName.setAccessible(true);

		long start = System.currentTimeMillis();
		for (int i = 0; i < 100000000; i++) {
			getName.invoke(user, null);
		}
		long stop = System.currentTimeMillis();

		System.out.println(stop-start);
	}
}

反射操作泛型(了解)

  • 泛型->约束机制
  1. ParameterizedType
  2. GenericType
  3. TypeVariable
  4. WildcardType
public class Test {
	public static void main(String[] args) throws NoSuchMethodException {

		Method method1 = Test.class.getMethod("method1", Map.class, List.class);

		Type[] genericParameterTypes = method1.getGenericParameterTypes();

		for (Type genericParameterType : genericParameterTypes) {
			System.out.println(genericParameterType);
			if (genericParameterType instanceof ParameterizedType){
				Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
				for (Type actualTypeArgument : actualTypeArguments) {
					System.out.println(actualTypeArgument);
				}
			}

		}



	}

	public void method1(Map<String, User> map, List<User> user) {}

}
public class Test {
	public static void main(String[] args) throws NoSuchMethodException {

		Method method2 = Test.class.getMethod("method2", null);

		Type genericReturnType = method2.getGenericReturnType();


		System.out.println(genericReturnType );
		if (genericReturnType  instanceof ParameterizedType){
			Type[] actualTypeArguments = ((ParameterizedType) genericReturnType ).getActualTypeArguments();
			for (Type actualTypeArgument : actualTypeArguments) {
				System.out.println(actualTypeArgument);
			}
		}
	}
	
	public Map<String, User> method2() {return null;}
}

反射操作注解

  • getAnnotations()

  • getAnnotaion()

  • ORM:对象关系映射

    1. 类和表名对应
    2. 属性和字段对应
    3. 对象和属性对应

利用注解和反射完成类和表结构的映射关系

//给类注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Tab_annotation{
	String value();
}

//给属性注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Col_annontation{
	String colname();
	String type();
	int length();
}
@Tab_annotation("tb_student")
public class Student {

	@Col_annontation(colname = "name", type = "varchar(20)", length = 10)
	private String name;

	@Col_annontation(colname = "id", type = "int", length = 10)
	private Integer id;

	@Col_annontation(colname = "age", type = "int", length = 10)
	private Integer age;

	public Student() {
	}

	public Student(String name, Integer id, Integer age) {
		this.name = name;
		this.id = id;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Integer getage() {
		return age;
	}

	public void setage(Integer age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student{" +
				"name='" + name + '\'' +
				", id=" + id +
				", age=" + age +
				'}';
	}
}
public class Test {
	public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException, NoSuchFieldException {

		Class<?> aClass = Class.forName("com.tiko.Student");

		//通过反射获取注解
		Annotation[] annotations = aClass.getAnnotations();
		for (Annotation annotation : annotations) {
			System.out.println(annotation);
		}

		//通过反射获取注解value的值
		Tab_annotation annotation = aClass.getAnnotation(Tab_annotation.class);//获取指定的注解
		String value = annotation.value();//根据注解获取对应的值
		System.out.println(value);

		//获得指定的注解的值
		Field field = aClass.getDeclaredField("name");//通过反射获取类中的属性
		Col_annontation annotation1 = field.getAnnotation(Col_annontation.class);//获取属性上的注解
		String colname = annotation1.colname();//获取注解上的值
		String type = annotation1.type();
		int length = annotation1.length();
		System.out.println(colname + ","+ type+ "," + length);
	}
}

参考自

posted @ 2020-02-26 20:55  tikoblog  阅读(597)  评论(0)    收藏  举报