java之 ------ JUnit、注解、类加载器

JUnit软件测试技术(工具)

在项目中建立专门用户测试的包结构。

在Junit中,通过@Test注解,可以运行一个方法(鼠标放在选择要运行的方法名上,单击右键,选择Run As,再选择JUnit Test即可)。

这样做的好处就是不用在主代码中添加测试代码,避免了代码的冗余。而且一个测试类,可以测试多项功能,不需要main方法。

一、 Junit注解说明

使用了@Test注解应该满足以下条件:

1) 必须是无参数的非静态方法。

2) 添加@Test注解的类,必须拥有一个无参数的公开构造

package junit.test;

import org.junit.Test;

import junit.UserDaoImpl;

public class TestUserDaoImpl {

	@Test
	public void testFun1(){
		new UserDaoImpl().fun1();
	}

	@Test
	public void testFun2(){
		new UserDaoImpl().fun2();
	}

	@Test
	public void testFun3(){
		new UserDaoImpl().fun3();
	}

}

二、 JUnit测试示例演示

1、运行完成后,可以在Junit的窗口上看到运行所用的时间和结果信息。

2、被测试程序的运行结果出现在控制台(Console)上。

三、 JUnit中的其它注解

@BeforeClass、@AfterClass、@Before、@After

package junit.test;

import junit.UserDaoImpl;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class TestUserDaoImpl2 {
	static UserDaoImpl obj = null;

	@Test
	public void testFun1(){
		obj.fun1();
	}

	@BeforeClass
	public static void init(){
		obj = new UserDaoImpl();
		System.out.println("111111111111");
	}
	@Test
	public void testFun2(){
		obj.fun2();
	}

	@Test
	public void testFun3(){
		obj.fun3();
	}

	@AfterClass
	public static void finish(){
		obj = null;
		System.out.println("clearing....");
	}
}

结果:111111111111

fun1......

8787

fun2......

fun3......

clearing....

注解 ( Annotation )

一、元数据

所谓元数据就是数据的数据。也就是说,元数据是描述数据的。就象数据表中的字段一样,每个字段描述了这个字段下的数据的含义。

元数据可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。许多元数据工具,如XDoclet,将这些功能添加到核心Java语言中,暂时成为Java编程功能的一部分。

一般来说,元数据的好处分为三类:文档编制、编译器检查和代码分析。代码级文档最常被引用。元数据提供了一种有用的方法来指明方法是否取决于其他方法,它们是否完整,特

定类是否必须引用其他类,等等。

二、 什么是注解

Java中的注解就是Java源代码的元数据,也就是说注解是用来描述Java源代码的。  基本语法就是:@后面跟注解的名称。

三、 Java中预定义注解 (Java.lang包当中的三个预定注解)

①Override:标识某一个方法是否正确覆盖了它的父类的方法。

②Deprecated:表示已经不建议使用这个类成员了。  它是一个标记注解。

③SuppressWarnings:用来抑制警告信息。

四、自定义注解

自定义注解的语法很简单,跟定义接口类似,只是在名称前面加上@符号。

1、 最简单的自定义注解

<span style="font-size:14px;">public @interface MyAnno {
}</span>

2、 使用这个注解

<span style="font-size:14px;">@MyAnno
public class UserModel{
} </span>

3、为注解添加成员

<span style="font-size:14px;">//定义
public @interface MyAnno {
  public String schoolName();
}</span>
<span style="font-size:14px;">//使用
@MyAnno(schoolName="中华人民共和国")
public class UserModel{
} </span>

4、设置默认值

<span style="font-size:14px;">//定义
public @interface MyAnno {
  public String schoolName() default "中华人民共和国";
}</span>
<span style="font-size:14px;">//使用1
@MyAnno
public class UserModel{
}</span>
<span style="font-size:14px;">//使用2
@MyAnno(schoolName="Java高手")
public class UserModel{
}</span>

五、对注解的注解

☆指定目标 Target

