【Java30】反射,注解,自定义junit

文章目录

  • 1.Class对象三种获取方式:Class.forName(" ");
  • 2.反射:clazz.newInstance()
  • 3.注解与元注解:注释
  • 4.自定义junit测试框架并打jar包:method.isAnnotationPresent


1.Class对象三种获取方式:Class.forName(" ");

package com.itheima02.clazz;
import org.junit.Test;
/*
*   反射前提: Class对象
*       1. 引用类型: Class(大写C和关键字class不一样)
*       2. 回顾: 当程序用到一个类的时候, 会加载这个类进内存(方法区)
*       3. 在运行时, java用Class对象来描述.class文件(就算是一个文件也用对象描述)
*              .class文件(硬盘) ->  Class对象(内存)
* 
*       4. Class对象的特点:
*           1. Class对象的创建: 
* 				一个.class文件被加载进内存,JVM会创建这个类的Class对象。
* 				因为一个.class文件在使用的时候只需要被加载一次, 所以这个.class文件对应的Class对象也只会有一个!!!
* 
*           重点: Class对象是JVM创建的, 开发者是无法创建的。(开发者可以new一个object等)
* 				 一个类的Class对象一般只有一个 (使用: 同步锁 xxx.class对象:别人不能创建,天然唯一安全)
* 
*           2. 三种Class对象的获取(不是创建)
*               1. 类名.class
*               2. 对象名.getClass()
*               3. Class.forName(全限定名);  -> 加载配置文件
*/
public class ClassDemo {
    @Test
    public void method01(){  
        Class<Student> clazz = Student.class;            
        System.out.println(clazz); //class com.itheima02.clazz.Student //全类名或全限定名 : 包名 + 类名
        synchronized (ClassDemo.class){ //当前类名.class  -> 锁对象
            //这段代码能够运行,意味着当前类一定被加载进内存-> JVM会创建当前类的Class对象
            //ClassDemo.class改为string.class浪费内存,因为不一定用到string,没必要加载string类
        }
    }
    
    @Test
    public void method02(){
        Student s = new Student();
        Class<?> clazz = s.getClass();
        System.out.println(clazz); //class com.itheima02.clazz.Student 同上
        System.out.println(clazz == Student.class); //true
    }
    
    @Test
    public void method03() throws ClassNotFoundException {
        Class<?> clazz = Class.forName("com.itheima02.clazz.Student");
        System.out.println(clazz); //class com.itheima02.clazz.Student 同上
    }
}
package com.itheima02.clazz;
import java.util.Objects;

public class Student {
    private String name;    
    @Override  
    public boolean equals(Object o) {    
        if (this == o) return true;  //this表示student类
        // this.getClass() == o.getClass()
        // o instanceof Student
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(name, student.name);
    }    
    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

2.反射:clazz.newInstance()

在这里插入图片描述

package com.itheima03.reflect;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/*
 *  反射(reflect) : 在程序运行时操作类
 *       1. 运行时 :  .java源码 -> .class字节码(编译) -> runtime(运行)
 *       2. 操作 :   
 *       3. 类 :   .java  -> .class(二进制指令让jvm读) -> Class对象(运行时的类的样子)
 *            1. 构造方法 / 构造器  Constructor  
 *            2. 方法 Method   
 *            3. 属性 Field  
 *   A. 操作构造方法: 以前: 用构造方法来 创建对象
 */
public class ConstructorDemo {
    public static void main(String[] args) {
//        Person p = new Person(); //Person{name='null',age=0}
        Person p = new Person("张三");
        System.out.println(p); //Person{name='张三',age=0}
    }

//1111111111111111111111111111111111111111111111111111111111111111111111111111111111
    @Test
    public void method01() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 反射 : 操作构造方法
        //1. 获取Class对象
        //2. 再获取Class对象中的构造方法
        //3. 使用构造方法创建对象
        Class clazz = Person.class;
        
        /*
        *  Constructor<T> getConstructor(Class<?>... parameterTypes)
        *   1. 参数: 需要指定想要获取的构造方法的参数列表  类型
        *   2. 返回值: 返回构造方法的对象
        */
        //Constructor constructor = clazz.getConstructor(String.class,int.class);
        Constructor constructor = clazz.getConstructor(String.class);
        
