单元测试、反射、注解、Lombok
1. 单元测试
1.1 Junit单元测试框架
1.2 Junit框架入门
package com.itheima.a_单元测试;
import org.junit.Test;
public class SpringUtilTest {
@Test
public void testPrintNumber() {
StringUtil.printNumber("Jack");
StringUtil.printNumber("张三");
StringUtil.printNumber("");
StringUtil.printNumber(null);
}
}
1.3 Junit框架的常见注解
package com.itheima.a_单元测试;
import org.junit.*;
public class SpringUtilTest {
@Before
public void init() {
System.out.println("===init===");
}
@After
public void destroy() {
System.out.println("===destroy===");
}
@BeforeClass
public static void initClass() {
System.out.println("===initClass===");
}
@AfterClass
public static void destroyClass() {
System.out.println("===destroyClass===");
}
@Test
public void testPrintNumber() {
StringUtil.printNumber("Jack");
StringUtil.printNumber("张三");
StringUtil.printNumber("");
}
@Test
public void testGetMaxIndex() {
StringUtil su = new StringUtil();
int i = su.getMaxIndex("我是孙庆的爹");
System.out.println("i:" + i);
}
}
1.4 Junit框架断言
package com.itheima.a_单元测试;
import org.junit.Assert;
import org.junit.Test;
public class SpringUtilTest {
@Test
public void testGetMaxIndex() {
StringUtil su = new StringUtil();
int i0 = su.getMaxIndex("我是孙庆的爹");
Assert.assertEquals("NotEquals", 5, i0);
}
}
2. 反射
2.1 认识反射、获取类
package com.itheima.b_反射;
/*
反射的第一步是什么
获取Class类对象,如此才可以解析类的全部成分
获取Class对象的三种方式
1. 直接使用类名.class获取:Class c1 = 类名.class
2. 调用Class提供的方法:Class c2 = Class.forName("全类名")
3. 调用Object提供的方法:Class c3 = 对象.getClass()
*/
public class Demo1 {
public static void main(String[] args) throws Exception {
Class c1 = Cat.class;
System.out.println(c1.getName());
Class c2 = Class.forName("com.itheima.b_反射.Cat");
System.out.println(c2.getName());
Class c3 = new Cat().getClass();
System.out.println(c3.getName());
}
}
2.2 获取类的构造器
有Declared的方法是拿所有的,没有Declared修饰的是拿公共的(public)
package com.itheima.b_反射;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
/*
获取构造器[下面是Class的方法]
Constructor<?>[] getConstructors() 获取所有的公共构造器(只能获取public修饰的)
Constructor<?>[] getDeclaredConstructors() 获取全部构造器(只要存在就能拿到)
Constructor<T> getConstructor(Class<?>... parameterTypes) 获取某个公共构造器(只能获取public修饰的)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取某个构造器(只要存在就能拿到)
使用构造器(创建对象)[下面是Constructor的方法]
T newInstance(Object... initArgs) 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
注意
使如果想使用private修饰构造器反射创建对象,需要暴力反射(禁止JVM检查构造方法的访问权限)
*/
public class Demo2 {
public static void main(String[] args) throws Exception {
Class myClass = new Cat().getClass();
// Constructor<?>[] getConstructors() 获取所有的公共构造器(只能获取public修饰的)
Constructor[] constructors = myClass.getConstructors();
// Arrays.stream(constructors).forEach(System.out::println);
// System.out.println();
// Constructor<?>[] getDeclaredConstructors() 获取全部构造器(只要存在就能拿到)
Constructor[] declaredConstructors = myClass.getDeclaredConstructors();
// Arrays.stream(declaredConstructors).forEach(System.out::println);
// System.out.println();
// Constructor<T> getConstructor(Class<?>... parameterTypes) 获取某个公共构造器(只能获取public修饰的)
Constructor<Cat> constructor = myClass.getConstructor();
Constructor<Cat> constructor1 = myClass.getConstructor(String.class);
// Constructor<Cat> constructor2 = myClass.getConstructor(String.class, int.class);
// System.out.println(constructor);
// System.out.println(constructor1);
// System.out.println(constructor2);
// System.out.println();
// Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取某个构造器(只要存在就能拿到)
Constructor<Cat> declaredConstructor = myClass.getDeclaredConstructor(String.class, int.class);
// System.out.println(declaredConstructor);
// 使用公告构造器创建对象
Cat cat = constructor.newInstance();
System.out.println(cat);
// 使用私有构造器创建对象
declaredConstructor.setAccessible(true);//暴力反射
Cat cat1 = declaredConstructor.newInstance("招财猫", 21);
System.out.println(cat1);
}
}
2.3 获取类的成员变量
package com.itheima.b_反射;
import java.lang.reflect.Field;
import java.util.Arrays;
/*
获取成员变量[Class提供]
public Field[] getFields() 获取类的所有公共成员变量(只能获取public修饰的)
public Field[] getDeclaredFields() 获取类的全部成员变量(只要存在就能拿到)
public Field getField(String name) 获取类的某个公共成员变量(只能获取public修饰的)
public Field getDeclaredField(String name) 获取类的某个成员变量(只要存在就能拿到)
使用成员变量(赋值和取值) [Field提供]
public void set(Object obj, Object value): 赋值
public Object get(Object obj): 取值
public void setAccessible(boolean flag): 设置为true,表示禁止检查访问控制(暴力反射)
注意
使如果想使用private修饰的变量,需要暴力反射
*/
public class Demo3 {
public static void main(String[] args) throws Exception {
Cat cat = new Cat();
Class<? extends Cat> catClass = cat.getClass();
// public Field getDeclaredField(String name) 获取类的某个成员变量(只要存在就能拿到)
Field name = catClass.getDeclaredField("name");
Field country = catClass.getDeclaredField("COUNTRY");
Field age = catClass.getDeclaredField("age");
//获取成员变量[Class提供]
// public Field[] getFields() 获取类的所有公共成员变量(只能获取public修饰的)
// Field[] fields = catClass.getFields();
// Arrays.stream(fields).forEach(System.out::println);
// System.out.println();
// public Field[] getDeclaredFields() 获取类的全部成员变量(只要存在就能拿到)
// Field[] declaredFields = catClass.getDeclaredFields();
// Arrays.stream(declaredFields).forEach(item-> System.out.println(item.getName()+"类型:"+item.getType()));
// public Field getField(String name) 获取类的某个公共成员变量(只能获取public修饰的)
// Field name = catClass.getField("name");
// System.out.println(name);
//使用成员变量(赋值和取值) [Field提供]
System.out.println("======");
System.out.println(name.getName());
System.out.println(age.getName());
System.out.println("======");
System.out.println(cat);
// public void set(Object obj, Object value): 赋值
String countryStr = (String) country.get(country);
System.out.println(countryStr);
// public void setAccessible(boolean flag): 设置为true,表示禁止检查访问控制(暴力反射)
name.setAccessible(true);
age.setAccessible(true);
name.set(cat, "孙庆");
age.set(cat, 21);
System.out.println(cat);
// public Object get(Object obj): 取值
String catName = (String) name.get(cat);
System.out.println(catName);
int catAge = (int) age.get(cat);
System.out.println(catAge);
System.out.println("======");
}
}
2.4 获取类的成员方法
package com.itheima.b_反射;
import java.lang.reflect.Method;
import java.util.Arrays;
/*
获取成员方法[Class提供]
Method[] getMethods() 获取类的全部公共成员方法(只能获取public修饰的)
Method[] getDeclaredMethods() 获取类的全部成员方法(只要存在就能拿到)
Method getMethod(String name, Class<?>... parameterTypes) 获取类的某个公共成员方法(只能获取public修饰的)
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 获取类的某个成员方法(只要存在就能拿到)
使用成员方法(执行方法)[Method提供]
public Object invoke(Object obj, Object... args) 触发某个对象的该方法执行。
public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
注意
使如果想使用private修饰的成员方法,需要暴力反射
*/
public class Demo4 {
public static void main(String[] args) throws Exception {
Cat cat = new Cat();
Class<? extends Cat> catClass = cat.getClass();
//获取成员方法[Class提供]
//Method[] getMethods() 获取类的全部公共成员方法(只能获取public修饰的)
// Method[] methods = catClass.getMethods();
//Method[] getDeclaredMethods() 获取类的全部成员方法(只要存在就能拿到)
System.out.println("================");
Method[] methodsArr = catClass.getDeclaredMethods();
// Arrays.stream(methods).forEach(item -> {
// System.out.println("方法名字:" + item.getName() + ",返回值类型:" + item.getReturnType() + ",参数个数:" + item.getParameterCount());
// });
//Method getMethod(String name, Class<?>... parameterTypes) 获取类的某个公共成员方法(只能获取public修饰的)
// Method method = catClass.getMethod(cat.getName());
// System.out.println(method);
//Method getDeclaredMethod(String name, Class<?>... parameterTypes) 获取类的某个成员方法(只要存在就能拿到)
Method eat = catClass.getDeclaredMethod("eat", String.class);
System.out.println(eat.getReturnType());
System.out.println(Arrays.toString(eat.getParameterTypes()));
//使用成员方法(执行方法)[Method提供]
//public Object invoke(Object obj, Object... args) 触发某个对象的该方法执行。
//public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
eat.setAccessible(true);
System.out.println(eat.invoke(cat, "鱼"));
}
}
2.5 作用、应用场景
2.6 案例
package com.itheima.b_反射;
import java.lang.reflect.Field;
import java.util.Arrays;
/*
反射案例
对于任意一个对象,该框架都可以把对象的字段名和对应的值,然后打印在控制台
*/
public class Demo5 {
public static void main(String[] args) {
//1. 准备两个对象
Student student = new Student("柳岩", 40, '女', 167.5, "女星");
Teacher teacher = new Teacher("播妞", 6000);
//2.调用方法
printInfo(student);
printInfo(teacher);
}
public static void printInfo(Object o) {
Class<?> obj = o.getClass();
Field[] list = obj.getDeclaredFields();
System.out.println("======" + obj.getSimpleName() + "======");
Arrays.stream(list).forEach(item -> {
try {
item.setAccessible(true);
System.out.println(item.getName() + "=" + item.get(o));
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
class Student {
public Student(String name, int age, char sex, double height, String hobby) {
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
this.hobby = hobby;
}
private String name;
private int age;
private char sex;
private double height;
private String hobby;
}
class Teacher {
public Teacher(String name, double salary) {
this.name = name;
this.salary = salary;
}
private String name;
private double salary;
}
3. 注解
3.1 快速入门
package com.itheima.c_annotation.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassNameCheck {
public String[] author() default "佚名";
public String value();
}
3.2 注解解析
3.3 注解属性
package com.itheima.c_annotation.example;
import com.itheima.c_annotation.ClassUtil;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class checkClassName {
public static void isRight() throws Exception {
StringBuilder sb = new StringBuilder();
//拿集合
Set<Class> classSet = ClassUtil.getClasses("com.itheima.c_annotation.example");
//遍历
System.out.println("------------");
List<Class> list = classSet.stream()
.filter(e -> e.isAnnotationPresent(ClassNameCheck.class))
.filter(e -> !e.getSimpleName().startsWith("Heima"))
.collect(Collectors.toList());
if (list.size() != 0) {
list.stream().forEach(e -> {
ClassNameCheck annotation = (ClassNameCheck) e.getDeclaredAnnotation(ClassNameCheck.class);
System.out.print(e.getSimpleName() + "作者:");
Arrays.stream(annotation.author()).forEach(System.out::print);
System.out.println(",作用:" + annotation.value());
});
throw new Exception("类名不规范");
}
System.out.println("------------");
}
}
获取某个包下所有的类
package com.itheima.c_annotation;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.FileFilter;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import static cn.hutool.core.util.ClassUtil.getClassLoader;
public class ClassUtil {
private ClassUtil() {
}
/**
* 获取某个包下的所有类
*/
public static Set<Class> getClasses(String packageName) {
try {
Set<Class> classSet = new HashSet<>();
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageName.replace(".", "/"));
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
if (url != null) {
String protocol = url.getProtocol();
if (protocol.equals("file")) {
String packagePath = url.getPath().replaceAll("%20", " ");
addClass(classSet, packagePath, packageName);
} else if (protocol.equals("jar")) {
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
if (jarURLConnection != null) {
JarFile jarFile = jarURLConnection.getJarFile();
if (jarFile != null) {
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String jarEntryName = jarEntry.getName();
if (jarEntryName.endsWith(".class")) {
String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
doAddClass(classSet, className);
}
}
}
}
}
}
}
return classSet;
} catch (Exception e) {
throw new RuntimeException("包名错误");
}
}
private static void addClass(Set<Class> classSet, String packagePath, String packageName) {
File[] files = new File(packagePath).listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
}
});
for (File file : files) {
String fileName = file.getName();
if (file.isFile()) {
String className = fileName.substring(0, fileName.lastIndexOf("."));
if (StringUtils.isNotEmpty(packageName)) {
className = packageName + "." + className;
}
doAddClass(classSet, className);
} else {
String subPackagePath = fileName;
if (StringUtils.isNotEmpty(packagePath)) {
subPackagePath = packagePath + "/" + subPackagePath;
}
String subPackageName = fileName;
if (StringUtils.isNotEmpty(packageName)) {
subPackageName = packageName + "." + subPackageName;
}
addClass(classSet, subPackagePath, subPackageName);
}
}
}
/**
* 加载类
*/
private static Class loadClass(String className, boolean isInitialized) {
Class cls;
try {
cls = Class.forName(className, isInitialized, getClassLoader());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return cls;
}
/**
* 加载类(默认将初始化类)
*/
private static Class loadClass(String className) {
return loadClass(className, true);
}
private static void doAddClass(Set<Class> classSet, String className) {
Class cls = loadClass(className, false);
classSet.add(cls);
}
}