Junit、反射和注解

Junit,反射和注解

一:Junit

1.1:Junit

Junit:单元测试框架
框架:把一些工具类,抽象类,接口,以及他们的实现集中在一起,完成某个人功能,具有高通用性。
Junit框架:可以执行没有main方法的方法(测试方法)。

具体的格式:
	@Test
    public void print3(){
        System.out.println("Test2");
    }

1.2:Junit怎么用

a:使用测试方法的注意
	修饰符必须是public 返回值必须是void
	
b:执行
	具体方法名右击,执行某一个方法。
	空白处右击,执行整个类的测试方法。

c:常用注解
	@Before:在每个测试方法之前都会运行一次
	@After:在每个测试方法运行以后运行的方法
	具体的格式:
		public class Demo02 {
	
	    @Before
	    public void print(){
	        System.out.println("before");
	    }
	    @After
	    public void print1(){
	
	        System.out.println("after");
	    }
	
	    @Test
	    public void print2(){
	        System.out.println("Test1");
	    }
	
	    @Test
	    public void print3(){
	        System.out.println("Test2");
	    }	
	  }	
d:Junit框架组成:反射 + 注解;

二:反射

2.1:反射的概述

	反射是一种机制,利用该机制可以在程序运行过程中对类进行
解剖并操作类中的方法,属性,构造方法等成员(获取类的信息)。

2.2:获取Class对象的三种方法

a:Class对象是
	字节码文件被加载到方法区之后,立马就会在堆内存中生成唯一的一个该字节码
	的描述对象(Class对象)。
	
b:三种方式
	  Class c = Student.class;通过类名.class获取
	  Class c = stu.getClass();通过Object类的成员方法getClass()方法
	  Class c = Class.forName("java.lang.String");通过全类名进行查找
	  具体的实现:
		  public static void main(String[] args) throws ClassNotFoundException {
	        //Class对象的三种获取方式
	        //Class对象三种方式生成的对象是一个吗?
	        //1.静态方法
	        Class class1 = Class.forName("com.itheima.javabean.Student");
	        //2.类名获取
	        Class class2 = Student.class;
	        //通过对象进行获取
	        Student student = new Student();
	        Class class3 = student.getClass();
	        
			//同一个字节码文件产生的Class对象永远相同。
	        System.out.println(class1 == class2);
	        System.out.println(class3 == class2);
	     }

2.3:预定义对象

a:预定义对象的定义
	一些没有.class文件仍然有Class对象;8大基本数据类型,及其数组,void。
b:具体实现
	 public static void main(String[] args) {
	        //8大基本数据类型
	        Class intClass = int.class;
	        Class charClass = char.class;
	        Class shortClass = short.class;
	        Class byteClass = byte.class;
	        Class longClass = long.class;
	
	        Class floatClass = float.class;
	        Class doubleClass = double.class;
	        Class booleanClass = boolean.class;
	
	        //void获取Class对象
	        Class voidClass = void.class;
	        
	        //数据获取Class对象
	        int[] i = new int[10];
	        char[] c = new char[10];
	        Class aClass = i.getClass();
	        Class aClass1 = c.getClass();
	    }

2.3:获取Class对象的信息

a:方法
	String getSimpleName(); 获得简单类名,只是类名,没有包
	String getName(); 获取完整类名,包含包名+类名
	T newInstance() ;创建此 Class 对象所表示的类的一个新实例。
					 要求:类必须有public的无参数构造方法
b:代码
	// 获得字符串的Class对象
	Class c = Class.forName("java.lang.String");
	
	// 获得简单类名
	String simplename = c.getSimpleName();
	// 打印输入:simplename = String
	
	// 获得完整类名(包含包名和类名)
	String name = c.getName();
	// 打印输入:name = java.lang.String
	
	// 创建字符串对象
	String str = (String) c.newInstance();
	// 输出str:空字符串 ""

2.4:获取Class对象的构造方法(Constructor)

a:获取单个构造方法
	1. Constructor getConstructor(Class... parameterTypes) 
		根据参数类型获取构造方法对象,只能获得public修饰的构造方法。
		如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
	
	2. Constructor getDeclaredConstructor(Class... parameterTypes)
		根据参数类型获取构造方法对象,包括private修饰的构造方法。
		如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
		