在了解如何使用Target 之前,需要认识另一个类,该类被称为ElementType (通过API详细学习) ,它实际上是一个枚举。这个枚举定义了注释类型可应用的不同程序元素。

<span style="font-size:14px;">@Target({ ElementType.TYPE, ElementType.METHOD}) </span>

☆设置保持性 Retention

RetentionPolicy (通过API详细学习)枚举类中定义了3种注解保持性,分别决定了Java 编译器以何种方式处理注解。

@Retention(RetentionPolicy.SOURCE) 

☆添加公共文档 Documented

在默认的情况下在使用javadoc自动生成文档时,注解将被忽略掉。如果想在文档中也包含注解,必须使用Documented为文档注解。

@Documented 

☆设置继承 Inherited

在默认的情况下,父类的注解并不会被子类继承。如果要继承,就必须加上Inherited注解。

@Inherited 

package annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD , ElementType.TYPE} )
public @interface MyAnno {
    public String schoolName() default "哈哈大学";
}

六、如何读取注解

要读取注解的内容,就需要使用反射的技术。   注意:要想使用反射得到注释信息,须用@Retention(RetentionPolicy.RUNTIME)进行注解。

import java.lang.reflect.*;
public class TestMyAnno {
  public static void main(String[] args)throws Exception {
    Class c = Class.forName(“anno.UserModel");
    boolean flag = c.isAnnotationPresent(MyAnno.class);
    System.out.println(flag);
    if(flag){
      MyAnno ma = (MyAnno)c.getAnnotation(MyAnno.class);
      System.out.println("学校名称:=="+ma.schoolName());
      //获取到了这些数据过后,下面就可以开始你的处理了
    }
  }
}

类加载器

Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,  ExtClassLoader,  AppClassLoader

类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap

Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类

加载。

一、类加载器之间的父子关系和管辖范围图

二、类加载器的委托机制(通过API认识ClassLoader类)

当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

首先当前线程的类加载器去加载线程中的第一个类。如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。

还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

每个类加载器加载类时,又先委托给其上级类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加

载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?

对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。

package loader;

import org.junit.Test;

public class Demo {

	@Test  //查看类加载器
	public void testLoader0() throws Exception {
		Class c = Class.forName("loader.Person");
		ClassLoader loader = c.getClassLoader(); //AppClassLoader--java
		System.out.println(loader);

		loader = loader.getParent(); //ExtClassLoader --java
		System.out.println(loader);

		loader = loader.getParent(); //null  BootStrap --C
		System.out.println(loader);

	}

	@Test  //类加载器
	public void testLoader1() throws Exception {
		//AppClassLoader只能加载项目当中的类
		Class c = Class.forName("loader.Person");
		Object obj = c.newInstance();
		System.out.println("obj:"+obj);

		Class c2 = Class.forName("d:/ex/UserModel.class");//这个是项目外的类,所以会报错
		Object obj2 = c2.newInstance();
		System.out.println("obj2:"+obj2);
	}

	@Test
	public void testLoader2() throws Exception{
		Hello h = new Hello();
		System.out.println(h);
		System.out.println(h.getClass().getClassLoader());
	}

}

练习

一、做自己的类加载器

虚拟机的核心是通过类加载器来加载.class文件,然后进行相应的解析执行。那么我们可以自己做类加载器,手动加载需要的.class以进行解析执行,从而扩展虚拟机的功能。

以下内容摘自API文档:应用程序需要实现 ClassLoader 的子类,以扩展 Java 虚拟机动态加载类的方式。

网络类加载器子类必须定义方法 findClass 和 loadClassData,以实现从网络加载类。下载组成该类的字节后,它应该使用方法 defineClass 来创建类实例。

myClassLoader.java

package loader.myClassLoader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class MyClassLoader extends ClassLoader{
	public Class findClass(String name) {
        byte[] b=null;
		try {
			b = loadClassData(name);
		} catch (IOException e) {
			e.printStackTrace();
		}
        return defineClass(null, b, 0, b.length);
    }

	private byte[] loadClassData(String fileName) throws IOException {
		InputStream in = new FileInputStream(fileName);
		byte[] b = new byte[1024];
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int len=0;
		while((len=in.read(b))!=-1){
			out.write(b,0,len);
		}
		out.close();
		b = out.toByteArray();
		return b;
	}
}

TestMyClassLoader.java

package loader.myClassLoader;
import java.lang.reflect.Method;
import loader.Hello;
import org.junit.Test;
public class TestMyClassLoader {
	/*
	 * 演示用我们自己做的类加载器 来加载项目外面的类,并且可以查看到该类的加载器就是我们自己的
	 */
	@Test
	public void testLoader() throws Exception{
		MyClassLoader loader = new MyClassLoader();
		Class clazz = loader.findClass("d:/ex/Hello.class");
		//Class clazz = loader.findClass("d:/ex/UserModel.class");
		Object obj = clazz.newInstance();
		System.out.println(obj);
		System.out.println(obj.getClass().getClassLoader()); //loader.myClassLoader.MyClassLoader
	}//[email protected]

