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

简介: JUnit软件测试技术(工具)在项目中建立专门用户测试的包结构。 在Junit中,通过@Test注解,可以运行一个方法。 Junit注解说明使用了@Test注解应该满足以下条件: 1) 必须是无参数的非静态方法。

JUnit软件测试技术(工具)

在项目中建立专门用户测试的包结构。
在Junit中,通过@Test注解,可以运行一个方法。

Junit注解说明

使用了@Test注解应该满足以下条件:
1) 必须是无参数的非静态方法。
2) 添加@Test注解的类,必须拥有一个无参数的公开构造

JUnit测试示例演示

1、运行完成后,可以在Junit的窗口上看到运行所用的时间和结果信息。
2、被测试程序的运行结果出现在控制台(Console)上。

“项目”代码:

package cn.hncu.user.dao.dao;
/**
 * @author 陈浩翔
 * @version 1.0  2016-5-4
 */
public interface UserDao {
    public abstract void fun1()throws Exception;
    public abstract void fun2();
    public abstract void fun3();
}
package cn.hncu.user.dao.impl;

import cn.hncu.user.dao.dao.UserDao;

/**
 * @author 陈浩翔
 * @version 1.0  2016-5-4
 */
public class UserDaoImpl implements UserDao{
    @Override
    public void fun1() throws Exception {
        System.out.println("fun1....");
    }
    @Override
    public void fun2() {
        System.out.println("fun2....");
    }
    @Override
    public void fun3() {
        System.out.println("fun3....");
    }
}
package cn.hncu.user.dao.factory;

import cn.hncu.user.dao.dao.UserDao;
import cn.hncu.user.dao.impl.UserDaoImpl;

/**
 * @author 陈浩翔
 * @version 1.0  2016-5-4
 */
public class UserDaoFactory {
    public static UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

随便写了几个输出。。。

下面的是测试代码:

package cn.hncu.test;

import org.junit.Test;

import cn.hncu.user.dao.dao.UserDao;
import cn.hncu.user.dao.factory.UserDaoFactory;
import cn.hncu.user.dao.impl.UserDaoImpl;

/**
 * @author 陈浩翔
 * @version 1.0  2016-5-4
 */
//使用@Test的条件2:该类必须具有一个无参构造方法
public class TestUserDaoImpl {
    UserDao dao = UserDaoFactory.getUserDao();