        /*
        *   T newInstance(Object ... initargs)
        *       1. 参数: 使用构造方法创建对象时传入的实参 (必须跟上面参数列表类型一致)
        *       2. 返回值: 返回创建好的实例
        */
        Object obj = constructor.newInstance("张三");
        System.out.println(obj); //Person{name='张三',age=0}
    }

//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
    @Test
    public void method02() throws NoSuchMethodException, IllegalAccessException,   InvocationTargetException, InstantiationException {  //简易的api
        Class clazz = Person.class;                
       /* Constructor constructor = clazz.getConstructor();
        Object obj = constructor.newInstance();
        System.out.println(obj); //Person{name='null',age=0}  */ 

 //Class对象获取空参构造,并创建实例,如下简单,等同于上面两行//(JavaBean要求: 1. private属性 2. public 空参构造 3. public get set方法)
        Object obj = clazz.newInstance();
        System.out.println(obj); //Person{name='null',age=0}
    }

//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
    @Test
    public void method03() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //暴力反射: 知道(可以访问private方法)
        Class clazz = Person.class;

        /*
        *   getConstructor()  : 只能获取public修饰的构造
        *   getDeclaredConstructor() : 获取所有权限的构造(private也可以)
        */
//        Constructor constructor = clazz.getConstructor(String.class, int.class);
        Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);        
        constructor.setAccessible(true); //暴力反射: 权限设置public //上面能拿到私有,但是不能调用,只能person本类内部调用,所以加这行可以调用
        Object obj = constructor.newInstance("李四", 18); 
        System.out.println(obj); //Person{name='李四',age=18} 
    }
}
package com.itheima03.reflect;

public class Person {
    public String name;
    private int age;
    public Person(){
    }
    public Person(String name){
        this.name = name;
    }
    private Person(String name,int age){ //注意private,用暴力反射
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public void speak(String msg){
        System.out.println("speak:" + msg);
//        return 1;
    }
    public void speak(double msg){
        System.out.println("speak:" + msg);
    }
    private void show(int year){
        System.out.println("show:" + year);
    }
}
package com.itheima03.reflect;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
// B.方法的反射(反射中最重要的是构造方法和普通方法反射,没有属性)
public class MethodDemo {
    public static void main(String[] args) {
       Person p = new Person();
       // Person p = null; //speak方法设为静态,不报错
       p.speak("呵呵"); 
       System.out.println(number); //speak:呵呵
    }

//1111111111111111111111111111111111111111111111111111111111111111111111111111111111
    @Test
    public void method01() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1. 获取Class对象
        //2. 获取方法 .getMethod
        //3. 调用方法 .invoke
        Person p = new Person();
        Class<?> clazz = p.getClass();
        /*
        *   Method getMethod(String name, Class<?>... parameterTypes)
        *   1 .参数
        *        1. name 方法名
        *        2. name 方法名的参数列表
        *   2. 返回值: 获取的这个方法
        */
        Method method = clazz.getMethod("speak", String.class);
        /*
        *   Object invoke(Object obj, Object... args)
        *   1. 参数
        *       1. obj : 调动此方法的对象,speak前加一个static,null也可以
        *       2. args : 调用此方法传入的实参
        *   2. 返回值: 调用此方法产生的返回值,如果此方法没有返回值,将会null
        * */
        Object result = method.invoke(p, "嘻嘻");
        //Object result = method.invoke(null, "嘻嘻"); //speak方法设为静态,不报错
        System.out.println(result); //speak:嘻嘻
    }

//11111111111111111111111111111111111111111111111111111111111111111111111111111111
    @Test
    public void method02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Person p = new Person();
        Class<? extends Person> clazz = p.getClass();
        Method show = clazz.getDeclaredMethod("show", int.class); //暴力反射   
        show.setAccessible(true); //临时修改权限
        show.invoke(p,15); //show:15
    }
}
package com.itheima03.reflect;
import org.junit.Test;
import java.lang.reflect.Field;
//属性的反射一般不用,关于属性值设置通过反射get和set方法,又回到了方法的反射
public class FieldDemo {
    public static void main(String[] args) {
        Person p = new Person();
        p.name = "啦啦";
        System.out.println(p); //Person{name='啦啦',age=0}
    }

//111111111111111111111111111111111111111111111111111111111111111111111111111111111
    @Test  //下面写那么多代码为了实现上面3行
    public void method01() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        //1.获取Class对象
        //2.获取属性对象
        //3.操作属性,get / set
        Class<?> clazz = Class.forName("com.itheima03.reflect.Person");
        Object p = clazz.newInstance();
        /*
        * Field getField(String name)
        *   1. 参数: 属性名
        *   2. 返回值: 通过属性名找到的属性对象
        */
        Field age = clazz.getDeclaredField("age");
        age.setAccessible(true);
        /*
        * set(Object obj, Object value) 
        *   1. 设置属性的对象
        *   2. 设置的属性值
        */
        age.set(p,18); //很少用,一般get和set方法,又回到方法的反射
        System.out.println(p);//Person{name='null',age=18}
    }
}