b:获取多个构造方法
	3. Constructor[] getConstructors()
		获取所有的public修饰的构造方法
		
	4. Constructor[] getDeclaredConstructors()
		获取所有构造方法,包括privat修饰
		
c:Constructor类中常用方法
	T newInstance(Object... initargs)根据指定参数创建对象。
	void setAccessible(true) 暴力反射,设置为可以直接访问私有类型的构造方法
	
	实例:
		//获取构造器方法
		
        Class class1 = Student.class;
        //根据参数类型获取某个构造方法
        Constructor constructor1 = class1.getConstructor(String.class,int.class);
        Constructor declaredConstructor = class1.getDeclaredConstructor(int.class);

        //获取所有的public构造方法
        Constructor[] constructors = class1.getConstructors();
        //获取所有的够着方法
        Constructor[] declaredConstructors = class1.getDeclaredConstructors();

        //根据构造器创建对象
        Object o = constructor1.newInstance("张三",13);
        System.out.println(o);

        //将这个declaredConstructors设置可以访问。
        declaredConstructor.setAccessible(true);
        //如果没有上一步会发生 java.lang.IllegalAccessException异常
        Object o1 = declaredConstructor.newInstance(13);
        System.out.println(o1);
	

2.5:获取Class对象的成员方法(Method)

a:获取单个方法
	1. Method getMethod("方法名", 方法的参数类型... 类型)
	根据方法名和参数类型获得一个方法对象,只能是获取public修饰的
	
	2. Method getDeclaredMethod("方法名", 方法的参数类型... 类型)
	根据方法名和参数类型获得一个方法对象,包括private修饰的
	
b:获取所有的方法
	3. Method[] getMethods() (了解)
	获取所有的public修饰的成员方法,包括父类中。
	
	4. Method[] getDeclaredMethods() (了解)
	获取当前类中所有的方法,包含私有的,不包括父类中
	
	
c:Method类中常用的方法
	1.Object invoke(Object obj, Object... args)
		根据参数args调用对象obj的该成员方法
		如果obj=null,则表示该方法是静态方法
	
	2. void setAccessible(boolean flag)
		暴力反射,设置为可以直接调用私有修饰的成员方法

	例子:
 		//通过反射获取方法对象
        Class class1 = Student.class;
        Method study1 = class1.getMethod("study");
        Method study = class1.getDeclaredMethod("study",int.class);

        Method[] methods = class1.getMethods();
        Method[] declaredMethods = class1.getDeclaredMethods();

        //使用方法
        study.setAccessible(true);
        Object o = study.invoke(class1.newInstance(), 19);

2.6:获取对象的成员变量信息(Field)

a:获取单个属性值
	1. Field getDeclaredField(String name)
	根据属性名获得属性对象,包括private修饰的
	2. Field getField(String name)
	根据属性名获得属性对象,只能获取public修饰的
b:获取多个属性值
	3. Field[] getFields()
	获取所有的public修饰的属性对象,返回数组。
	4. Field[] getDeclaredFields()
	获取所有的属性对象,包括private修饰的,返回数组。
c:Field类中常用方法
	void set(Object obj, Object value)
	void setInt(Object obj, int i)
	void setLong(Object obj, long l)
	void setBoolean(Object obj, boolean z)
	void setDouble(Object obj, double d)
	Object get(Object obj)
	int getInt(Object obj)
	long getLong(Object obj)
	boolean getBoolean(Object ob)
	double getDouble(Object obj)
	void setAccessible(true);暴力反射,设置为可以直接访问
	Class getType(); 获取属性的类型,返回Class对象
	
	setXxx方法都是给对象obj的属性设置使用,针对不同的类型选取不同的方法。
	getXxx方法是获取对象obj对应的属性值的,针对不同的类型选取不同的方法

	实例:
	    Student student = new Student();
        Class clazz = student.getClass();
        //获取属性对象
        Field nameField = clazz.getDeclaredField("name");
        //属性可以赋值set和取值get
        nameField.set(student,"杨幂");
        System.out.println(student);

        Object o = nameField.get(clazz.newInstance());
		// Object o = nameField.get(student);
        System.out.println(o);//null

