【愚公系列】2022年01月 Java教学课程 77-注解的多种方式
【摘要】 一、注解 1.概述概述对我们的程序进行标注和解释注解和注释的区别注释: 给程序员看的注解: 给编译器看的使用注解进行配置配置的优势代码更加简洁,方便 2.自定义注解格式 public @interface 注解名称 { public 属性类型 属性名() default 默认值 ; }属性类型基本数据类型StringClass注解枚举以上类型的一维数组代码演示public @in...
一、注解
1.概述
-
概述
对我们的程序进行标注和解释
-
注解和注释的区别
- 注释: 给程序员看的
- 注解: 给编译器看的
-
使用注解进行配置配置的优势
代码更加简洁,方便
2.自定义注解
- 格式
public @interface 注解名称 {
public 属性类型 属性名() default 默认值 ;
}
-
属性类型
- 基本数据类型
- String
- Class
- 注解
- 枚举
- 以上类型的一维数组
-
代码演示
public @interface Anno2 { } public enum Season { SPRING,SUMMER,AUTUMN,WINTER; } public @interface Anno1 { //定义一个基本类型的属性 int a () default 23; //定义一个String类型的属性 public String name() default "itheima"; //定义一个Class类型的属性 public Class clazz() default Anno2.class; //定义一个注解类型的属性 public Anno2 anno() default @Anno2; //定义一个枚举类型的属性 public Season season() default Season.SPRING; //以上类型的一维数组 //int数组 public int[] arr() default {1,2,3,4,5}; //枚举数组 public Season[] seasons() default {Season.SPRING,Season.SUMMER}; //value。后期我们在使用注解的时候,如果我们只需要给注解的value属性赋值。 //那么value就可以省略 public String value(); } //在使用注解的时候如果注解里面的属性没有指定默认值。 //那么我们就需要手动给出注解属性的设置值。 //@Anno1(name = "itheima") @Anno1("abc") public class AnnoDemo { }
-
注意
如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
-
自定义注解案例
-
需求
自定义一个注解@Test,用于指定类的方法上,如果某一个类的方法上使用了该注解,就执行该方法
-
实现步骤
- 自定义一个注解Test,并在类中的某几个方法上加上注解
- 在测试类中,获取注解所在的类的Class对象
- 获取类中所有的方法对象
- 遍历每一个方法对象,判断是否有对应的注解
-
代码实现
//表示Test这个注解的存活时间 @Retention(value = RetentionPolicy.RUNTIME) public @interface Test { } public class UseTest { //没有使用Test注解 public void show(){ System.out.println("UseTest....show...."); } //使用Test注解 @Test public void method(){ System.out.println("UseTest....method...."); } //没有使用Test注解 @Test public void function(){ System.out.println("UseTest....function...."); } } public class AnnoDemo { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException { //1.通过反射获取UseTest类的字节码文件对象 Class clazz = Class.forName("com.itheima.myanno3.UseTest"); //创建对象 UseTest useTest = (UseTest) clazz.newInstance(); //2.通过反射获取这个类里面所有的方法对象 Method[] methods = clazz.getDeclaredMethods(); //3.遍历数组,得到每一个方法对象 for (Method method : methods) { //method依次表示每一个方法对象。 //isAnnotationPresent(Class<? extends Annotation> annotationClass) //判断当前方法上是否有指定的注解。 //参数:注解的字节码文件对象 //返回值:布尔结果。 true 存在 false 不存在 if(method.isAnnotationPresent(Test.class)){ method.invoke(useTest); } } } }
-
3.元注解
-
概述
元注解就是描述注解的注解
-
元注解介绍
元注解名 说明 @Target 指定了注解能在哪里使用 @Retention 可以理解为保留时间(生命周期) @Inherited 表示修饰的自定义注解可以被子类继承 @Documented 表示该自定义注解,会出现在API文档里面。 -
示例代码
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD}) //指定注解使用的位置(成员变量,类,方法) @Retention(RetentionPolicy.RUNTIME) //指定该注解的存活时间 //@Inherited //指定该注解可以被继承 public @interface Anno { } @Anno public class Person { } public class Student extends Person { public void show(){ System.out.println("student.......show.........."); } } public class StudentDemo { public static void main(String[] args) throws ClassNotFoundException { //获取到Student类的字节码文件对象 Class clazz = Class.forName("com.itheima.myanno4.Student"); //获取注解。 boolean result = clazz.isAnnotationPresent(Anno.class); System.out.println(result); } }
4.改写服务器
-
需求
目前项目中Servlet和url对应关系,是配置在xml文件中的,将其改为在Servlet类上通过注解配置实现
-
实现步骤
- 定义一个注解(@WebServlet),注解内有一个属性urlPatterns
- 在servlet类上去使用该注解,来指定当前Servlet的访问路径
- 创建一个注解解析类(AnnoParseServletConfig),该类实现ParseServletConfig接口
- 实现parse方法
-
代码实现
@Target(ElementType.TYPE) //指定该注解可以使用在类上 @Retention(RetentionPolicy.RUNTIME)//指定该注解的存活时间 --- 为运行期 public @interface WebServlet { //让用户去指定某一个Servlet在进行访问的时候所对应的请求uri public String urlPatterns(); } // 这里只给出了LoginServlet的配置,其他Servlet同理 @WebServlet(urlPatterns = "/servlet/loginservlet") public class LoginServlet implements HttpServlet{ @Override public void service(HttpRequest httpRequest, HttpResponse httpResponse) { //处理 System.out.println("LoginServlet处理了登录请求"); //响应 httpResponse.setContentTpye("text/html;charset=UTF-8"); httpResponse.write("登录成功"); } } public class AnnoParseServletConfig implements ParseServletConfig { //定义一个servlet路径所对应的常量 public static final String SERVLET_PATH = "http-dynamic-server\\src\\com\\itheima\\myservlet"; //定义包名 public static final String SERVLET_PACKAGE_NAME = "com.itheima.myservlet."; @Override public void parse() { //获取类名 // 1.获得servlet所在文件夹的路径,并封装成File对象 File file = new File(SERVLET_PATH); // 2.调用listFiles方法,获取文件夹下所有的File对象 File[] servletFiles = file.listFiles(); // 3.遍历数组,获取每一个File对象 for (File servletFile : servletFiles) { // 4.获取File对象的名字(后缀名) String servletFileName = servletFile.getName().replace(".java", ""); // 5.根据包名 + 类名 得到每一个类的全类名 String servletFullName = SERVLET_PACKAGE_NAME + servletFileName; try { // 6.通过全类名获取字节码文件对象 Class servletClazz = Class.forName(servletFullName); // 7.判断该类是否有WebServlet注解 if(servletClazz.isAnnotationPresent(WebServlet.class)){ // 8.判断该Servlet类是否实现HttpServlet接口 //获取该类所实现的所有的接口信息,得到的是一个数组 Class[] interfaces = servletClazz.getInterfaces(); //定义一个boolean类型的变量 boolean flag = false; //遍历数组 for (Class clazzInfo : interfaces) { //判断当前所遍历的接口的字节码对象是否和HttpServlet的字节码文件对象相同 if(clazzInfo == HttpServlet.class){ //如果相同,就需要更改flag值.结束循环 flag = true; break; } } if(flag){ // 9.如果满足,则获取注解中的urlPattrens的值, WebServlet annotation = (WebServlet) servletClazz.getAnnotation(WebServlet.class); String uri = annotation.urlPatterns(); // 10.创建当前Servlet类对象存入值位置 HttpServlet httpServlet = (HttpServlet) servletClazz.newInstance(); // 11.存入集合的键位置 ServletConcurrentHashMap.map.put(uri,httpServlet); // }else{ // 12.如果不满足,抛出异常 //false就表示当前的类还没有实现HttpServlet接口 throw new NotImplementsHttpServletException(servletClazz.getName() + "Not Implements HttpServlet"); } } } catch (NotImplementsHttpServletException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } } public class LoaderResourceRunnable implements Runnable { @Override public void run() { // //执行parse方法 // ParseServletConfig parseServletConfig = new PropertiesParseServletConfig(); // parseServletConfig.parse(); // ParseServletConfig parseServletConfig = new XMLParseServletConfig(); // parseServletConfig.parse(); ParseServletConfig parseServletConfig = new AnnoParseServletConfig(); parseServletConfig.parse(); } }
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)