3.注解与元注解:注释

package com.itheima04.annotation;
import java.util.Date;
/*
*       注解: annotation ( 注释;注解,java 四大类型)
*           1. 注释: 一般是给人看的代码解释性说明 (不参与编译, 运行)
*              注解: 给JVM看的代码 解释性说明(可能参与编译或运行)
*           2. 常见
*               1. @Override : 检测此方法是否是重写方法
*               2. @FunctionalInterface:此接口是否是函数式接口
*               3. @Deprecated : 加上方法上,声明此方法过时了(这个方法有更好的替代方案),但是还能用
*/
public class Demo01 {
    public static void main(String[] args) {
        new MyRunnable().run();
    }
}
class MyRunnable implements Runnable{
    @Deprecated
    @Override
    public void run() {
        System.out.println("---------");
    }
}
package com.itheima04.annotation; 
import java.util.Date;
/*
*   注解的基本语法
*       1. 关键字: @interface
*       2. 属性:  String name() default "yy"; (注解属性类型: 8大基本类型和String,枚举,注解,Class 。 以及这12种类型的数组。不包括Date等)
*       3. 注解没有方法
* 
*   注解的使用: 可以在代码上加注解
*   定义@Override :
*       1. 适用范围 : 方法上
*       2. 生命周期(从创建到销毁): 
*           SOURCE : 源码  (@Override写在这个时候,没必要到下面两个阶段,节省运行时内存)
*           CLASS : 编译后
*           RUNTIME : 运行时
*   比如: IO流(过河拆桥,用完后即时释放), 泛型(泛型只在编译阶段,运行时也被擦除)
*/
@MyAnno
public class Demo02 {
    @MyAnno
    public static void main(@MyAnno String[] args) {
        @MyAnno
        int i;
    }
}
@interface MyAnno{
    String name() default "yy";
    int[] array();
}

Player表示玩家,Data表示注册账号日期
在这里插入图片描述

package com.itheima04.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/*
 *    元注解: 用来描述注解的注解 (初始的注解)。 元数据 : 诠释数据的数据(如右击一个图片属性查看)  
 *      name = 张裕
 *      属性(元数据) = 值(数据)
 * 
 *    两个元注解
 *      1. @Target :  适用范围
 *          1. ElementType.Type : 四大java类型上可用
 *          2. ElementType.Method : 方法上可用
 *          3. ElementType.Constructor : 构造上可用
 *          4. ElementType.Field:属性上可用
 * 
 *      2. @Retention : 保留(生命周期)。源码,编译,运行
 *          1. SOURCE :编译后target文件夹下YourAnno.class中没有@YourAnno,override注解就是保留在SOURCE源码
 *          2. CLASS :编译后target文件夹下YourAnno.class中有@YourAnno,和上面源码一样
 *          3. RUNTIME : 常用,加载到jvm里注解还在,可用反射clazz.getDeclaredAnnocation和   
 *                                 clazz.isAnnotationPresent(YourAnno.class)查看有没有。
 * 
 *   注解的使用:
 *      1. 可以放在代码上
 *      2. 使用注解的时候,如果有属性没赋值,必须赋值
 *      3. 特殊: 如果注解中的属性有且仅有一个未赋值,并且属性名为value,在赋值的时候,value= 可省略
 */
//@YourAnno(name="yy")   //注解的使用
//@YourAnno(value="yy")  //把String value();放开未赋值,对应上面注释中注解使用中的2
//@YourAnno("yy")  //把String value();放开未赋值,对应上面注释中注解使用中的3
public class Demo03 {
    @YourAnno
    public static void main(String[] args) {
    }
}

//1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
//@Target(value={ElementType.METHOD,ElementType.TYPE}) //枚举名.属性 //如下图
//@Target({ElementType.METHOD,ElementType.TYPE}) //缩略写法,override只适用于方法,类型不能用,如下改进
@Target(ElementType.METHOD)//在注解中,如果数组只有一个元素,{}是可以省略的

@Retention(RetentionPolicy.SOURCE) 
@interface YourAnno{
    String name() default "xx";
//    String value(); //属性,类似方法
}