	@Test
	public void testLoader2() throws Exception{
		MyClassLoader loader = new MyClassLoader();
		Class clazz = loader.findClass("E:\\MyEclipse 10\\paragraph2\\bin\\loader\\Hello.class");
		Object obj = clazz.newInstance();
		System.out.println(obj);
		//System.out.println(obj.getClass().getClassLoader());
		Method m = clazz.getMethod("call", null);
		m.invoke(obj, null);

		System.out.println("-------");

		Hello h = new Hello();
		System.out.println(h);
		h.call();

		//既然上面两个对象是一样的,那么能不能相互转换呢?※※不能,因为空间不一样。不同类加载器所加载的类模板(字节码对象)在不同的内存空间  这里会挂掉
		Hello h2 = (Hello)obj;
		System.out.println(h2);

	}
}

运行结果:

二、作自己的测试工具MyJUnit

(注解与反射共同使用的案例 )

相关说明:1)JUnit用的是@Test注解,我们用@MyTest注解。

2)JUnit已经嵌入到MyEclipse当中,我们自己的MyJUnit只要能独立运行就可以(不嵌入),同时这样我们也不方便在MyJUnit中以参数方式接收到被测试类的类名与方法名,只能以键盘输

入的方式接收。

3)JUnit能实现指定单个方法来调用执行,由于不能利用MyEclipse传参,因此我们在MyJUnit程序中遍历所有的方法并通过判断是否声明@MyTest注解来决定是否调用执行该方法。

MyTest.java

package loader.myJunit;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
}

MyTestDemo.java

package loader.myJunit;

public class MyTestDemo {
	public void aa(){
		System.out.println("AAA");
	}
	@MyTest
	public void bb(){
		System.out.println("BBB");
	}

	@MyTest
	public void cc(){
		System.out.println("CCC");
	}

}

MyJUnit.java

package loader.myJunit;

import java.lang.reflect.Method;
import java.util.Scanner;

import loader.myClassLoader.MyClassLoader;

public class MyJUnit {

	public static void main(String[] args) throws Exception {
		System.out.println("请输入要被测试的类:");
		Scanner sc = new Scanner(System.in);
		String className = sc.nextLine();

//		Class clazz = Class.forName(className);//必须是完整类名(带包名)
//		Object obj = clazz.newInstance();
		MyClassLoader loader = new MyClassLoader();
		Class clazz = loader.findClass(className);
		Object obj = clazz.newInstance();

		Method ms[] = clazz.getDeclaredMethods();
		for(Method m: ms){
			boolean boo = m.isAnnotationPresent(MyTest.class);
			if(boo){
				m.invoke(obj, null);
			}
		}
	}
}

运行结果:

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-15 17:57:40

java之 ------ JUnit、注解、类加载器的相关文章

day19_java基础加强_动态代理+注解+类加载器

一.动态代理 1.1.代理模式 ? ? 什么是代理模式及其作用? ? ? ? ? Proxy Pattern(即:代理模式),23种常用的面向对象软件的设计模式之一.? ? ? ? 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.? ? ? ? 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.? ? 优点:? ? ? ? (1) 职责清晰,真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件

