9.测试和反射

1. 测试分类

  • 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
  • 白盒测试:需要写代码的。关注程序具体的执行流程。

2.Junit测试(白盒测试)

	//所在包
	package cn.qiang.junit;
	public class Calculator { ... }
	import cn.qiang.junit.Calculator;//导入junit依赖环境
	...
	//所在包
	package cn.itcast.test;

	public class CalculatorTest {   
    	//初始化方法:用于资源申请,所有测试方法在执行之前都会先执行该方法    
    	@Before
    	public void init(){ System.out.println("init..."); }
	
		//释放资源方法:在所有测试方法执行完后,都会自动执行该方法
		@After
    	public void close(){ System.out.println("close..."); }
   
 		//测试add方法
    	@Test
    	public void testAdd(){      
        	System.out.println("testAdd...");
        	Calculator c  = new Calculator();        
        	int result = c.add(1, 2);      
        	Assert.assertEquals(3,result);断言这个结果是3
    	}

    	@Test
    	public void testSub(){       
        	Calculator c  = new Calculator();
        	int result = c.sub(1, 2);
        	System.out.println("testSub....");
        	Assert.assertEquals(-1,result);
    	}
	}
  命名建议:
- 测试类名:CalculatorTest
- 测试方法名:testAdd( )  void 空参 @Test
- 包名:cn.itcast.test
- 导入junit依赖环境

3.反射

  • 反射机制:将类的各个组成部分封装为其他对象
  • 好处:
    1. 可以在程序运行过程中,操作这些对象。
    2. 可以解耦,提高程序的可扩展性。
    在这里插入图片描述

①获取Class对象

		//1.Class.forName("全类名") 字节码文件加载进内存,返回Class对象
        Class cls1 = Class.forName("cn.itcast.domain.Person");//用于配置文件
        System.out.println(cls1);
        
        //2.类名.class 通过类名的属性class获取
        Class cls2 = Person.class;//用于参数的传递
        System.out.println(cls2);
        
        //3.对象.getClass() Object类方法
        Person p = new Person();
        Class cls3 = p.getClass();//用于对象的获取字节码的方式
        System.out.println(cls3);

        //== 比较三个对象
        System.out.println(cls1 == cls2);//true
        System.out.println(cls1 == cls3);//true

注意:同一个字节码文件(*.class)在一次程序运行过程中只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个

		public class Person {
    		private String name;
    		private int age;
    		public String a;
    		protected String b;
    		default String c;
    		private String d;
    		...
    		
    		public Person() { }
    		
    		public Person(String name, int age) {
				this.name = name;
        		this.age = age;
    		}
			
			public void eat() System.out.println("eat...");
    		
    		public void eat(String food) System.out.println("eat..."+food);
    		
    		private void play() System.out.println("play..."); 
    		
    		private void play(String game) System.out.println("play..."+game);
		}

②使用Class对象—获取成员变量

 	1. 获取成员变量
	    public final class Class<T> {
     	 	public Field getField(String name)
     	 	//获取指定public修饰的成员变量
     	 	public Field[] getFields()
      		//获取所有public修饰的成员变量
      		public Field getDeclaredField(String name)
      		//获取指定成员变量,非public要打开权限
      		public Field[] getDeclaredFields()
      		//获取所有的成员变量,不考虑修饰符      		
     	}
     	
     	public final class Field{
		 	public void set(Object obj, Object value)
		 	public Object get(Object obj)
		}  
						
		//获取Person的Class对象  
		Class personClass = Person.class;
		
		//获取public成员变量a
		Field a = personClass.getField("a");
		    //获取到成员变量a之后可以用Field成员方法操作他
		    Person p = new Person();
        	System.out.println("默认的变量值:"+a.get(p));
        	a.set(p,"张三");//设置a的值
        	System.out.println("getField设置后的成员变量:"+a.get(p));
		
		//获取所有public成员
		Field[] fields = personClass.getFields();
			for (Field field : fields)
            	System.out.println("getFields方法获取的成员变量:"+field);
     
       	
       	//获取非public成员变量d
       	Field d = personClass.getDeclaredField("d");
        	d.setAccessible(true);//忽略访问权限修饰符的安全检查,暴力反射
        	//获取到成员变量d之后可以用Field成员方法操作他
        	System.out.println("默认的变量值:"+d.get(p));
        	d.set(p,"林俊杰");//设置d的值
        	System.out.println("getDeclaredField设置后的成员变量:"+d.get(p));
        
        //获取所有非public成员变量
       	Field[] declaredFields = personClass.getDeclaredFields();
			for (Field declaredField : declaredFields) 
            	System.out.println(declaredField);
		        

③使用Class对象—获取构造方法

 	 2. 获取构造方法们
		public final class Class<T> {    		
     		public Constructor<T> getConstructor(Class<?>... parameterTypes)     	
		}
		
		public final class Constructor<T>{
			public T newInstance(Object ... initargs)
		}
		
		Class personClass = Person.class;       
        Constructor constructor1 = personClass.getConstructor();
        Constructor constructor2 = personClass.getConstructor(String.class, int.class);

        System.out.println(constructor1);
        System.out.println(constructor2);

        Object person1 = constructor1.newInstance();
        Object person2 = constructor2.newInstance("张三", 23);

        System.out.println(person1);
        System.out.println(person2);		