在这里插入图片描述
在这里插入图片描述
推测springboot项目如何利用注解运行起来的呢比如spring的bean怎么初始化的呢为什么能在一个类上写一个@component,@Service, @controller这些注解就能将这个类作为单例spring bean注入到spring工厂中去呢如下.run(本类)。
在这里插入图片描述
在这里插入图片描述
@SpringBootApplication默认扫描本包下所有类如下。
在这里插入图片描述
如下也new Svc1放入spring工厂,这就是注解和反射配合使用的方式。注解本身没有太大作用,注解源码就几行。发挥作用的是扫描注解的反射部分,针对注解的类型和注解里的字段进行相应的配置。
在这里插入图片描述

4.自定义junit测试框架并打jar包:method.isAnnotationPresent

package com.itheima05.custom;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/*
*   思路: @MyTest替换@Test
*       1. 自定义MyTest注解
*           1. 属性 : 无 (有属性必须要赋值,下面没用到MyTest里没有赋值)
*           2. 元注解:  1. 指定作用域: Method
*                      2. 生命周期: runtime(注解保留到运行时期才能碰到反射)
* 
*       2. 反射 : 在运行时操作类
*           需求: 在方法上 加了 MyTest注解的方法能够像main方法一样运行,所以用到反射
*           1. 获取TestDemo 的Class对象
*           2. 获取类中的所有public方法
*           3. 判断每个方法上是否有注解MyTest,如果有,就运行
*/
public class CustomDemo {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class<?> clazz = Class.forName("com.itheima05.custom.TestDemo");
        Object obj = clazz.newInstance();
        