三:注解

3.1:注解的概述

a:概念
	注解是JDK1.5的特性。
	注解相当一种标记,是类的组成部分,可以给类携带一些额外的信息。
	标记(注解)可以加在包,类,字段,方法,方法参数以及局部变量上。
	注解是给编译器或JVM看的,编译器或JVM可以根据注解来完成对应的功能。
	
b:常见注解
1. @Override :用来修饰方法声明,告诉编译器该方法是重写父类中的方法
						  如果父类不存在该方法,则编译失败。
2. @Deprecated:用来表示不赞成使用

3.2:自定义注解

a:格式:
	public @interface Book {
		// 书名
		String value();
		// 价格
		double price() default 100;
		// 多位作者
		String[] authors();
	}
	
	public class BookShelf {
		@Book(value = "西游记",price = 998,authors = {"吴承恩","白求恩"})
		public void showBook(){
		}
	 }

b:自定义的注解属性的类型。
	八种基本数据类型(int,float,boolean,byte,double,char,long,short)
	String类型,Class类型,枚举类型,注解类型;以及以上所有类型的一维数组
	
c:使用注解的注意
	如果属性有默认值,则使用注解的时候,这个属性可以不用赋值,也可以覆盖。
	如果属性没有默认值,那么在使用注解时一定要给属性赋值。
	当只对名称是value赋值,在使用注解时给value属性赋值
	可以直接给属性值。
		public @interface Book {
			// 书名
			String value();
			}
			// 使用注解Book
			public class BookShelf {
			@Book("西游记")
			public void showBook(){
			}
		 }

3.3:注解之元注解

a:概述
	Java API提供的注解
	专门用来定义注解的注解。
	任何Java官方提供的非元注解的定义中都使用到了元注解

b:常用原注解
	@Target
		作用:指明此注解用在哪个位置,如果不写默认是任何地方都可以使用。
		可选的参数值在枚举类型RetentionPolicy中包括
			TYPE: 用在类,接口上
			FIELD:用在成员变量上
			METHOD: 用在方法上
			PARAMETER:用在参数上
			CONSTRUCTOR:用在构造方法上
			LOCAL_VARIABLE:用在局部变量上
		
	@Retention
		作用:定义该注解的生命周期(有效范围)
		可选的参数值在枚举类型RetentionPolicy中包括
			SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了。
			CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存
					中没有,默认值。
			RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存
					 中,程序可以通过反射获取该注解。

3.4:注解的案例

在这里插入图片描述

3.4:注解的解析

a:概念
	通过Java技术获取注解数据的过程则称为注解解析
b:注解相关的接口
	Anontation:所有注解类型的公共接口,类似所有类的父类是Object。
	AnnotatedElement:是Anontation的子接口,定义了与注解解析相关的方法 。
	AnnotatedElement的实现类:Class Constructor Field Method)常用方法以下四个方法。
	
	boolean isAnnotationPresent(Class annotationClass); 判断当前对象是否有指定的注解
														,有则返回true,否则返回false。
	T getAnnotation(Class<T> annotationClass); 获得当前对象上指定的注解对象。
	Annotation[] getAnnotations(); 获得当前对象及其从父类上继承的所有的注解对象。
	Annotation[] getDeclaredAnnotations();获得当前对象上所有的注解对象,不包括父类的。
	
	 AnnotatedElement:定义了与注解解析相关的方法,常用方法以下四个:
  

c:获取注解的原理
	注解作用在那个成员上,就通过反射获得该成员的对象来得到它的注解。

	具体步骤:
		注解在方法上
			// 得到方法对象
			Method method = clazz.getDeclaredMethod("方法名");
			// 根据注解名得到方法上的注解对象
			Book book = method.getAnnotation(Book.class);
		注解在类上
			// 获得Class对象
			Class c = 类名.class;
			// 根据注解的Class获得使用在类上的注解对象
			Book book = c.getAnnotation(Book.class);
