一. 注解
Java 定义了一套注解,共有10 个,6个在 java.lang 中,剩下 4 个在 java.lang.annotation(元注解) 中。
(1)作用在代码的注解是
@Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
@SuppressWarnings - 指示编译器去忽略注解中声明的警告。
@SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
@FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
@Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
(2)作用在其他注解的注解(或者说 元注解)是:
@Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
@Documented - 标记这些注解是否包含在用户文档中。
@Target - 标记这个注解可以修饰哪些 Java 成员。
@Inherited - 如果一个类用上了@Inherited修饰的注解,那么其子类也会继承这个注解
常用注解
@Documented 标记这些注解是否包含在用户文档中。
@Inherited 可以继承
/**
* @Retention()
*
* RetentionPolicy.SOURCE //源码级别保留,编译后即丢弃。
*
* RetentionPolicy.CLASS //编译级别保留,编译后的class文件中存在,在jvm运行时丢弃,这是默认值。
*
* RetentionPolicy.RUNTIME // 运行级别保留,编译后的class文件中存在,在jvm运行时保留,可以被反射调用。
*
* @Target()
*
* ElementType.TYPE //类,接口或者枚举
*
* ElementType.FIELD //域,包含枚举常量
*
* ElementType.METHOD //方法
*
* ElementType.PARAMETER //参数
*
* ElementType.CONSTRUCTOR //构造方法
*
* ElementType.LOCAL_VARIABLE //局部变量
*
* ElementType.ANNOTATION_TYPE //注解类型
*
* ElementType.PACKAGE //包
*
* ElementType.TYPE_PARAMETER //类型参数声明(1.8)
*
* ElementType.TYPE_USE //使用类型(1.8)
*/
@Target( {ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String name();
}
二.反射
修饰符在反射面前一文不值
注意我在这里用private修饰过的,在使用反射时可以拿到
这里先搞一个user类
package reflection;
import annotation.MyAnnotation;
import annotation.Singleton;
@Singleton
@MyAnnotation
public class User {
@MyAnnotation
public Integer ID;
private String name;
private Integer age;
@MyAnnotation
public User(Integer ID, String name, Integer age) {
this.ID = ID;
this.name = name;
this.age = age;
}
public User() {
}
public Integer getID() {
return ID;
}
public void setID(Integer ID) {
this.ID = ID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@MyAnnotation
public void eating(){
System.out.println("我正在吃");
}
private void eating(String FoodsName){
System.out.println("我正在吃"+FoodsName);
}
@Override
public String toString() {
return "User{" +
"ID=" + ID +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
然后在进行获取class对象进行使用
private修饰过的,依旧可以被搞定
package reflection;
import annotation.MyAnnotation;
import org.junit.Before;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
public class Test {
/**
* 0.创建拿到反射类
* 1.反射拿到成员变量
* 2.反射拿到成员方法
* 3.反射拿到构造器
* 4.反射拿到注解
*/
Class<User> clazz = null;
@Before
public void create() {
clazz = User.class;
}
@org.junit.Test
public void CreateReflection() throws ClassNotFoundException {
//使用类
Class<User> class1 = User.class;
//使用对象
User user = new User();
Class<? extends User> class2 = user.getClass();
//使用全类名
Class<?> class3 = Class.forName("reflection.User");
}
//对类对象的操作
@org.junit.Test
public void objectTest() throws InstantiationException, IllegalAccessException {
//获取类名字
String name = clazz.getName();
//获取类加载器
ClassLoader classLoader = clazz.getClassLoader();
//获取资源
URL resource = clazz.getResource("");
//得到父类
Class superclass = clazz.getSuperclass();
//判断一个类是不是接口,数组等等
boolean array = clazz.isArray();
boolean anInterface = clazz.isInterface();
//重点,使用class对象实例化一个对象
Object instance = clazz.newInstance();
}
//获取对象的操作
public void GetVariable() throws NoSuchFieldException {
//获取字段,只能获取公共的字段(public)
Field name = clazz.getField("name");
Field[] fields = clazz.getFields();
//能获取所有的字段包括private
Field ID = clazz.getDeclaredField("ID");
Field[] fields2 = clazz.getDeclaredFields();
}
//对类成员变量的操作
@org.junit.Test
public void variableTest() throws NoSuchFieldException, IllegalAccessException {
/**
* 成员变量与类方法,构造器大同小异
*/
User user = new User();
user.setAge(12);
user.setID(1);
user.setName("zhangsan");
Field id = clazz.getField("ID");
id.set(user, 2);
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(user, "lisi");
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);
age.set(user, 17);
System.out.println(user);
}
//对类成员方法的操作
@org.junit.Test
public void MethodTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
user.setID(12);
//获取某个方法,名字,后边是参数类型
Method method = clazz.getDeclaredMethod("eating", String.class);
method.setAccessible(true);
//拿到参数的个数
int parameterCount = method.getParameterCount();
//拿到方法的名字
String name = method.getName();
//拿到参数的类型数组
Class<?>[] parameterTypes = method.getParameterTypes();
//拿到返回值类型
Class<?> returnType = method.getReturnType();
//重点。反射调用方法,传一个实例,和参数
method.invoke(user, "热狗");
System.out.println(name);
}
//对类构造器的操作
@org.junit.Test
public void ConstructorTest() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Constructor[] constructors = clazz.getConstructors();
Constructor constructor = clazz.getConstructor(Integer.class, String.class, Integer.class);
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
Constructor declaredConstructor = clazz.getDeclaredConstructor();
User user = (User) constructor.newInstance(1, "lisi", 12);
System.out.println("User = " + user.getName());
}
//对注解的操作
@org.junit.Test
public void AnnoationTest() throws NoSuchFieldException, NoSuchMethodException {
//获取注解的名字
MyAnnotation declaredAnnotation = clazz.getAnnotation(MyAnnotation.class);
System.out.println("declaredAnnotation.name() = " + declaredAnnotation.name());
//拿到所有注解
Annotation annotation = clazz.getAnnotation(MyAnnotation.class);
Annotation[] annotations = clazz.getAnnotations();
//字段上
Field field = clazz.getDeclaredField("name");
Annotation annotation1 = field.getAnnotation(MyAnnotation.class);
Annotation[] annotations1 = field.getAnnotations();
//方法上
Method method = clazz.getDeclaredMethod("eating", String.class);
Annotation annotation2 = method.getAnnotation(MyAnnotation.class);
Annotation[] annotations2 = method.getAnnotations();
}
}
小案例
在以后学到框架的时候可以通过不同的注解来做具体的操作,
当前的具体实现小案例在SingletonHandler中只是具体的简单创造了一下实例,在以后的框架中会有更深层次的学习,装载在维护上下文的环境中
主函数
package reflection;
import context.ApplicationContext;
import handler.SingletonHandler;
import reflection.Utils.FileUtils;
import java.io.File;
import java.net.URL;
import java.util.List;
public class BootStrap {
//在类加载之后处理 启动慢 运行快
static {
//获得当前根路径的绝对路径(用来替换的工具)
final URL resource = Thread.currentThread().getContextClassLoader().getResource("");
List<String> classNames = FileUtils.getClassName(new File(resource.getFile()));
SingletonHandler.handler(classNames);
/**在这之前装填了所有属于当前根路径的class(添加了sington注解的)
* 维护在上下文中
*/
}
public static void main(String[] args) {
//这里直接可以通过方法拿到添加了sington注解的实例User的实例
User user = ApplicationContext.getSington(User.class);
System.out.println(user);
}
}
维护的上下文
package context;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ApplicationContext {
//维护一个上下文环境
public static final Map<Class<?>,Object> context=new ConcurrentHashMap<>();
//维护一个上下文
public static void addSington(Class<?> clazz,Object entity) {
ApplicationContext.context.put(clazz,entity);
}
//拿到上下文的实例
public static <T>T getSington(Class<?> clazz) {
return (T)ApplicationContext.context.get(clazz);
}
}
获取路径的工具包
package reflection.Utils;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class FileUtils {
//找绝对路径的文件名
private static void findclass(String path, List<String> classPathList) {
//拿到文件
File file = new File(path);
//文件化集合 并且过滤
File[] clazz = file.listFiles(((dir, name) -> new File(dir, name).isDirectory() || name.contains("class")));
//判断是否为空
if (clazz == null || clazz.length == 0) {
return;
}
//在不为空的情况下进行遍历
for (File list : clazz) {
if (list.isDirectory()) {
findclass(list.getAbsolutePath(), classPathList);
} else {
classPathList.add(list.getAbsolutePath());
}
}
}
public static List<String> getClassName(File file) {
List<String> classpaths = new ArrayList<>();
findclass(file.getAbsolutePath(), classpaths);
//[D:\ydl\practice\out\production\annotation\reflection\BootStrap.class,把这个绝对路径转换为全限定名称]
//用流做映射,转换函数给他返回出去为annotation.reflection.BootStrap
List<String> collect = classpaths.stream().map(path -> {
String fileName = file.getAbsolutePath();
return path.replace(fileName + "\\", "").replaceAll("\\\\", ".").replace(".class", "");
}).collect(Collectors.toList());
return collect;
}
}
单例注解
package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Singleton {
}
为了转载在上下文中的解析器
package handler;
import annotation.Singleton;
import context.ApplicationContext;
import java.util.List;
public class SingletonHandler {
public static void handler(List<String> classNames) {
for (String className : classNames) {
Class<?> clazz = null;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
assert clazz != null;
Singleton annotation = clazz.getDeclaredAnnotation(Singleton.class);
if (annotation != null) {
Object instance = null;
try {
instance = clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
ApplicationContext.addSington(clazz,instance);
}
}
}
}