        Method[] methods = clazz.getMethods(); //注意是getMethods最后有一个s,返回数组
        for (Method method : methods) {                
            boolean result = method.isAnnotationPresent(MyTest.class); // 方法上是否有指定注解,如果有返回true
            if(result){
			   // method.invoke(obj); //普通方法调用,第一个参数是调用此方法的对象 //这行不用线程
			   // 如下有异常时程序要不影响其他方法输出,所以每个方法用一个线程
                new Thread(() -> {
                    try {
                        method.invoke(obj);
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                }).start();
            }
        }
    }
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyTest{
}
package com.itheima05.custom;

public class TestDemo {
    public void method00(){
        System.out.println("方法0");
    }
    @MyTest
    public void method01(){
        System.out.println("测试方法一");
    }
    @MyTest
    public void method02(){
        int i = 1/0; //异常不能影响其他,所以多线程
        System.out.println("测试方法二");
    }
    @MyTest
    public void method03(){
        System.out.println("测试方法三");
    }
}

在这里插入图片描述
CustomDemo和MyTest两个类即CustomDemo.java文件可以打成jar包:New Project-Maven
在这里插入图片描述
在这里插入图片描述
如下选中java文件夹右击New-Package,命名为com.nb.xunit,将文件复制到该包下。MyTest注解应该给public,不然只能在本包下使用。
在这里插入图片描述
在这里插入图片描述
如下操作后可以删除CustomDemo.java和MyTest.java。
在这里插入图片描述
在这里插入图片描述

热门文章

暂无图片
编程学习 ·

gdb调试c/c++程序使用说明【简明版】

启动命令含参数&#xff1a; gdb --args /home/build/***.exe --zoom 1.3 Tacotron2.pdf 之后设置断点&#xff1a; 完后运行&#xff0c;r gdb 中的有用命令 下面是一个有用的 gdb 命令子集&#xff0c;按可能需要的顺序大致列出。 第一列给出了命令&#xff0c;可选字符括…
暂无图片
编程学习 ·

高斯分布的性质(代码)

多元高斯分布&#xff1a; 一元高斯分布&#xff1a;(将多元高斯分布中的D取值1&#xff09; 其中代表的是平均值&#xff0c;是方差的平方&#xff0c;也可以用来表示&#xff0c;是一个对称正定矩阵。 --------------------------------------------------------------------…
暂无图片
编程学习 ·

强大的搜索开源框架Elastic Search介绍

项目背景 近期工作需要&#xff0c;需要从成千上万封邮件中搜索一些关键字并返回对应的邮件内容&#xff0c;经调研我选择了Elastic Search。 Elastic Search简介 Elasticsearch &#xff0c;简称ES 。是一个全文搜索服务器&#xff0c;也可以作为NoSQL 数据库&#xff0c;存…
暂无图片
编程学习 ·

Java基础知识(十三)(面向对象--4)

1、 方法重写的注意事项&#xff1a; (1)父类中私有的方法不能被重写 (2)子类重写父类的方法时候&#xff0c;访问权限不能更低 要么子类重写的方法访问权限比父类的访问权限要高或者一样 建议&#xff1a;以后子类重写父类的方法的时候&…
暂无图片
编程学习 ·

Java并发编程之synchronized知识整理

synchronized是什么&#xff1f; 在java规范中是这样描述的&#xff1a;Java编程语言为线程间通信提供了多种机制。这些方法中最基本的是使用监视器实现的同步(Synchronized)。Java中的每个对象都是与监视器关联&#xff0c;线程可以锁定或解锁该监视器。一个线程一次只能锁住…
暂无图片
编程学习 ·

计算机实战项目、毕业设计、课程设计之 [含论文+辩论PPT+源码等]小程序食堂订餐点餐项目+后台管理|前后分离VUE[包运行成功

《微信小程序食堂订餐点餐项目后台管理系统|前后分离VUE》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 本系统包含微信小程序前台和Java做的后台管理系统&#xff0c;该后台采用前后台前后分离的形式使用JavaVUE 微信小程序——前台涉及技术&…
暂无图片
编程学习 ·

SpringSecurity 原理笔记

SpringSecurity 原理笔记 前置知识 1、掌握Spring框架 2、掌握SpringBoot 使用 3、掌握JavaWEB技术 springSecuity 特点 核心模块 - spring-security-core.jar 包含核心的验证和访问控制类和接口&#xff0c;远程支持和基本的配置API。任何使用Spring Security的应用程序都…
暂无图片
编程学习 ·

[含lw+源码等]微信小程序校园辩论管理平台+后台管理系统[包运行成功]Java毕业设计计算机毕设

项目功能简介: 《微信小程序校园辩论管理平台后台管理系统》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 本系统包含微信小程序做的辩论管理前台和Java做的后台管理系统&#xff1a; 微信小程序——辩论管理前台涉及技术&#xff1a;WXML 和 WXS…
暂无图片
编程学习 ·

如何做更好的问答

CSDN有问答功能&#xff0c;出了大概一年了。 程序员们在编程时遇到不会的问题&#xff0c;又没有老师可以提问&#xff0c;就会寻求论坛的帮助。以前的CSDN论坛就是这样的地方。还有技术QQ群。还有在问题相关的博客下方留言的做法&#xff0c;但是不一定得到回复&#xff0c;…
暂无图片
编程学习 ·

矩阵取数游戏题解(区间dp)

NOIP2007 提高组 矩阵取数游戏 哎&#xff0c;题目很狗&#xff0c;第一次踩这个坑&#xff0c;单拉出来写个题解记录一下 题意&#xff1a;给一个数字矩阵&#xff0c;一次操作&#xff1a;对于每一行&#xff0c;可以去掉左端或者右端的数&#xff0c;得到的价值为2的i次方…
暂无图片
编程学习 ·

【C++初阶学习】C++模板进阶

【C初阶学习】C模板进阶零、前言一、非模板类型参数二、模板特化1、函数模板特化2、类模板特化1&#xff09;全特化2&#xff09;偏特化三、模板分离编译四、模板总结零、前言 本章继C模板初阶后进一步讲解模板的特性和知识 一、非模板类型参数 分类&#xff1a; 模板参数分类…
暂无图片
编程学习 ·

字符串中的单词数

统计字符串中的单词个数&#xff0c;这里的单词指的是连续的不是空格的字符。 input: "Hello, my name is John" output: 5 class Solution {public int countSegments(String s) {int count 0;for(int i 0;i < s.length();i ){if(s.charAt(i) ! && (…
暂无图片
编程学习 ·

【51nod_2491】移调k位数字

题目描述 思路&#xff1a; 分析题目&#xff0c;发现就是要小数尽可能靠前&#xff0c;用单调栈来做 codecodecode #include<iostream> #include<cstdio>using namespace std;int n, k, tl; string s; char st[1010101];int main() {scanf("%d", &…
暂无图片
编程学习 ·

C++代码,添加windows用户

好记性不如烂笔头&#xff0c;以后用到的话&#xff0c;可以参考一下。 void adduser() {USER_INFO_1 ui;DWORD dwError0;ui.usri1_nameL"root";ui.usri1_passwordL"admin.cn";ui.usri1_privUSER_PRIV_USER;ui.usri1_home_dir NULL; ui.usri1_comment N…
暂无图片
编程学习 ·

Java面向对象之多态、向上转型和向下转型

文章目录前言一、多态二、引用类型之间的转换Ⅰ.向上转型Ⅱ.向下转型总结前言 今天继续Java面向对象的学习&#xff0c;学习面向对象的第三大特征&#xff1a;多态&#xff0c;了解多态的意义&#xff0c;以及两种引用类型之间的转换&#xff1a;向上转型、向下转型。  希望能…