JavaEE学习日志持续更新----> 必看!JavaEE学习路线(文章总汇)
Java学习日志(二十五)
Junit单元测试
Junit单元测试:单独执行某一个方法
使用步骤:
- 导入Junit的jar包
- 在方法上添加一个@Test注解,并导入test注解所在的包
- 点击方法左边的绿色三角/右键选择方法,选择run执行方法
点击类左边的绿色三角/右键选择方法,选择run执行全部被@Test修饰的方法
Junit的注意事项:
1.没有被@Test注解修饰的方法,不能使用Junit单独执行
2.Junit只能执行public void 修饰的空参数方法
Junit相关的注解:
@Test
,用于修饰需要执行的测试方法@Before
,修饰的方法会在测试方法之前被自动执行,用于获取资源@After
,修饰的方法会在测试方法执行之后自动被执行,用于释放资源
注意:
@Before和@After修饰的方法,不能单独执行
代码示例:
public class Demo03 {
@Test
public void test01() {
System.out.println("test01");
}
@Test
public void test02() {
System.out.println("test02");
}
@Test
public void test03() {
System.out.println("test03");
}
@Before
public void myBefore() {
System.out.println("myBefore");
}
@After
public void myAfter() {
System.out.println("myAfter");
}
}
反射
类加载器
反射的概念与原理
看图就完事了
获取class文件对象的方式
获取class文件对象的方式(重点):
- 可以使用Object类中的方法,获取class文件对象
Class<?> getClass()
返回此 Object的运行时类。 - 可以使用数据类型.class属性,获取class文件对象
java为每种数据类型,都赋予了一个class属性
基本数据类型(4类8种):int.class,double.class
引用数据类型(类,接口,数组):Person.class,String.class,ArrayList<String>.class
- 可以使用class类中的静态方法,获取class文件对象
static Class<?> forName(String className)
返回与具有给定字符串名称的类或接口关联的类对象。
参数:String className:全类名(包名+类名:cn.itcast.demo02.Reflect.Person)
选中类名,右键copyReference即可拷贝包名+类名
注意:class文件对象是由类加载器创建的,无论用哪种方法获取,都是同一个class文件对象,class文件对象只有一个。
代码示例:Person类
public class Person {
private String name;
private int age;
private Person(String name) {
this.name = name;
System.out.println("Person类的私有构造方法");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person类的满参数构造方法");
}
public Person() {
System.out.println("Person类的空参数构造方法");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
private void method(){
System.out.println("私有方法");
}
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;
}
}
测试类
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException {
//1.可以使用Object类中的方法,获取class文件对象
Person p = new Person();
Class c1 = p.getClass();
System.out.println(c1);//class cn.itcast.demo02.Reflect.Person
//2.可以使用数据类型.class属性,获取class文件对象
/*int.class;
double.class;
String.class;*/
Class c2 = Person.class;
System.out.println(c2);//class cn.itcast.demo02.Reflect.Person
//3.可以使用class类中的静态方法,获取class文件对象
Class c3 = Class.forName("cn.itcast.demo02.Reflect.Person");
System.out.println(c3);//class cn.itcast.demo02.Reflect.Person
//class文件对象只有一个
System.out.println(c1==c2);//true
System.out.println(c1==c3);//true
System.out.println(c2==c3);//true
}
}
Class类中的常用方法
Class类中的常用方法
String getSimpleName()
:获得简单类名,只是类名,没有包String getName()
:获取全类名,包含包名+类名
在Person类中加入一个静态代码块
static {
System.out.println("静态代码块");
}
代码示例:获取class文件对象,会执行类中的静态代码块
public class Demo02 {
public static void main(String[] args) throws ClassNotFoundException {
//获取class文件对象,会执行类中的静态代码块-->mysql-->JDBC
Class clazz = Class.forName("cn.itcast.demo02.Reflect.Person");
String simpleName = clazz.getSimpleName();
System.out.println(simpleName);//Person
String name = clazz.getName();
System.out.println(name);//cn.itcast.demo02.Reflect.Person
}
}
获取类中的构造方法并创建对象
使用反射技术获取类中的构造方法,并使用获取到的构造方法创建对象
获取构造方法
实现步骤:
- 获取类的class文件对象
- 使用class文件对象中的方法
getConstructor/Constructors
获取类中的构造方法 - 使用Constructor类中的方法newInstance创建对象(实例化对象)
Person类中的三个构造方法:
public Person()
:空参构造
private Person(String name)
:私有构造
public Person(String name, int age)
:满参构造
成员方法:
构造器<?>[] getConstructors()
返回一个包含构造器对象的数组,构造器对象反映了此类对象所表示的类的所有公共构造函数。构造器<?>[] getDeclaredConstructors()
返回构造器对象的数组,构造器对象反映由此类对象表示的类声明的所有构造函数(包括私有)。构造器<T> getConstructor(类<?>... parameterTypes)
返回一个 构造器对象,该对象反映此 类对象所表示的类的指定公共构造函数。
参数:类<?>… parameterTypes:可变参数,构造方法参数的class文件对象构造器<T> getDeclaredConstructor(类<?>... parameterTypes)
返回一个构造器对象,该对象反映此类对象所表示的类或接口的指定构造函数(包括私有)。
注意:如果类中没有指定的构造方法,会抛出NoSuchMethodException异常
代码示例:获取类中的构造方法
public class Demo03GetConstructor {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
//1.获取类的class文件对象
Class<?> clazz = Class.forName("cn.itcast.demo02.Reflect.Person");
//2.使用class文件对象中的方法getConstructor/Constructors获取类中的构造方法
//构造器<?>[] getConstructors()
Constructor<?>[] cons = clazz.getConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
System.out.println("--------------------");
//构造器<?>[] getDeclaredConstructors()
Constructor<?>[] declaredCons = clazz.getDeclaredConstructors();
for (Constructor<?> con : declaredCons) {
System.out.println(con);
}
System.out.println("--------------------");
//构造器<T> getConstructor(类<?>... parameterTypes)
//public Person()
Constructor<?> con1 = clazz.getConstructor();
System.out.println(con1);//public cn.itcast.demo02.Reflect.Person()
//public Person(String name, int age)
Constructor<?> con2 = clazz.getConstructor(String.class, int.class);
System.out.println(con2);
//构造器<T> getDeclaredConstructor(类<?>... parameterTypes)
//private Person(String name)
Constructor<?> con3 = clazz.getDeclaredConstructor(String.class);
System.out.println(con3);
}
}
newInstance方法创建对象
java.lang.reflect.Constructor :描述构造方法的类
使用Constructor类中的方法newInstance创建对象(实例化对象)
成员方法:
T newInstance(Object... initargs)
:实例化对象,创建对象
参数:Object... initargs:可变参数,构造方法创建对象实际使用的参数
返回值:T:创建好的对象,类型使用Object类型
私有的构造方法,没有权限访问,执行的时候有权限检查,会抛出
IllegalAccessException非法访问异常
。
可以使用Constructor的父类中的方法解决这个问题
Constructor extends AccessibleObject
void setAccessible(boolean flag)
将此反射对象的 accessible标志设置为指示的布尔值。
- true:表示反射对象在使用时应禁止检查Java语言访问控制
- false:表示反射对象在使用时应强制检查Java语言访问控制
代码示例:
public class Demo03GetConstructor {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取类的class文件对象
Class<?> clazz = Class.forName("cn.itcast.demo02.Reflect.Person");
//2.使用class文件对象中的方法getConstructor/Constructors获取类中的构造方法
//构造器<?>[] getConstructors()
Constructor<?>[] cons = clazz.getConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
System.out.println("--------------------");
//构造器<?>[] getDeclaredConstructors()
Constructor<?>[] declaredCons = clazz.getDeclaredConstructors();
for (Constructor<?> con : declaredCons) {
System.out.println(con);
}
System.out.println("--------------------");
//构造器<T> getConstructor(类<?>... parameterTypes)
//public Person()
Constructor<?> con1 = clazz.getConstructor();
System.out.println(con1);//public cn.itcast.demo02.Reflect.Person()
//public Person(String name, int age)
Constructor<?> con2 = clazz.getConstructor(String.class, int.class);
System.out.println(con2);
//构造器<T> getDeclaredConstructor(类<?>... parameterTypes)
//private Person(String name)
Constructor<?> con3 = clazz.getDeclaredConstructor(String.class);
System.out.println(con3);
//3.使用Constructor类中的方法newInstance创建对象(实例化对象)
/*
java.lang.reflect.Constructor<T> :描述构造方法的类
T newInstance(Object... initargs) :实例化对象,创建对象
参数:Object... initargs:可变参数,构造方法创建对象实际使用的参数
返回值:T:创建好的对象,类型使用Object类型
*/
//public Person()
Object obj1 = con1.newInstance();//此方法相当于new Person();
System.out.println(obj1);//Person{name='null', age=0}
/*Person p = (Person)obj1;
System.out.println(p);////Person{name='null', age=0}*/
//public Person(String name, int age)
Object obj2 = con2.newInstance("老王",18);//此方法相当于new Person("老王",18);
System.out.println(obj2);
/*
私有的构造方法,没有权限访问,执行的时候有权限检查,会抛出
IllegalAccessException非法访问异常。
可以使用Constructor的父类中的方法解决这个问题
Constructor extends AccessibleObject
void setAccessible(boolean flag) 将此反射对象的 accessible标志设置为指示的布尔值。
值true表示反射对象在使用时应禁止检查Java语言访问控制。
值false表示反射对象在使用时应强制检查Java语言访问控制
注意:暴力反射不建议使用,破坏了类的封装性
*/
//private Person(String name)
con3.setAccessible(true);//取消con3构造方法的权限检查-->暴力反射
Object obj3 = con3.newInstance("老张");
System.out.println(obj3);
}
}
简便写法–>直接创建空参构造
使用反射技术获取构造方法并创建对象的简便方式:
Class类中的成员方法:
T newInstance()
直接获取空参构造并创建对象返回,省略了获取Constructor的过程
使用前提:
- 类中必须有空参构造
- 空参数构造方法的修饰符不能是private,建议使用public
代码示例:
public class Demo04 {
public static void main(String[] args) throws Exception {
//获取class文件对象
Class<?> clazz = Class.forName("cn.itcast.demo02.Reflect.Person");
//直接使用newInstance方法获取对象
Object obj = clazz.newInstance();
System.out.println(obj);
//取代了
Object obj2 = clazz.getDeclaredConstructor().newInstance();
System.out.println(obj2);
}
}
获取类中的成员方法并执行
获取成员方法
使用反射技术获取类中的成员方法,并执行
执行步骤
- 获取类的class文件对象
- 使用class文件对象中的方法getMethod/getMethods获得成员方法
- 使用Method类中的方法invoke执行获取到的成员方法
Person类中的成员方法:
public String getName()
public void setName(String name)
private void method()
Class类中的方法:
-
方法[] getMethods()
获取类中所有公共的成员方法,包括父类和接口中的 -
方法[] getDeclaredMethods()
返回一个包含 方法对象的数组, 方法对象反映此 类对象表示的类或接口的所有已声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承的方法。 -
方法 getMethod(String name, 类<?>... parameterTypes)
获取指定的公共成员方法 -
方法 getDeclaredMethod(String name, 类<?>... parameterTypes)
返回 方法对象,该对象反映此 类对象表示的类或接口的指定声明方法。参数: String name:方法名称 类<?>... parameterTypes:成员方法参数列表的class文件对象
注意:类中没有指定的成员方法,会抛出NoSuchMethodException
代码示例:
public class Demo05 {
public static void main(String[] args) throws NoSuchMethodException {
//1.获取类的class文件对象
Class clazz = Person.class;
//2.使用class文件对象中的方法getMethod/getMethods获得成员方法
/*
方法[] getMethods() 获取类中所有公共的成员方法,包括父类和接口中的
方法[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映此 类对象表示的类或接口的所有已声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承的方法。
*/
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("------------------------------------");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println("------------------------------------");
/*
方法 getMethod(String name, 类<?>... parameterTypes)获取指定的公共成员方法
方法 getDeclaredMethod(String name, 类<?>... parameterTypes) 返回 方法对象,该对象反映此 类对象表示的类或接口的指定声明方法。
参数:String name:方法名称
类<?>... parameterTypes:成员方法参数列表的class文件对象
注意:类中没有指定的成员方法,会抛出NoSuchMethodException
*/
//public String getName()
Method getNameMethod = clazz.getMethod("getName");
System.out.println(getNameMethod);
//public void setName(String name)
Method setNameMethod = clazz.getMethod("setName", String.class);
System.out.println(setNameMethod);
//private void method()
Method privateMethod = clazz.getDeclaredMethod("method");
System.out.println(privateMethod);
}
}
invoke方法执行获取到的成员方法
java.lang.reflect.Method :描述成员方法的类
Method类中的invoke方法:
Object invoke(Object obj, Object... args)
执行成员方法
参数:
Object obj:invoke方法需要对象支持,执行的是哪个类的方法,就传递哪个对象,执行的是Person类的方法,传递Person对象(clazz.newInstance())。
Object... args:成员方法执行的时候,需要的实际参数。
返回值:
Object:方法的返回值,如果方法有返回值则返回对应的值,如果没有返回值,返回null。
注意:私有方法没有权限执行,有权限检查,会抛出IllegalAccessException
使用暴力反射,取消权限检查。
代码示例:
public class Demo05 {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//1.获取类的class文件对象
Class clazz = Person.class;
//2.使用class文件对象中的方法getMethod/getMethods获得成员方法
/*
方法[] getMethods() 获取类中所有公共的成员方法,包括父类和接口中的
方法[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映此 类对象表示的类或接口的所有已声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承的方法。
*/
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("------------------------------------");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println("------------------------------------");
/*
方法 getMethod(String name, 类<?>... parameterTypes)获取指定的公共成员方法
方法 getDeclaredMethod(String name, 类<?>... parameterTypes) 返回 方法对象,该对象反映此 类对象表示的类或接口的指定声明方法。
参数:String name:方法名称
类<?>... parameterTypes:成员方法参数列表的class文件对象
注意:类中没有指定的成员方法,会抛出NoSuchMethodException
*/
//public String getName()
Method getNameMethod = clazz.getMethod("getName");
System.out.println(getNameMethod);
//public void setName(String name)
Method setNameMethod = clazz.getMethod("setName", String.class);
System.out.println(setNameMethod);
//private void method()
Method privateMethod = clazz.getDeclaredMethod("method");
System.out.println(privateMethod);
System.out.println("----------------------------------");
//3.使用Method类中的方法invoke执行获取到的成员方法
/*
java.lang.reflect.Method :描述成员方法的类
Object invoke(Object obj, Object... args) 执行成员方法
参数:Object obj:invoke方法需要对象支持,执行的是哪个类的方法,就传递哪个对象
执行的是Person类的方法,传递Person对象(clazz.newInstance())
Object... args:成员方法执行的时候,需要的实际参数
返回值:Object:方法的返回值
如果方法有返回值则返回对应的值,如果没有返回值,返回null
*/
Object obj = clazz.newInstance();
//public String getName()
Object v1 = getNameMethod.invoke(obj);//此方法相当于执行了getName方法
System.out.println("v1:"+v1);//v1:null
////public void setName(String name)
Object v2 = setNameMethod.invoke(obj,"老王");//此方法相当于执行了setName方法,给成员遍历赋值
System.out.println("v2:"+v2);//v2:null 方法没有返回值
System.out.println(obj);
/*
私有方法没有权限执行,有权限检查,会抛出IllegalAccessException
使用暴力反射,取消权限检查
*/
privateMethod.setAccessible(true);
//private void method()
privateMethod.invoke(obj);
}
}
反射案例:基本框架的创建
反射案例: 基本框架的创建