实例:
 		//使用反射,将Student类的私有的method方法上的注解中
 		//的name属性值,赋值method方法并执行
        Class clazz = Student.class;
        Method method = clazz.getDeclaredMethod("method", String.class);
        //判断下该方法对象上有没有指定的注解MyAnnotation
        boolean result = method.isAnnotationPresent(MyAnnotation.class);
        System.out.println(result);
        if (result) {
            //获取该注解
            MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
            System.out.println(annotation.name());
            System.out.println(annotation.value());
            method.setAccessible(true);
            Object invoke = method.invoke(clazz.newInstance(), annotation.name());
            System.out.println(invoke);
		}

3.5:自定义简单的Junit框架

a:
	@Target(value = {ElementType.METHOD})
	@Retention(RetentionPolicy.RUNTIME)
	public @interface MyTest {
	}

b:
	{
        Class clazz = Test.class;

        Method[] methods = clazz.getMethods();//获取指定Class对象中的所有的public方法
        System.out.println(methods.length);

        for (Method method : methods) {
            if (method.isAnnotationPresent(MyTest.class)) {
                method.invoke(clazz.newInstance());
            }
        }
    }

3.6:自定义高通用性的解析代码

public class Demo {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        //将Map集合转换成一个java对象
        HashMap<Object, Object> map = new HashMap<>();
        map.put("name", "张三");
        map.put("age", 1);

        /*Student student = new Student();
        student.name = (String) map.get("name");
        student.age = (Integer) map.get("age");
        System.out.println(student);*/

        Student student = parseObj(Student.class, map);
        System.out.println(student);

        HashMap<Object, Object> maps = new HashMap<>();
        maps.put("name1", "刘备");
        maps.put("age1", 10);
        maps.put("id", 100);
        Person person = parseObj(Person.class, maps);
        System.out.println(person);

    }

    public static <T> T parseObj(Class<T> clazz, HashMap<Object, Object> maps) throws IllegalAccessException, InstantiationException {
        T t = clazz.newInstance();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.set(t,maps.get(field.getName()));
        }

        return t;
    }
}

四:总结

a:反射
	反射很强大,可以对类里面的成分(成员变量。成员方法。构造方法)进行操作。
	可以通过反射找到所有的构造方法(包括私有),并通过构造方法创建对象
	可以通过反射找到所有方法对象(包括私有),通过方法对象执行这个方法。
	可以通过反射找到所有属性对象(包括私有),可以对对象的属性进行赋值和取值。
	
b:注释
	系统给了一些注释,我们只需要明白是做什么用的就行;
	我们自己自定义注释,public @interface  名字{}
	在解析注释无论是自定义还是系统给的,都可以用注释解析获取注释。获取注释的变量。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Junit 是一个流行的 Java 单元测试框架,它使用注解反射来实现测试的自动化。在 Junit 中,可以使用注解来标记测试方法,并使用反射来执行这些方法。 要给注解中的 int 值排序,可以使用反射来获取注解的值并进行排序。下面是一个简单的示例: ```java import java.lang.annotation.*; import java.lang.reflect.*; import java.util.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface SortValue { int value(); } public class TestClass { @SortValue(3) public void method1() { System.out.println("Method 1"); } @SortValue(1) public void method2() { System.out.println("Method 2"); } @SortValue(2) public void method3() { System.out.println("Method 3"); } public static void main(String[] args) { Class<?> clazz = TestClass.class; Method[] methods = clazz.getDeclaredMethods(); // 使用 TreeMap 来按照注解的值进行排序 TreeMap<Integer, Method> sortedMethods = new TreeMap<>(); for (Method method : methods) { SortValue annotation = method.getAnnotation(SortValue.class); if (annotation != null) { sortedMethods.put(annotation.value(), method); } } for (Method method : sortedMethods.values()) { try { method.invoke(clazz.newInstance()); } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { e.printStackTrace(); } } } } ``` 在上面的示例中,我们定义了一个 `SortValue` 注解,用于给测试方法指定排序值。然后在 `TestClass` 中,我们使用了这个注解来标记几个测试方法。 在 `main` 方法中,通过反射获取到了 `TestClass` 的所有方法,并将带有 `SortValue` 注解的方法按照注解的值使用 `TreeMap` 进行排序。最后,按照排序后的顺序依次调用这些方法。 这样,就能够按照注解中的 int 值进行排序并执行相应的测试方法了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值