步骤:
定义一个测试类(测试用例)
建议:
a. 测试类名:被测试的类名Test CalculatorTest
b. 包名:xxx.xxx.xx.test cn.itcast.test
定义测试方法:可独立运行
建议:
a. 方法名:test测试的方法名 testAdd()
b. 返回值:void
c. 参数列表:空参
给方法加 @Test
导入 junit 依赖环境
判定结果:
红色:失败
绿色:成功
一般我们会使用断言操作来处理结果:
Assert.assertEquals(期望的结果,运算的结果)
java.lang.Class
Class Class
枚举是一种类,注解是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class
对象。基本的 Java 类型(boolean
、byte
、char
、short
、int
、long
、float
和 double
)和关键字 void
也表示为 Class
对象。
Class
没有公共构造方法。Class
对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass
方法自动构造的。
类型参数:
T
- 由此 Class
对象建模的类的类型。
例如,String.class
的类型是 Class<String>
。如果将被建模的类未知,则使用 Class<?>
。
1. Class.forName("全类名"): 将字节码文件加载进内存,返回Class对象 <"全类名"即是:包名.类名> 多用于配置文件,将类名定义在配置文件中,读取文件,加载类。 2. 类名.class:通过类名的属性class获取 多用于参数的传递 3. 对象.getClass():getClass()方法在Object类中定义着,返回此Object运行时类。 多用于对象获取字节码的方式 注意: 同一个字节码文件(*.class)在一次程序运行过程中只会被加载一次,不论通过哪种方式获取的Class对象都是同一个。
public class ReflectDemo1{ public static void main(String[] args) throws ClassNotFoundException { //1. Class.forName("全类名") 全类名:包名.类名。 Class cls1 = Class.forName("day13.reflection.demo1.Person"); System.out.println(cls1); //2. 类名.class Class<Person> cls2 = Person.class; System.out.println(cls2); //3. 对象.getClass() Person p = new Person(); Class<? extends Person> cls3 = p.getClass(); System.out.println(cls3); //相同字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪种方式获取的Class对象都是同一个! System.out.println(cls1 == cls2); //true System.out.println(cls1 == cls3); //true } }
获取功能:
①获取成员变量:
Field[] getFields(); 获取所有public修饰的成员变量 (所有public) Field getField(String name); 获取指定名称的public修饰的成员变量 (单个) Field[] getDeclaredFields(); 获取所有的成员变量,不考虑修饰符 (所有) Field getDeclaredField(String name); 获取指定名称的成员变量 (单个)
import java.lang.reflect.Field; public class ReflectDemo2 { public static void main(String[] args) throws Exception { //获取Class对象 Class cls = Person.class; //1.Field[] getFields(); 获取所有public修饰的成员变量 Field[] fields = cls.getFields(); for(Field f : fields){ System.out.println(f); } System.out.println("-----------------------"); /* Field getField(String name); 获取指定名称的public修饰的成员变量 操作:<Field类中的两个方法:> ①设置值:void set(Object obj,Object value) ②获取值:Object get(Object obj) ③忽略访问权限修饰符的安全检查: setAccessible(true); 暴力反射-->解决访问私有属性时抛出的IllegalAccessException异常! 访问私有属性/方法时,均可使用暴力反射! */ Field a = cls.getField("a"); Person p = new Person(); //获取成员变量a的值 Object value = a.get(p); System.out.println(value); //设置a的值 a.set(p,"Basketball"); System.out.println(p); System.out.println("========================="); //Field[] getDeclaredFields(); 获取所有的成员变量,不考虑修饰符 Field[] declaredFields = cls.getDeclaredFields(); for(Field f : declaredFields){ System.out.println(f); } //Field getDeclaredField(String name); 获取指定名称的成员变量 Field d = cls.getDeclaredField("d"); //忽略访问权限修饰符的安全检查 d.setAccessible(true); //暴力反射-->解决访问私有属性时出现的IllegalAccessException! //获取私有成员变量d的值 System.out.println(d.get(p)); } }
②获取构造方法:
Constructor<?>[] getConstructors(); Constructor<T> getConstructor(Class<?>... parameterTypes); Constructor<?>[] getDeclaredConstructors(); Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes); java.lang.reflect.Constructor类: public T newInstance(Object... initargs); 用于创建有参对象 java.lang.Class类: public T newInstance(); 创建由此类对象表示的类的新实例(用于无参构造的创建) public ClassLoader getClassLoader(); 返回该类的类加载器
import java.lang.reflect.Constructor; public class ReflectDemo3 { public static void main(String[] args) throws Exception { //获取Class类对象 Class cls = Person.class; //Constructor<T> getConstructor(Class<?>... parameterTypes); Constructor constructor = cls.getConstructor(String.class,int.class); //创建对象 Object obj = constructor.newInstance("杜兰特",35); //System.out.println(obj.getClass()); //Object类中的getClass():返回此Object的运行时类。 System.out.println(obj); System.out.println("-----------------------------"); //创建对象:无参 Constructor constructor1 = cls.getConstructor(); Object obj1 = constructor1.newInstance(); System.out.println(obj1); //Class类中的 public T newInstance(); 创建由此类对象表示的类的新实例 Object o = cls.newInstance(); System.out.println(o); } }
③获取成员方法:
Method[] getMethods(); Method getMethod(String name,Class<?>... parameterTypes); Method[] getDeclaredMethods(); Method getDeclareMethod(String name,Class<?>... parameterTypes); java.lang.reflect.Method类: public Object invoke(Object obj,Object... args); 对带有指定参数的指定对象调用由此Method对象表示的底层方法(执行方法) public String getName(); 以 String 形式返回此 Method 对象表示的方法名称。
import java.lang.reflect.Method; public class ReflectDemo4 { public static void main(String[] args) throws Exception { //获取Class类对象 Class cls = Class.forName("day13.reflection.demo1.Person"); Method eat_method = cls.getMethod("eat"); System.out.println(eat_method); Person p = new Person(); //执行方法 eat_method.invoke(p); Method eat = cls.getMethod("eat", String.class); //执行方法 eat.invoke(p,"土豆"); System.out.println("==============================="); //获取所有public修饰的方法 Method[] methods = cls.getMethods(); for (Method method : methods) { System.out.println(method); String name = method.getName(); //获取方法名称 getName(); System.out.println(name); //method.setAccessible(true); //暴力反射 } //获取类名:String getName() String className = cls.getName(); System.out.println(className); } }
④获取类名
public String getName(); 获取类名
Class类: public ClassLoader getClassLoader();返回该类的类加载器 ClassLoader抽象类: public InputStream getResourceAsStream(String name);返回用于读取指定资源的输入流 Properties集合类: java.util.Properties extends java.util.Hashtable<K,V> implements Map<K,V> public void load(InputStream inStream);从输入字节流读取属性列表(键值对) public String getProperty(String key);用指定的键在此属性列表中搜索属性
import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Method; import java.util.Properties; /* 需求: 写一个“框架”,不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法。 实现: 1.配置文件 2.反射 步骤: 1.将需要创建的对象的全类名和需要执行的方法定义在配置文件中 2.在程序中加载读取配置文件 3.使用反射技术来加载类文件进内存 4.创建对象 5.执行方法 */ public class ReflectTest { /* 前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法。 */ public static void main(String[] args) throws Exception { //1.创建Properties对象 Properties pro = new Properties(); //2.通过类加载器获取配置文件 ClassLoader cl = ReflectTest.class.getClassLoader(); //配置文件要放在src路径下面!否则出现NullPointException InputStream is = cl.getResourceAsStream("pro.properties"); //3.加载配置文件 pro.load(is); //4.获取配置文件中定义的数据 String className = pro.getProperty("className"); String methodName = pro.getProperty("methodName"); //5.加载该类进内存 Class cls = Class.forName(className); //6.创建对象 Object o = cls.newInstance(); //7.执行方法 Method method = cls.getMethod(methodName); method.invoke(o); } }
注解(Annotation):也叫元数据。一种代码级别的说明,JDK1.5及以后版本引入的新特性,与类、接口、枚举同属一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明、注释。
概念描述:
java.lang.annotation.Interface Annotation: 所有 annotation 类型都要扩展的公共接口。
①编写文档:通过代码里标识的注解生成文档【生成doc文档】
②代码分析:通过代码里标识的注解对代码进行分析【使用反射】
③编译检查:通过代码库标识的注解让编译器能够实现基本的编译检查【Override】