    /**
     * 测试fun1()方法
     */
    //使用@Test的条件1:测试方法必须是非静态、无参
    @Test
    public void testFun1(){
        try {
            dao.fun1();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


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

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

}

正确的演示结果:

错误的演示结果:(没有无参构造方法)

JUnit中的其它注解

@BeforeClass、@AfterClass、@Before、@After

package cn.hncu.test;

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

import cn.hncu.user.dao.dao.UserDao;
import cn.hncu.user.dao.factory.UserDaoFactory;
import cn.hncu.user.dao.impl.UserDaoImpl;

/**
 * @author 陈浩翔
 * @version 1.0  2016-5-4
 */

public class TestUserDaoImpl2 {
    UserDao dao = UserDaoFactory.getUserDao();

    //注意要加static
    @BeforeClass
    public static void initFirst(){
        System.out.println("finishEnd...");
    }

    //在每次运行@Test方法之前,都会先运行这个@Before的方法
    @Before
    public void init(){
        System.out.println("init...");
    }

    @Test
    public void testFun1(){
        try {
            dao.fun1();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
        /*运行结果
    finishEnd...
    init...
    fun1....
    finish...
    finishEnd...
    */

    @Test
    public void testFun2() {
        dao.fun2();
    }
    /*运行结果
    finishEnd...
    init...
    fun2....
    finish...
    finishEnd...
    */

    @Test
    public void testFun3() {
        dao.fun3();
    }
    /*运行结果
    finishEnd...
    init...
    fun3....
    finish...
    finishEnd...
    */

    //在每次运行@Test方法之后,都会最后运行这个@After的方法
    @After
    public void finish(){
        System.out.println("finish...");
    }

    //注意要加static
    @AfterClass
    public static void finishEnd(){
        System.out.println("finishEnd...");
    }

}

注解 ( Annotation )

元数据

    所谓元数据就是数据的数据。也就是说,元数据是描述数据的。就象数据表中的字段一样,每个字段描述了这个字段下的数据的含义。
   元数据可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。许多元数据工具,如XDoclet,将这些功能添加到核心Java语言中,暂时成为Java编程功能的一部分。
    一般来说,元数据的好处分为三类:文档编制、编译器检查和代码分析。代码级文档最常被引用。元数据提供了一种有用的方法来指明方法是否取决于其他方法,它们是否完整,特定类是否必须引用其他类,等等。 

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

像前面演示的那几个都是注解。

Java中预定义注解

①Override:标识某一个方法是否正确覆盖了它的父类的方法。
(如果用了这个注解,但是父类中没有这个方法,就会报错)

②Deprecated:表示已经不建议使用这个类成员了。 它是一个标记注解。
(用了这个注解的,表示在下一个升级版本中,可能不会有这个方法了,但是会有类似功能的方法代替,会在注释中提出)

③SuppressWarnings:用来抑制警告信息。
(例如:压泛型的警告)

(这个是可以传参进去的,可以实现不同的功能)

自定义注解1

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

public @interface MyAnno {
}

使用这个注解
和使用其他注解是一样的

@MyAnno
public class UserModel{
} 

为注解添加成员

//定义
public @interface MyAnno {
  public String schoolName();
}
//使用
@MyAnno(schoolName="湖南城市学院")
public class UserModel{
} 

设置默认值

//定义
public @interface MyAnno {
  public String schoolName() default "湖南城市学院";
}
//使用1
@MyAnno
public class UserModel{
}
//使用2
@MyAnno(schoolName="城院Java高手训练营")
public class UserModel{
}

对注解的注解

package cn.hncu.anno;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyAnno {
}

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

@Target({ ElementType.TYPE, ElementType.METHOD}) 

//这个注解可以在哪里用,TYPE-可以在类上面用,METHOD-可以在方法上用

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

@Retention(RetentionPolicy.RUNTIME)

//运行时VM虚拟机也能识别这个注解,这个注解一直存在

@Retention(RetentionPolicy.SOURCE) 

//class文件中有这个注解,但是VM虚拟机运行时,忽略这个注解了。
(这是默认的)

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

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

如何读取注解

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

    /**
     * 分别读取类上的@MyAnno注解 和  方法上的@MyAnno注解
     */
    @Test
    public void readAnno(){
        //※※注意:MyAnno注解定义时,必须指定它的保持性为 RUNTIME,否则下面是读取不出注解的

        //以下方式是读取“声明在类上的”MyAnno注解
        Class c = UserModel.class;
        //boolean boo = c.isAnnotationPresent(cn.hncu.anno.MyAnno.class);
        //boolean boo = c.isAnnotationPresent(MyAnno.class);
        boolean boo = (c.getAnnotation(MyAnno.class)!=null);
        System.out.println(boo);

        //以下方式是读取“声明在方法上的”MyAnno注解
        Method ms[] = c.getDeclaredMethods();
        for(Method m:ms){
            if(m.isAnnotationPresent(MyAnno.class)){
                System.out.println(m.getName()+"方法上有@MyAnno注解");
            }
        }
    }

结果:

true
getAge方法上有@MyAnno注解
getId方法上有@MyAnno注解

类加载器

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

    @Test
    public void systemLoaderDemo(){
        ClassLoader loader = Person.class.getClassLoader();
        System.out.println(loader);//AppClassLoader
        loader = loader.getParent();
        System.out.println(loader);//ExtClassLoader
        loader = loader.getParent();
        System.out.println(loader);//null
    }

因为BootStrap是最底层,用C写的,我们不能访问到,我们没有权限,所以输出就是null了。

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

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

类加载器的委托机制

通过API认识ClassLoader类

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

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

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

每个类加载器加载类时,又先委托给其上级类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?
对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的aa.jar包中后,运行结果为ExtClassLoader的原因。

演示不是classpath下的类,系统类加载器是无法加载的
Person类:

package cn.hncu;
/**
 * 
 * @author 陈浩翔
 *
 * @version 1.0  2016-5-4
 */
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}
    @Test
    public void loaderLocalClassDemo() throws ReflectiveOperationException{
        Class c = Class.forName("cn.hncu.Person");
        System.out.println(c);
        Object obj = c.newInstance();
        System.out.println(obj);
    }

运行结果:

class cn.hncu.Person
Person [name=null, age=0]

再看:
我把Person.class移到d:\cn\hncu

//不是classpath下的类,系统类加载器是无法加载的---如果要加载,得自己写类加载器
@Test
    public void loaderRemoteClassDemo() throws ReflectiveOperationException{
        Class c = Class.forName("d:\\cn\\hncu\\Person.class");
        System.out.println(c);
        Object obj = c.newInstance();
        System.out.println(obj);
    }

结果:

挂了,不能运行了。

因为没有配置classpath。

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

必须是压.class文件,不要压缩.java文件。!!!!

package cn.hncu;

/**
 * 
 * @author 陈浩翔
 *
 * @version 1.0  2016-5-4
 */
public class LoaderDemo {
    public static void main(String[] args) {
        LoaderDemo a = new LoaderDemo();
        System.out.println(a);
    }

    @Override
    public String toString() {
        return "随便演示。。。chx";
    }
}

先按照这个命令打包这个.java

package cn.hncu;

/**
 * 
 * @author 陈浩翔
 *
 * @version 1.0  2016-5-4
 */
public class LoaderDemo {
    public static void main(String[] args) {
        LoaderDemo a = new LoaderDemo();
        System.out.println(a);
    }

    @Override
    public String toString() {
        return "湖南城院。。。随便演示...chx";
    }
    //改了没用。已经不会运行这里的代码了。
}

大家看输出结果:

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

也就是那三层从上到下,如果上面已经有那个类了,就不会运行下面的那个类:
BootStrap—>ExtClassLoader—>AppClassLoader(System classLoader)

大家再看看这个图,是不是感觉容易理解一些了:

目录
相关文章
|
2月前
|
安全 Java 测试技术
Java 大学期末实操项目在线图书管理系统开发实例及关键技术解析实操项目
本项目基于Spring Boot 3.0与Java 17,实现在线图书管理系统,涵盖CRUD操作、RESTful API、安全认证及单元测试,助力学生掌握现代Java开发核心技能。
98 1
|
2月前
|
人工智能 前端开发 安全
Java开发不可不知的秘密:类加载器实现机制
类加载器是Java中负责动态加载类到JVM的组件,理解其工作原理对开发复杂应用至关重要。本文详解类加载过程、双亲委派模型及常见类加载器,并介绍自定义类加载器的实现与应用场景。
151 4
|
3月前
|
人工智能 Java 开发者
【Java实例-简易计算机】使用Java实现简单的计算机案例
一个简单的Java案例——“简易计算器”,帮助编程新手快速上手。通过实现用户输入、基本逻辑运算和结果输出,学习者可以掌握变量声明、Scanner对象使用、控制流语句等关键知识点。文章分为设计思路、关键知识点、完整代码和测试运行四个部分。
122 9
【Java实例-简易计算机】使用Java实现简单的计算机案例
|
4月前
|
Java 测试技术 项目管理
【JavaEE】从 0 到 1 掌握 Maven 构建 Java 项目核心技巧 解锁 Java 项目高效管理实用实例
本文从Maven基础概念讲起,涵盖安装配置、核心概念(如POM与依赖管理)及优化技巧。结合Java Web项目实例,演示如何用Maven构建和管理项目,解决常见问题,助你高效掌握这一强大工具,提升Java开发与项目管理能力。适合初学者及进阶开发者学习。资源链接:[点此获取](https://pan.quark.cn/s/14fcf913bae6)。
146 6
|
3月前
|
Java 开发者
【Java实例-神秘年龄】用Java挑战你的直觉
我们一起走进这款款简单却充满趣味的Java小游戏——“神秘年龄”。这款游戏不仅适合编程初学者作为练习项目,也能为有一定基础的开发者提供一个轻松的编程小憩。
38 0
【Java实例-神秘年龄】用Java挑战你的直觉
|
3月前
|
Java 开发者
【Java实例-神秘硬币】用Java投掷你的幸运硬币,你是猜正还是反?
本文分享了一个简单有趣的编程案例——猜硬币正反面游戏。通过模拟抛硬币(0为正面,1为反面),用户输入猜测值,程序判断结果并输出。
101 0
【Java实例-神秘硬币】用Java投掷你的幸运硬币,你是猜正还是反?
|
3月前
|
存储 算法 Java
【Java实例-智慧牌局】Java实现赌桌上的21点
游戏规则:游戏开始时,玩家和庄家各获得两张牌,玩家可以看到自己手中的两张牌以及庄家的一张明牌。玩家需要根据手中的牌面总和,选择“要牌”(Hit)以获取更多牌,或“停牌”(Stand)停止要牌。如果玩家的牌面总和超过21点,即为爆牌,玩家立即输掉游戏。若玩家选择停牌,庄家则开始行动,其策略是当牌面总和小于17点时必须继续要牌。若庄家牌面总和超过21点,则庄家爆牌,玩家获胜。若双方均未爆牌,最终比较牌面总和,更接近21点的一方获胜;若牌面总和相同,则游戏以平局结束。
53 0
|
9月前
|
XML Java 编译器
Java注解的底层源码剖析与技术认识
Java注解(Annotation)是Java 5引入的一种新特性,它提供了一种在代码中添加元数据(Metadata)的方式。注解本身并不是代码的一部分,它们不会直接影响代码的执行,但可以在编译、类加载和运行时被读取和处理。注解为开发者提供了一种以非侵入性的方式为代码提供额外信息的手段,这些信息可以用于生成文档、编译时检查、运行时处理等。
191 7
|
3月前
|
Java 开发者
【Java实例-英雄对战】Java战斗之旅,既分胜负也决生死
游戏规则:在“英雄对战”中,玩家和敌人轮流选择行动,目标是在对方生命值归零前将其击败。游戏开始时,玩家和敌人都有100生命值。每回合,玩家可以选择“攻击”,“追击”,“闪避反击”这三种行动之一。
44 0
|
3月前
|
Java
【Java实例-小兵拆炸弹】Java打造数学挑战-拆炸弹
今天,我将向大家分享一款用Java开发的控制台小案例——“小兵拆炸弹”。游戏规则:玩家需要在有限的尝试次数内解开一系列数学题,以成功拆解炸弹。游戏的目标是连续答对五道数学题,每道题都由系统随机生成。如果玩家在五次机会内成功解密,游戏胜利;否则,炸弹爆炸,游戏结束。
59 0

热门文章

最新文章