④使用Class对象—获取成员方法

 	3. 获取成员方法们
 		public final class Class<T> {        		      	      		
      		public Method getMethod(String name, Class<?>... parameterTypes)
      		//获取指定public修饰的成员方法        	
      		public Method[] getMethods()
      		//获取所有public修饰的成员方法      	
      		Method[] getDeclaredMethods()
      		//获取指定成员方法,非public要打开权限
      		Method getDeclaredMethod(String name,<?>... parameterTypes)
      		//获取所有的成员方法,不考虑修饰符     
      	}
      	
      	public final class Method{
      		public Object invoke(Object obj, Object... args)
      		//执行方法
      		public String getName() { return name; }
      		//获取方法名
		}
		
		Class personClass = Person.class;

        Method eat_method1 = personClass.getMethod("eat");
        Method eat_method2 = personClass.getMethod("eat", String.class);

        Method[] methods1 = personClass.getMethods();

        Method play_method1=personClass.getDeclaredMethod("play");
        Method play_method2=personClass.getDeclaredMethod("play",String.class);

        Method[] methods2 = personClass.getDeclaredMethods();

        Person p = new Person();

        eat_method1.invoke(p); //执行方法
        eat_method2.invoke(p,"饭");

        play_method1.setAccessible(true);
        play_method2.setAccessible(true);
        play_method1.invoke(p); //执行方法
        play_method2.invoke(p,"lol");

        System.out.println("仅公有");
        for (Method method : methods1) {
            System.out.print(method+" ");
            System.out.println(method.getName());
        }

        System.out.println("有私有");
        for (Method method : methods2)
            System.out.println(method);


        String className = personClass.getName(); //获取类名
        System.out.println(className);//cn.itcast.domain.Person	

4.反射案例

步骤:

  1. 在配置文件中写入类名和方法
  2. 在程序中加载读取配置文件
  3. 使用反射技术来加载类文件进内存
  4. 创建对象并执行方法
框架类:配置文件+反射
public class ReflectTest {
    public static void main(String[] args) throws Exception {

        //前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法
        //1.....

        //2.加载配置文件
        //创建Properties对象
        Properties pro = new Properties();
        //加载配置文件,转换为一个集合
        //通过类加载器获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        //获取字节码文件,并获取对应的类加载器,把ReflectTest加载进内存
        classLoader.getResource("C:\\Users\\QIANG\\Desktop\\day01_基础加强\\代码\\day01_基础加强\\src\\pro.properties");        
        InputStream is = classLoader.getResourceAsStream("pro.properties");

        pro.load(is);//需要传入一个字节流或者字符流

        //3.获取配置文件中定义的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");


        //4.加载该类进内存
        Class cls = Class.forName(className);
        //5.创建对象
        Object obj = cls.newInstance();
        //6.获取方法对象
        Method method = cls.getMethod(methodName);
        //7.执行方法
        method.invoke(obj);
    }
}

5.注解

①预定义注解

		@Override	
		@Deprecated  注解标注的内容,表示已过时
		@SuppressWarnings(value="all") 压制警告
		@Override
    	public String toString() { return super.toString(); }
    	
    	@Deprecated//过期注解
    	public void show1(){ //有缺陷 }    	
    	
    	public void show2(){ //替代show1方法 }

②自定义注解

1. 格式和本质:注解本质是一个接口,继承自Annotation接口

		public interface MyAnno extends java.lang.annotation.Annotation {}

		元注解
		public @interface 注解名称{
			属性列表;
		}	

2. 属和元注解:

  • 属性:接口中的抽象方法
  • 元注解:用于描述注解的注解
		public enum Person { P1,P2,P3; }

		public @interface MyAnno {
     		int value();
    		String show(); 
    		String[] strs();//字符串数组
     		String name() default "张三";//默认赋值
     		Person per();//枚举
    		MyAnno2 anno2();//注解    	
		}
		* 属性只能是:基本数据类型 + String + 枚举 + 注解 + 以上类型的数组
		* 使用default修饰属性,可以不进行属性的赋值
		* 一个属性且属性名为value,可直接定义@SuppressWarnings("all")
		* 数组中只有一个值时{ }可以省略	
				
		@MyAnno(value=12,show="迪迦",strs={"bbb","aaa"},per = Person.P3,anno2 = @MyAnno2)
		public class Worker {
    		public String name = "aaa";
    		public void show()
    	}
		
		* @Target:描述注解能够作用的位置
			* ElementType取值:
				* TYPE:可以作用于类上
				* METHOD:可以作用于方法上
				* FIELD:可以作用于成员变量上
		* @Retention:描述注解被保留的阶段
			* @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
		* @Documented:描述注解是否被抽取到api文档中
		* @Inherited:描述注解是否被子类继承		
		
		@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
		@Retention(RetentionPolicy.RUNTIME)
		@Documented
		@Inherited
		public @interface MyAnno {
		}
		
		@MyAnno
		public class Worker {
	    	@MyAnno
	    	public String name = "aaa";
		    @MyAnno
		    public void show()
		}


		

③使用(解析)注解

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值