导语:
一、Junit单元测试
1.Junit测试概述
2.Junit使用步骤
3.Junit_@Before&@After
二、反射
1.反射概述
2.反射获取字节码Class对象的三种方式
3.Class对象功能概述
4.Class对象功能_获取Field
5.Class对象功能_获取Constructor
6.Class对象功能_获取Method
7.反射案例
三、注解
1.注解概念
2.JDK内置注解
3.自定义注解_格式&本质
4.自定义注解_属性定义
5.自定义注解_元注解
6.解析注解
7.注解案例_简单的测试框架
结语:
导语:
这篇文档详细介绍了Java编程中Junit测试、反射原理和注解应用的核心知识点,旨在帮助初学者掌握Java基础,也可作为进阶学习的参考资料。
一、Junit单元测试
1.Junit测试概述
-
黑盒测试:无需编写代码,只需给输入值,检查输出是否符合预期。
-
白盒测试:需要编写代码,关注程序的具体执行流程。
案例代码:
展示了如何使用JUnit进行黑盒测试和白盒测试:
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
}
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
public class CalculatorTest {
private Calculator calculator;
@Before
public void setUp() {
calculator = new Calculator();
}
// 黑盒测试
@Test
public void testAdd() {
int result = calculator.add(1, 2);
assertEquals(3, result);
}
// 白盒测试
@Test
public void testSubtract() {
int result = calculator.subtract(5, 3);
assertEquals(2, result);
}
}
2.Junit使用步骤
-
定义测试类(以Test结尾)
-
定义测试方法(以test开头)
-
给测试方法添加@Test注解
-
导入Junit依赖
案例代码:
import org.junit.Assert;
import org.junit.Test;
public class CalculatorTest {
@Test
public void testAdd() {
Calculator c = new Calculator();
int result = c.add(1, 2);
Assert.assertEquals(3, result);
}
@Test
public void testSubtract() {
Calculator c = new Calculator();
int result = c.subtract(5, 3);
Assert.assertEquals(2, result);
}
}
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
3.Junit_@Before&@After
-
@Before:初始化方法,在测试方法执行前自动执行
-
@After:释放资源方法,在测试方法执行后自动执行
代码案例:
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class CalculatorTest {
private Calculator calculator;
@Before
public void setUp() {
// 初始化操作
calculator = new Calculator();
System.out.println("setUp...");
}
@After
public void tearDown() {
// 释放资源
calculator = null;
System.out.println("tearDown...");
}
@Test
public void testAdd() {
int result = calculator.add(1, 2);
Assert.assertEquals(3, result);
}
@Test
public void testSubtract() {
int result = calculator.subtract(5, 3);
Assert.assertEquals(2, result);
}
}
二、反射
1.反射概述
-
将类的各个组成部分封装为其他对象
-
好处:在运行时操作对象,提高程序扩展性
代码案例:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
public class ReflectionExample {
public static void main(String[] args) {
try {
// 获取类的Class对象
Class<?> personClass = Class.forName("Person");
// 获取所有public字段
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println("Public field: " + field);
}
// 获取所有public方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println("Public method: " + method);
}
// 获取所有public构造器
Constructor<?>[] constructors = personClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("Public constructor: " + constructor);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
2.反射获取字节码Class对象的三种方式
-
Class.forName()
-
类名.class
-
对象.getClass()
代码案例:
public class ReflectionExample {
public static void main(String[] args) {
// 方式1:使用Class.forName()
try {
Class<?> personClass1 = Class.forName("Person");
System.out.println(personClass1);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 方式2:使用类名.class
Class<?> personClass2 = Person.class;
System.out.println(personClass2);
// 方式3:使用对象.getClass()
Person person = new Person();
Class<?> personClass3 = person.getClass();
System.out.println(personClass3);
}
}
3.Class对象功能概述
-
获取成员变量
-
获取构造方法
-
获取成员方法
-
获取全类名
案例代码:
public class ReflectionExample {
public static void main(String[] args) {
try {
// 获取Person类的Class对象
Class<?> personClass = Class.forName("Person");
// 获取所有成员变量
Field[] fields = personClass.getDeclaredFields();
for (Field field : fields) {
System.out.println("Field: " + field);
}
// 获取所有构造方法
Constructor<?>[] constructors = personClass.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("Constructor: " + constructor);
}
// 获取所有成员方法
Method[] methods = personClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println("Method: " + method);
}
// 获取全类名
String className = personClass.getName();
System.out.println("Full class name: " + className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
4.Class对象功能_获取Field
-
Field[] getFields()
-
Field getField(String name)
-
Field[] getDeclaredFields()
-
Field getDeclaredField(String name)
案例代码:
public class ReflectionExample {
public static void main(String[] args) {
try {
// 获取Person类的Class对象
Class<?> personClass = Class.forName("Person");
// 获取所有public字段
Field[] publicFields = personClass.getFields();
for (Field field : publicFields) {
System.out.println("Public Field: " + field);
}
// 获取指定名称的public字段
Field publicField = personClass.getField("name");
System.out.println("Specific Public Field: " + publicField);
// 获取所有字段(包括private)
Field[] allFields = personClass.getDeclaredFields();
for (Field field : allFields) {
System.out.println("Field: " + field);
}
// 获取指定名称的字段(包括private)
Field privateField = personClass.getDeclaredField("age");
System.out.println("Specific Field: " + privateField);
} catch (ClassNotFoundException | NoSuchFieldException e) {
e.printStackTrace();
}
}
}
5.Class对象功能_获取Constructor
-
Constructor[] getConstructors()
-
Constructor getConstructor(参数类型…)
-
Constructor getDeclaredConstructor(参数类型…)
-
Constructor[] getDeclaredConstructors()
案例代码:
public class ReflectionExample {
public static void main(String[] args) {
try {
// 获取Person类的Class对象
Class<?> personClass = Class.forName("Person");
// 获取所有public构造器
Constructor<?>[] publicConstructors = personClass.getConstructors();
for (Constructor<?> constructor : publicConstructors) {
System.out.println("Public Constructor: " + constructor);
}
// 获取指定参数的public构造器
Constructor<?> publicConstructor = personClass.getConstructor(String.class);
System.out.println("Specific Public Constructor: " + publicConstructor);
// 获取所有构造器(包括private)
Constructor<?>[] allConstructors = personClass.getDeclaredConstructors();
for (Constructor<?> constructor : allConstructors) {
System.out.println("Constructor: " + constructor);
}
// 获取指定参数的构造器(包括private)
Constructor<?> privateConstructor = personClass.getDeclaredConstructor(String.class, int.class);
System.out.println("Specific Constructor: " + privateConstructor);
} catch (ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
}
}
}
6.Class对象功能_获取Method
-
Method[] getMethods()
-
Method getMethod(String name, 参数类型…)
-
Method[] getDeclaredMethods()
-
Method getDeclaredMethod(String name, 参数类型…)
案例代码:
public class ReflectionExample {
public static void main(String[] args) {
try {
// 获取Person类的Class对象
Class<?> personClass = Class.forName("Person");
// 获取所有public方法
Method[] publicMethods = personClass.getMethods();
for (Method method : publicMethods) {
System.out.println("Public Method: " + method);
}
// 获取指定名称和参数的public方法
Method publicMethod = personClass.getMethod("setName", String.class);
System.out.println("Specific Public Method: " + publicMethod);
// 获取所有方法(包括private)
Method[] allMethods = personClass.getDeclaredMethods();
for (Method method : allMethods) {
System.out.println("Method: " + method);
}
// 获取指定名称和参数的方法(包括private)
Method privateMethod = personClass.getDeclaredMethod("showAge");
System.out.println("Specific Method: " + privateMethod);
} catch (ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
}
}
}
7.反射案例
-
从配置文件读取类名和方法名
-
使用反射加载类、创建对象、执行方法
案例代码:
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class ReflectionExample {
public static void main(String[] args) {
try {
// 加载配置文件
Properties properties = new Properties();
InputStream inputStream = ReflectionExample.class.getClassLoader().getResourceAsStream("config.properties");
properties.load(inputStream);
// 读取配置文件中的类名和方法名
String className = properties.getProperty("class.name");
String methodName = properties.getProperty("method.name");
// 使用反射加载类
Class<?> classObj = Class.forName(className);
// 使用反射创建对象
Object obj = classObj.newInstance();
// 使用反射执行方法
Method method = classObj.getMethod(methodName);
method.invoke(obj);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、注解
1.注解概念
-
说明程序,给计算机看的
-
分类:文档、代码分析、编译检查
案例代码
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 文档注解
@Deprecated
public class AnnotationExample {
// 编译检查注解
@Override
public String toString() {
return "This is a overridden toString method";
}
// 代码分析注解
@SuppressWarnings("unchecked")
public void analyzeCode() {
// 这里会有类型转换的警告
Object obj = new Object();
String str = (String) obj;
}
// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "";
}
@MyAnnotation("Hello")
public void annotatedMethod() {
System.out.println("Annotated method");
}
}
2.JDK内置注解
-
@Override
-
@Deprecated
-
@SuppressWarnings
案例代码:
public class AnnotationExample {
// 使用@Override注解标记重写父类方法
@Override
public String toString() {
return "This is a overridden toString method";
}
// 使用@Deprecated注解标记已过时的方法
@Deprecated
public void oldMethod() {
System.out.println("This is an old method");
}
// 使用@SuppressWarnings注解压制编译器警告
@SuppressWarnings("unchecked")
public void analyzeCode() {
// 这里会有类型转换的警告
Object obj = new Object();
String str = (String) obj;
}
}
3.自定义注解_格式&本质
-
本质是接口,默认继承Annotation接口
案例代码:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 定义一个自定义注解
@Target(ElementType.METHOD) // 注解的作用目标
@Retention(RetentionPolicy.RUNTIME) // 注解的保留策略
public @interface MyAnnotation {
// 定义一个value属性
String value();
}
// 使用自定义注解
public class AnnotationExample {
// 在方法上使用自定义注解,并指定value属性值
@MyAnnotation(value = "Hello")
public void annotatedMethod() {
System.out.println("Annotated method");
}
}
4.自定义注解_属性定义
-
返回值类型:基本数据类型、String、枚举、注解、数组
-
属性赋值
案例代码:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 定义一个自定义注解
@Target(ElementType.METHOD) // 注解的作用目标
@Retention(RetentionPolicy.RUNTIME) // 注解的保留策略
public @interface MyAnnotation {
// 定义一个String类型的value属性,并指定默认值为"Hello"
String value() default "Hello";
// 定义一个int类型的age属性
int age();
// 定义一个枚举类型的gender属性
Gender gender();
// 定义一个注解类型的anno属性
MyAnnotation2 anno();
// 定义一个String数组类型的tags属性
String[] tags();
}
// 定义一个枚举类型
enum Gender {
MALE, FEMALE
}
// 定义一个自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation2 {
String value();
}
// 使用自定义注解
public class AnnotationExample {
// 在方法上使用自定义注解,并为所有属性赋值
@MyAnnotation(value = "World", age = 30, gender = Gender.MALE, anno = @MyAnnotation2("anno2"), tags = {"tag1", "tag2"})
public void annotatedMethod() {
System.out.println("Annotated method");
}
}
5.自定义注解_元注解
-
@Target
-
@Retention
-
@Documented
-
@Inherited
案例代码:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 定义一个自定义注解
@Target(ElementType.METHOD) // 指定该注解只能用于方法
@Retention(RetentionPolicy.RUNTIME) // 指定注解保留到运行时
@Documented // 指定该注解会被包含在javadoc中
@Inherited // 指定该注解可以被继承
public @interface MyAnnotation {
// 定义一个String类型的value属性,并指定默认值为"Hello"
String value() default "Hello";
}
// 使用自定义注解
public class AnnotationExample {
// 在方法上使用自定义注解
@MyAnnotation("World")
public void annotatedMethod() {
System.out.println("Annotated method");
}
}
// 继承了父类的注解
public class ChildClass extends AnnotationExample {
// 子类会继承父类的@MyAnnotation注解
@Override
public void annotatedMethod() {
System.out.println("Child class");
}
}
6.解析注解
-
获取注解定义位置的对象
-
获取指定的注解
-
调用注解方法获取属性值
案例代码:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 定义一个自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
// 定义一个String类型的value属性
String value();
}
// 使用自定义注解
public class AnnotationExample {
// 在方法上使用自定义注解,并指定value属性值
@MyAnnotation(value = "Hello")
public void annotatedMethod() {
System.out.println("Annotated method");
}
}
// 解析注解
public class AnnotationParser {
public static void main(String[] args) throws Exception {
// 获取方法对象
Method method = AnnotationExample.class.getMethod("annotatedMethod");
// 获取方法上的MyAnnotation注解
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
// 调用注解方法获取value属性值
String value = myAnnotation.value();
// 输出value属性值
System.out.println("Value: " + value);
}
}
7.注解案例_简单的测试框架
-
自定义注解
-
定义测试类
-
执行测试
案例代码:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
// 定义一个自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
// 定义一个String类型的value属性
String value();
}
// 定义一个测试类
public class TestClass {
// 定义一个测试方法,并使用自定义的Test注解
@Test(value = "测试 add 方法")
public void testAdd() {
int result = 1 + 2;
assertEquals(3, result);
}
@Test(value = "测试 subtract 方法")
public void testSubtract() {
int result = 5 - 3;
assertEquals(2, result);
}
// 定义一个断言方法
public static void assertEquals(int expected, int actual) {
if (expected != actual) {
throw new RuntimeException("测试失败:期望值=" + expected + " 实际值=" + actual);
}
}
}
// 执行测试
public class TestRunner {
public static void main(String[] args) {
Class<?> testClass = TestClass.class;
try {
// 获取测试类对象
Object testInstance = testClass.newInstance();
// 遍历测试类中的所有方法
for (Method method : testClass.getMethods()) {
// 检查方法是否使用了Test注解
if (method.isAnnotationPresent(Test.class)) {
try {
// 执行测试方法
method.invoke(testInstance);
System.out.println("测试成功:" + method.getAnnotation(Test.class).value());
} catch (Exception e) {
System.out.println("测试失败:" + method.getAnnotation(Test.class).value());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
结语:
以上内容涵盖了JUnit单元测试、反射机制、注解的概念及自定义,以及如何解析注解并应用在简单的测试框架案例中。这些知识点对于Java后端开发中的框架设计、代码规范以及测试都非常重要。通过这些知识点的学习,可以加深对Java高级特性的理解,并为后续框架学习和项目开发打下基础。
#JavaWeb
欢迎大家交流,金三银四求职季期间关注公众号送面试宝典。