Java基础知识之类加载器

1.类加载器定义 1.1类加载器概述: java类的加载是由虚拟机来完成的,虚拟机把描述类的Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成能被java虚拟机直接使用的java类型,这就是虚拟机的类加载机制.JVM中用来完成上述功能的具体实现就是类加载器.类加载器读取.class字节码文件将其转换成java.lang.Class类的一个实例.每个实例用来表示一个java类.通过该实例的newInstance()方法可以创建出一个该类的对象. 1.2类的生命周期: 类从加载到虚拟

Java魔法堂:类加载器入了个门

一.前言 <Java魔法堂:类加载机制入了个门>中提及整个类加载流程中只有加载阶段作为码农的我们可以入手干预,其余均由JVM处理.本文将记录加载阶段的核心组件——类加载器的相关信息,以便日后查阅.若有纰漏请大家指正,谢谢. 注意:以下内容基于JDK7和HotSpot VM. 二.类加载器种类及其关系 从上图可知Java主要有4种类加载器 1. Bootstrap ClassLoader(引导类加载器):作为JVM的一部分无法在应用程序中直接引用,由C/C++实现(其他JVM可能通过Java来实

深入理解java:1.1.类加载器

从java的动态性到类加载机制 我们知道,Java是一种动态语言. 那么怎样理解这个"动态"呢? 或者说一门语言具备了什么特性,才能称之为动态语言呢? 对于java,我是这样理解的. 我们都知道JVM(java虚拟机)执行的不是本地机器码指令, 而是执行一种称之为字节码的指令(存在于class文件中). 这就要求虚拟机在真正执行字节码之前,先把相关的class文件加载到内存中. 虚拟机不是一次性加载所有需要的class文件,因为它在执行的时候根本不会知道以后会用到哪些class文件.

Java中对于ClassLoader类加载器 嵌套了深度技术的价值

关于Java技术是一种不断兴起的编程语言,对于ClassLoader 是 Java 届最为神秘的技术之一,无数人被它伤透了脑筋,摸不清门道究竟在哪里.本文我带你彻底吃透 ClassLoader,让你甚至Java类加载器的神奇之处  1.ClassLoader 做什么的? 顾名思义,它是用来加载 Class 的.它负责将 Class 的字节码形式转换成内存形式的 Class 对象.字节码可以来自于磁盘文件 *.class,也可以是 jar 包里的 *.class,也可以来自远程服务器提供的字节流,

Java基础之ClassLoader类加载器简介

classloader简介 1 classloader层次结构(父子关系) Bootstrap(ClassLoader) ExtClassLoader AppClassLoader XXXClassLoader 详见代码如下: sun.misc.Launcher public Launcher() { Launcher.ExtClassLoader var1; try { var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (I

java JVM-线程上下类加载器

public class One { public static void main(String[] args) throws Exception { ClassLoader loader=One.class.getClassLoader(); System.out.println(loader); //获得当前线程的上下文加载器,未改变前和第一种是一样的 ClassLoader loader2=Thread.currentThread().getContextClassLoader(); S

java JVM-线程上下类加载器图

原文地址:https://blog.51cto.com/14437184/2439551

Java---JUnita、注解与类加载器详解以及实例

JUnit软件测试技术(工具) 在项目中建立专门用户测试的包结构. 在Junit中,通过@Test注解,可以运行一个方法. ★ Junit注解说明 使用了@Test注解应该满足以下条件: 1) 必须是无参数的非静态方法. 2) 添加@Test注解的类,必须拥有一个无参数的公开构造 ★ JUnit测试示例演示 1.运行完成后,可以在Junit的窗口上看到运行所用的时间和结果信息. 2.被测试程序的运行结果出现在控制台(Console)上. "项目"代码: package cn.hncu.

JDK1.5的新特性:javabean、注解类、类加载器

关于Java基础的文章,我觉得写得还可以,以前发在了我其它的博客了,肯定是原创,现在再分享给大家出来. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------