12.javase-java基础语法-注解/反射

注解

一.为什么要开发.设计注解?
java支持注解是从JDK1.5之后开始的,为什么要设计注解,因为注解起到一个标识代码的作用,它配合反射,给JVM使用.将JAVA彻底的提升了一个台阶.

二.注解的格式

1.用@interface标识
2.添加元注解,修饰注解的注解叫元注解
3.属性用:属性类型 属性名(); 如:String value();
4.属性添加默认值用default 表示.

//@Target({ElementType.METHOD,ElementType.TYPE})注解有多个值时则用{值1,值2}
@Retention(RetentionPolicy.RUNTIME)//元注解,什么时候标注起作用
@Target(ElementType.METHOD)//元注解,标识本注解应用地方
@Documented//元注解,标识 生成javadoc文档的时候起作用
@interface Select{ //@interface 注解
	String value() default "gl"; //value为属性,不是方法.默认值,用default标识
}

三.元注解
1.Retention
英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。

它的取值如下:

RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

2.@Documented
顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。

3.@Target
Target 是目标的意思,@Target 指定了注解运用的地方。
你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。

ElementType.ANNOTATION_TYPE 可以给一个注解进行注解 ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE可以给一个类型进行注解,比如类、接口、枚举

4.@Repeatable
Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。

什么样的注解会多次应用呢?通常是注解的值可以同时取多个。
举个例子,一个人他既是程序员又是产品经理,同时他还是个画家。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Documented
@interface Persons {
    Person[]  value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Documented
@Repeatable(Persons.class)
@interface Person{
    String role() default "";
}

@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
}

反射

反射的作用:
反射的作用在于我们随时获取类的所有签名,这个在spring框架中发挥的淋漓尽致,因为我们对象的创建全部交给的spring框架.
1.什么对象需要交给框架,用注解标识.
2.编译器通过注解找到需要反射的类,在通过反射创建或者注入对象.这样就是spring框架的核心.
通过反射获取类.注解,字段,方法,构造方法在这里插入图片描述

//注解Controller,值是 人类
@Controller(value = "人类")
//类是Person
public class Person {
	//属性Field
	private String name;
	private int age;
	
	//构造Constructor
	public Person() {
		super();
		System.out.println("我是无参数的构造");
	}
	//带参数的构造Constructor
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
		System.out.println("我是有参数的构造方法");
	}
	
	//成员方法
	private int sum(int a,int b) {
		return a + b;
	}
}

		获取类
//方式一,通过对象获取
Person p = new Person("张三",35);
Class<?> clazz = p.getClass();
//方式二,通过类的全路径名获取
//这种方式会抛异常,因为你传的路径,可能不是类
String className = "cn.tedu.reflact.Person";
Class<?> clazz2 = Class.forName(className);
		
获取类的构造方法
//方式一无参构造,因为是无参数构造,所以不需要传参数
Constructor<?> constructor = clazz.getConstructor();
Person p2 = (Person)constructor.newInstance();
//方式二获取带参数的构造
Constructor<?> constructor2 = clazz.getConstructor(String.class,int.class);
//利用构造方法创建对象
Person p3 = (Person)constructor2.newInstance("李四",25);
		
		
获取类的注解
//获取单个注解,必须明确你要找的注解的名字,注意前后一致
Controller contro = clazz.getAnnotation(Controller.class);
//获取多个注解,不要导错包了.
Annotation[] annotationArray = clazz.getAnnotations();
		
		
//获取类的属性
Field f = clazz.getDeclaredField("name");
//设置属性的权限
f.setAccessible(true);
//获取Person对象的name字段,因为该字段是依附于对象存在的,所以要传对象参数
String name = (String) f.get(p);
System.out.println(name);
		
		
获取类的方法
//获取Person类的sum方法,带2个int类型参数和一个int类型的返回值
Method method = clazz.getDeclaredMethod("sum", 	int.class,int.class);
//设置方法的权限
method.setAccessible(true);
//因为这个方法依附于对象的,所以这里一定要传入一个对象参数
//并且因为这个sum方法时有返回值的,我用向下转型,强转成int类型
int sum =(int)method.invoke(p2, 10,20);
System.out.println(sum);
发布了42 篇原创文章 · 获赞 0 · 访问量 677

猜你喜欢

转载自blog.csdn.net/weixin_45449911/article/details/104435329