一、什么是类加载器
类加载器
类加载器:负责将.class文件(存储的物理文件)加载在到内存中
类加载的过程
类加载时机
类在什么时候会被加载到内存中呢?
类加载时机
- 创建类的实例(对象)
- 调用类的类方法
- 访问类或者接口的类变量,或者为该类变量赋值
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类 直接使用java.exe命令来运行某个主类
用到就加载,不用不加载 ![](https://img-blog.csdnimg.cn/7d7a16248bcf48b2950b7838d73a7cd1.png)
类加载的过程
类加载的过程的小结
当一个类被使用的时候,才会加载到内存
类加载的过程如下:
加载、验证、准备、解析、初始化
类加载的过程
加载 ![](https://img-blog.csdnimg.cn/452d0077ae3e4b1890214d15e738b211.png)
验证 ![](https://img-blog.csdnimg.cn/492ef1ba991e4212868f60afde85c5b6.png)
准备 ![](https://img-blog.csdnimg.cn/57afa38d94dd478b88f33a10d0966077.png)
解析
解析 ![](https://img-blog.csdnimg.cn/01c7c62342594528b4bb2bba464a3392.png)
初始化 ![](https://img-blog.csdnimg.cn/91404a3ee3624701b8f21c7b1d576329.png)
类加载器的分类
类加载器的分类
启动类加载器(Bootstrap ClassLoader):虚拟机内置的类加载器。
平台类加载器(Platform Classloader):负责加载JDK中一些特殊的模块。
系统类加载器(System Classloader):负责加载用户类路径上所指定的类库。
package com.myclassloader;
/**
* 获取类加载器
*/
public class ClassLoaderDemo1 {
public static void main(String[] args) {
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
//获取系统类加载器的父加载器 --- 平台类加载器
ClassLoader classLoader1 = systemClassLoader.getParent();
//获取平台类加载器的父加载器 --- 启动类加载器
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println("系统类加载器" + systemClassLoader);
System.out.println("平台类加载器" + classLoader1);
System.out.println("启动类加载器" + classLoader2);
}
}
package com.day015_Teacher.demo02_ClassLoader;
public class MyLoader {
public static void main(String[] args) {
ClassLoader s = ClassLoader.getSystemClassLoader();
System.out.println(s);
// 使用任意一个java类的对象的字节码文件对象,也可以获取它的类加载器
ClassLoader s2 = MyLoader.class.getClassLoader();
System.out.println(s2);
}
}
jdk.internal.loader.ClassLoaders$AppClassLoader@3fee733d
jdk.internal.loader.ClassLoaders$AppClassLoader@3fee733dProcess finished with exit code 0
所以:两种方式都是一样的
类加载器
方法名 | 说明 |
public static ClassLoader getSystemClassLoader() | 获取系统类加载器 |
public InputStream getResourceAsStream(String name) | 加载某一个资源文件 |
package com.myclassloader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ClassLoaderDemo2 {
public static void main(String[] args) throws IOException {
//static ClassLoader getSystemClassLoader() 获取系统类加载器
//InputStream getResourceAsStream(String name) 加载某一个资源文件
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
//利用加载器去加载一个指定的文件
//参数:文件的路径
//返回值:字节流。
InputStream is = systemClassLoader.getResourceAsStream("prop.properties");
Properties prop = new Properties();
prop.load(is);
System.out.println(prop);
is.close();
}
}
{name=zhangsan, age=13}
Process finished with exit code 0
package com.day015_Teacher.demo02_ClassLoader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;
public class ClassLoaderDemo2 {
public static void main(String[] args) throws IOException {
//static ClassLoader getSystemClassLoader() 获取系统类加载器
//InputStream getResourceAsStream(String name) 加载某一个资源文件
//用getClassLoader方法了,就是先获取系统类加载器,然后再利用类加载器读1.txt文件,生成一个字节输入流对象
// 而系统类加载器默认读文件的路径是从src开始读的,所以能读到;
//InputStream is = ClassLoaderDemo2.class.getClassLoader() .getResourceAsStream("1.txt");
// 不用getClassLoader方法,就是直接利用当前类的字节码文件对象读1.txt文件,生成一个字节输入流对象
// 而当前文件的字节码文件对象默认读文件的路径是从当前文件的包下开始读的,所以读不到;就得到了null
InputStream is = ClassLoaderDemo2.class.getResourceAsStream("1.txt");
// System.out.println(is);
//利用加载器去加载一个指定的文件
//参数:文件的路径
//返回值:字节流。
//ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
//InputStream is = systemClassLoader.getResourceAsStream("1.txt");
InputStreamReader isr = new InputStreamReader(is,"utf-8");
Properties prop = new Properties();
prop.load(isr);
System.out.println(prop);
is.close();
}
}
二、反射 学习的反射、动态代理、正则表达式、注解
反射是: 1.反射就是一个在程序运行期间,动态的获取类中的“组成部分” 的技术
类的组成部分包含:
成员变量,java写了一个Field类来描述所有类的成员变量;(把类中的成员变量,单独取出来,形成的事物)
成员方法,java写了一个Method类来描述所有类中的成员方法;(把类中的成员方法,单独取出来,形成的事物)
构造方法,java写了一个Constructor类来描述所有类中的构造方法;(把类中的构造方法,单独提取出来,形成的事物)
把java文件编译后,形成的class 文件看成一类事物,这一类事物,java写了一个Class类描述;(描述类的类)
用处:可以在代码运行期间,单独的操作类的某个组成部分
使用步骤:固定套路
1.获取一个类的字节码文件对象;(拿类的肉身 Class)
2.从字节码文件对象中获取每个组成部分;(解刨)
3.面向每个组成部分,单独操作;(让各个器官 运行起来啦,具体类:Field,Constructor,Mehod)
获取字节码3种方式:(不管使用哪一种方式,最终获取的都是同一份字节码文件)
1.通过对象,调用getClass()方法;
2.直接使用类名.class
3.通过Class类的静态方法,forName(类的全路径)
从字节码文件对象中获取每个组成部分;(解刨)
获取构造方法对象:
把类中的构造方法,单独取出来之后,提取到的这个"事物",就是构造方法对象,
而这个对象的类型就是:Constructor
从Class类中,可以找到两种获取构造方法对象的方式:
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
Constructor<?>[] getConstructors()
返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法
暴力反射:
当反射的方法名中带有:Declared就是暴力反射,暴力反射可以获取类中私有的内容
反射成员变量:
暴力反射成员变量:
反射成员方法:
反射的应用场景:
![]()
动态代理
动态代理是:在代码中运行期间,动态的给“目标类”生产一个“代理对象”,让使用者面向“代理对象”操作“目标类”;
java中的动态代理相关类:Proxy类中,提供了一个静态方法,
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
传递三个参数即可动态的产生出一个代理对象;
使用前提:目标类必须实现的有接口!将来动态产生的"代理对象"本质上是"目标类"的兄弟!
动态代理的实现代码:
两个方法,5个参数; ClassLoader loader Class<?>[] interfaces InvocationHandler h
1.Proxy类中的静态方法newProxyInstance(目标类的类加载器,目标类实现的所有接口的数组,增强的逻辑);
I 2.nvocationHandler 接口中的invoke
不能用
(即将动态产生的代理对象,目标类中的每一个方法对象,目标类中的每一个方法需要的实际参数);
![]()
/* * 动态代理 * 动态的给刘德华生产一个代理对象 * */ public class Test { public static void main(String[] args) { // 0: 准备一个目标对象 Class c = LDH.class; //1:直接利用java提供的静态方法,创建刘德华的代理对象 Star dl = (Star) Proxy.newProxyInstance (c.getClassLoader(), c.getInterfaces(), new InvocationHandler() { // proxy : 即将产生的代理对象(不能用), // method: 目标类(刘德华)中的每一个方法对象; // args: 目标类执行时,所需要的实际参数; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 增强的逻辑,将来我们执行目标类中的任意一个方法的时候,都会执行这一段代码 //对目标类中的方法进行判断 if ("sing".equals(method.getName())){ //参数判断,如果金额小于1000,不唱歌 double v = (double) args[0]; if (v<1000){ System.out.println("代理看到的金额是:" + args[0] + "他嫌少,不让刘得花唱歌!"); }else { System.out.println("代理看到的金额是:" + args[0] + "他从中拿了:" + v*0.6); method.invoke(c.newInstance(),v*0.4); } return null; }else if ("dance".equals(method.getName())){ System.out.println("代理卖力的表演,然后请刘得花出场..."); Object res = method.invoke(c.newInstance(), args); System.out.println("代理看到了刘得花的返回值:" + res); return "代理出了一身汗"; }else { //其他方法不做任何增强 return method.invoke(c.newInstance(), args); } } }); // 2: dl对象,调用唱歌和跳舞的方法 dl.sing(3000); String dance = dl.dance(2000); System.out.println(dance); } }
![]()
正则表达式
正则表达式是:是由一些特殊的符号组成的,它代表的是某种规则。
是一个字符串,这个字符串可以描述其他字符的“规则”
作用:用来校验字符串数据是否合法;可以从一段文本中查找满足要求的内容
效验电话: 简单使用(效验字符串是否合法)
![]()
信息爬取: 匹配字符串内容使用(信息筛选)
贪婪匹配和非贪婪匹配:
字符串的切分和替换:
反射概述
Java反射机制
是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意属性和方法;
这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
![]()
反射概述
程序员
Java反射机制
是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意方法和属性;
这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
Java反射机制
利用反射可以无视修饰符获取类里面所有的属性和方法。
先获取配置文件中的信息,动态获取信息并创建对象和调用方法
获取Class对象
获取Class类的对象
Class.forName(“全类名”);//包名+类名
类名.class
对象.getClass();
package com.myreflect.myreflect2;
/**
* 获取class对象的三种方式
*/
public class ReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
//1.Class类中的静态方法forName("全类名")
//全类名:包名 + 类名
Class clazz = Class.forName("com.myreflect.myreflect2.Student");
System.out.println(clazz);
//2.通过class属性来获取
Class clazz2 = Student.class;
System.out.println(clazz2);
//3.利用对象的getClass方法来获取class对象
//getClass方法是定义在Object类中.
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz3);
System.out.println(clazz == clazz2);
System.out.println(clazz2 == clazz3);
}
}
class com.myreflect.myreflect2.Student
class com.myreflect.myreflect2.Student
class com.myreflect.myreflect2.Student
true
true
Process finished with exit code 0
Class.forName(“全类名”);//包名+类名
类名.class
对象.getClass();
反射获取构造方法
获取Class类的对象
反射获取构造方法并使用
反射获取构造方法并使用
Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
Constructor<T> getConstructor(Class<?>... parameterTypes):返回单个公共构造方法对象
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回单个构造方法对象
package com.myreflect.myreflect3;
public class Student {
private String name;
private int age;
//私有的有参构造方法
private Student(String name) {
System.out.println("name的值为:" + name);
System.out.println("private...Student...有参构造方法");
}
//公共的无参构造方法
public Student() {
System.out.println("public...Student...无参构造方法");
}
//公共的有参构造方法
public Student(String name, int age) {
System.out.println("name的值为:" + name + "age的值为:" + age);
System.out.println("public...Student...有参构造方法");
}
}
一、 method2()
private static void method1() throws ClassNotFoundException {
// Constructor<?>[] getConstructors():
// 返回所有公共构造方法对象的数组
//1.获取Class对象
Class clazz = Class.forName("com.myreflect.myreflect3.Student");
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
}
public com.myreflect.myreflect3.Student()//公共的无惨构造
public com.myreflect.myreflect3.Student(java.lang.String,int)//公共的有参构造
Process finished with exit code 0
二、 method2()
private static void method2() throws ClassNotFoundException {
// Constructor<?>[] getDeclaredConstructors():
// 返回所有构造方法对象的数组
//1.获取Class对象
Class clazz = Class.forName("com.myreflect.myreflect3.Student");
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
private com.myreflect.myreflect3.Student(java.lang.String) //私有的有参构造方法
public com.myreflect.myreflect3.Student() //公共的无参构造方法
public com.myreflect.myreflect3.Student(java.lang.String,int) //公共的有参构造方法
Process finished with exit code 0
三、method3()
private static void method3() throws ClassNotFoundException, NoSuchMethodException {
// Constructor<T> getConstructor(Class<?>... parameterTypes):
// 返回单个公共构造方法对象
//1.获取Class对象
Class clazz = Class.forName("com.myreflect.myreflect3.Student");
//小括号中,一定要跟构造方法的形参保持一致.
Constructor constructor1 = clazz.getConstructor();
System.out.println(constructor1);
Constructor constructor2 = clazz.getConstructor(String.class, int.class);
System.out.println(constructor2);
//因为Student类中,没有只有一个int的构造,所以这里会报错.
Constructor constructor3 = clazz.getConstructor(int.class);
System.out.println(constructor3);
}
public com.myreflect.myreflect3.Student()//私有的有参构造方法
public com.myreflect.myreflect3.Student(java.lang.String,int) //公共的有参构造方法
Process finished with exit code 0
Exception in thread "main" java.lang.NoSuchMethodException: com.myreflect.myreflect3.Student.<init>(int)
at java.base/java.lang.Class.getConstructor0(Class.java:3354)
at java.base/java.lang.Class.getConstructor(Class.java:2156)
at com.myreflect.myreflect3.ReflectDemo1.method3(ReflectDemo1.java:41)
at com.myreflect.myreflect3.ReflectDemo1.main(ReflectDemo1.java:13)
Process finished with exit code 1
四、 method4()
private static void method4() throws ClassNotFoundException, NoSuchMethodException {
// Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):
// 返回单个构造方法对象
//1.获取Class对象
Class clazz = Class.forName("com.myreflect.myreflect3.Student");
Constructor constructor = clazz.getDeclaredConstructor(String.class);
System.out.println(constructor);
}
private com.myreflect.myreflect3.Student(java.lang.String)私有的有参构造方法
Process finished with exit code 0
Constructor类中用于创建对象的方法
T newInstance(Object... initargs):根据指定的构造方法创建对象
package com.myreflect.myreflect3;
public class Student {
private String name;
private int age;
//私有的有参构造方法
private Student(String name) {
System.out.println("name的值为:" + name);
System.out.println("private...Student...有参构造方法");
}
//公共的无参构造方法
public Student() {
System.out.println("public...Student...无参构造方法");
}
//公共的有参构造方法
public Student(String name, int age) {
System.out.println("name的值为:" + name + "age的值为:" + age);
System.out.println("public...Student...有参构造方法");
}
}
method1()
private static void method1() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
//1.获取class对象
Class clazz = Class.forName("com.myreflect.myreflect3.Student");
//2.获取构造方法对象
Constructor constructor = clazz.getConstructor(String.class, int.class);
//3.利用newInstance创建Student的对象
Student student = (Student) constructor.newInstance("zhangsan", 23);
System.out.println(student);
}
name的值为:zhangsanage的值为:23
public...Student...有参构造方法
com.myreflect.myreflect3.Student@7cd84586
Process finished with exit code 0
method2()
private static void method2() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
//1.获取class对象
Class clazz = Class.forName("com.myreflect.myreflect3.Student");
//2.获取构造方法对象
Constructor constructor = clazz.getConstructor();
//3.利用空参来创建Student的对象
Student student = (Student) constructor.newInstance();
System.out.println(student);
}
public...Student...无参构造方法
com.myreflect.myreflect3.Student@b4c966a
Process finished with exit code 0
method3()
private static void method3() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
//简写格式
//1.获取class对象
Class clazz = Class.forName("com.myreflect.myreflect3.Student");
//2.在Class类中,有一个newInstance方法,可以利用空参直接创建一个对象
Student student = (Student) clazz.newInstance();//这个方法现在已经过时了,了解一下
System.out.println(student);
}
public...Student...无参构造方法
com.myreflect.myreflect3.Student@b4c966a
Process finished with exit code 0
method4()
private static void method4() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
//获取一个私有的构造方法并创建对象
//1.获取class对象
Class clazz = Class.forName("com.myreflect.myreflect3.Student");
//2.获取一个私有化的构造方法.
Constructor constructor = clazz.getDeclaredConstructor(String.class);
//被private修饰的成员,不能直接使用的
//如果用反射强行获取并使用,需要临时取消访问检查
constructor.setAccessible(true);
//3.直接创建对象
Student student = (Student) constructor.newInstance("zhangsan");
System.out.println(student);
}
name的值为:zhangsan
private...Student...有参构造方法
com.myreflect.myreflect3.Student@506e1b77
Process finished with exit code 0
setAccessible(boolean flag):设置为true,表示取消访问检查
小结
获取class对象
三种方式 ---- Class.forName(“全类名”)
获取里面的构造方法对象
getConstructor (Class<?>... parameterTypes)
getDeclaredConstructor (Class<?>... parameterTypes)
如果是public的,直接创建对象
newInstance(Object... initargs)
如果是非public的,需要临时取消检查,然后再创建对象
setAccessible(boolean) 暴力反射
反射获取成员变量
反射获取[构造方法]并使用
反射获取[成员变量]并使用
第二步:获得Field对象
- Field[] getFields():返回所有[公共成员变量]对象的数组
- Field[] getDeclaredFields():返回所有[成员变量]对象的数组
- Field getField(String name):返回[单个公共成员]变量对象
- Field getDeclaredField(String name):返回单个成员变量对象
创建:Student
package com.myreflect.myreflect4;
public class Student {
public String name;
public int age;
public String gender;
private int money = 300;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", money=" + money +
'}';
}
}
Field[] getFields():返回所有[公共成员变量]对象的数组
private static void method1() throws ClassNotFoundException {
// Field[] getFields():返回所有公共成员变量对象的数组
//1.获取class对象
Class clazz = Class.forName("com.myreflect.myreflect4.Student");
//2.获取Field对象.
Field[] fields = clazz.getFields();
//3.遍历
for (Field field : fields) {
System.out.println(field);
}
}
}
public java.lang.String com.myreflect.myreflect4.Student.name
public int com.myreflect.myreflect4.Student.age
public java.lang.String com.myreflect.myreflect4.Student.gender
Process finished with exit code 0
method2() Field[] getDeclaredFields():返回所有[成员变量]对象的数组
private static void method2() throws ClassNotFoundException {
// Field[] getDeclaredFields():返回所有成员变量对象的数组
//1.获取class对象
Class clazz = Class.forName("com.myreflect.myreflect4.Student");
//2.获取所有的Field对象
Field[] fields = clazz.getDeclaredFields();
//3.遍历
for (Field field : fields) {
System.out.println(field);
}
}
public java.lang.String com.myreflect.myreflect4.Student.name
public int com.myreflect.myreflect4.Student.age
public java.lang.String com.myreflect.myreflect4.Student.gender
private int com.myreflect.myreflect4.Student.money
Process finished with exit code 0
method3() Field getField(String name):返回[单个公共成员]变量对象
private static void method3() throws ClassNotFoundException, NoSuchFieldException {
// Field getField(String name):返回单个公共成员变量对象
//想要获取的成员变量必须是真实存在的
//且必须是public修饰的.
//1.获取class对象
Class clazz = Class.forName("com.myreflect.myreflect4.Student");
//2.获取name这个成员变量
Field field = clazz.getField("name");
//3.打印一下
System.out.println(field);
}
public java.lang.String com.myreflect.myreflect4.Student.name
Process finished with exit code 0
注意点:
method4() Field getDeclaredField(String name):返回单个成员变量对象
private static void method4() throws ClassNotFoundException, NoSuchFieldException {
// Field getDeclaredField(String name):返回单个成员变量对象
//1.获取class对象
Class clazz = Class.forName("com.myreflect.myreflect4.Student");
//2.获取money成员变量
Field field = clazz.getDeclaredField("money");
//3.打印一下
System.out.println(field);
}
private int com.myreflect.myreflect4.Student.money
Process finished with exit code 0
第三步:赋值或者获取值
method1() void set(Object obj, Object value):赋值
private static void method1() throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException { // void set(Object obj, Object value):给obj对象的成员变量赋值为value //1.获取class对象 Class clazz = Class.forName("com.myreflect.myreflect4.Student"); //2.获取name这个Field对象 Field field = clazz.getField("name"); //3.利用set方法进行赋值. //3.1先创建一个Student对象 Student student = (Student) clazz.newInstance(); //3.2有了对象才可以给指定对象进行赋值 field.set(student,"zhangsan"); System.out.println(student); } } Student{name='zhangsan', age=0, gender='null', money=300} Process finished with exit code 0
method2() Object get(Object obj) 获取值。
private static void method2() throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
//1.获取class对象
Class clazz = Class.forName("com.myreflect.myreflect4.Student");
//2.获取成员变量Field的对象
Field field = clazz.getDeclaredField("money");
//3.取消一下访问检查
field.setAccessible(true);
//4.调用get方法来获取值
//4.1创建一个对象
Student student = (Student) clazz.newInstance();
//4.2获取指定对象的money的值
Object o = field.get(student);
//5.打印一下
System.out.println(o);
}
300
Process finished with exit code 0
不强转成子类
void set(Object obj, Object value):给指定对象的成员变量赋值
Object get(Object obj) 返回指定对象的Field的值
//1.获取class对象
Class clazz = Class.forName(“com.itheima.myreflect4.Student”);
//2.获取name这个成员变量
Field field = clazz.getField(“name”);
//3.调用set方法进行赋值
//此时有两个学生对象s1和s2
反射获取成员方法
反射获取[成员方法]并运行
第二步:获得Method对象
- Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
- Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
- Method getMethod(String name, Class<?>... parameterTypes) :
- 返回单个公共成员方法对象
- Method getDeclaredMethod(String name, Class<?>... parameterTypes):
- 返回单个成员方法对象
package com.myreflect.myreflect5;
public class Student {
//私有的,无参无返回值
private void show() {
System.out.println("私有的show方法,无参无返回值");
}
//公共的,无参无返回值
public void function1() {
System.out.println("function1方法,无参无返回值");
}
//公共的,有参无返回值
public void function2(String name) {
System.out.println("function2方法,有参无返回值,参数为" + name);
}
//公共的,无参有返回值
public String function3() {
System.out.println("function3方法,无参有返回值");
return "aaa";
}
//公共的,有参有返回值
public String function4(String name) {
System.out.println("function4方法,有参有返回值,参数为" + name);
return "aaa";
}
}
method1()Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
method2() Method[] getDeclaredMethods():
返回所有成员方法对象的数组,不包括继承的
method3() Method getMethod(String name, Class<?>... parameterTypes) :
返回单个公共成员方法对象
method5() Method getDeclaredMethod(String name, Class<?>... parameterTypes): 返回单个成员方法对象
常用的是method3() 精确反射
method5()
第三步:运行方法
Object invoke(Object obj, Object... args):运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)
package com.myreflect.myreflect5;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 获取Method对象并运行
*/
public class ReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
// Object invoke(Object obj, Object... args):运行方法
// 参数一:用obj对象调用该方法
// 参数二:调用方法的传递的参数(如果没有就不写)
// 返回值:方法的返回值(如果没有就不写)
//1.获取class对象
Class clazz = Class.forName("com.myreflect.myreflect5.Student");
//2.获取里面的Method对象 function4
Method method = clazz.getMethod("function4", String.class);
//3.运行function4方法就可以了
//3.1创建一个Student对象,当做方法的调用者
Student student = (Student) clazz.newInstance();
//3.2运行方法
Object result = method.invoke(student, "zhangsan");
//4.打印一下返回值
System.out.println(result);
}
}
三、xml
XML概述
万维网联盟(W3C)
万维网联盟(W3C)创建于1994年,又称W3C理事会。1994年10月在麻省理工学院计算机科学实验室成立。
建立者: Tim Berners-Lee (蒂姆·伯纳斯·李)。
是Web技术领域最具权威和影响力的国际中立性技术标准机构。
到目前为止,W3C已发布了200多项影响深远的Web技术标准及实施指南,
- 如广为业界采用的超文本标记语言HTML(标准通用标记语言下的一个应用)、
- 可扩展标记语言XML(标准通用标记语言下的一个子集)
- 以及帮助残障人士有效获得Web信息的无障碍指南(WCAG)等,
XML的全称为(EXtensible Markup Language),是一种可扩展的标记语言
标记语言:通过标签来描述数据的一门语言(标签有时我们也将其称之为元素)
可扩展:标签的名字是可以自定义的
可以理解为:XML文件是由很多标签组成的,而标签名是可以自定义的。
作用:
- 用于进行存储数据和传输数据
- 作为软件的配置文件
XML标签
- 标签由一对尖括号和合法标识符组成 <student>
- 标签必须成对出现 <student> <student>
开始标签 结束标签
-
- 标签必须成对出现 <student> <student>
- 特殊的标签可以不成对,但是必须有结束标记 <address/>
- 标签中可以定义属性,属性和标签名空格隔 <student id="1"> </student>
属性值必须用引号引起来
- 标签需要正确的嵌套 <student id="1">
- <name>张三</name>
- </student>
- </student>
- <name>张三</name>
语法规则
XML语法规则
- XML文件的后缀名为:xml
- 文档声明必须是第一行第一列
<?xml version=“1.0” encoding=“UTF-8” standalone=“yes”?>
version:该属性是必须存在的
encoding:该属性不是必须的
打开当前xml文件的时候应该是使用什么字符编码表
(一般取值都是UTF-8)
standalone: 该属性不是必须的,描述XML文件是否依赖其他的xml文件,取值为yes/no
- 必须存在一个根标签,有且只能有一个
解析XML
解析XML
就是从xml中获取到数据
DOM(Document Object Model)文档对象模型:
就是把文档的各个组成部分看做成对应的对象。
会把xml文件全部加载到内存。
在内存中形成一个树形结构,再获取对应的值
DOM解析思想
Document对象:整个xml文档
Document对象:整个xml文档
Element对象:所有标签
Document对象:整个xml文档
Element对象:所有标签
Attribute对象:所有属性
Document对象:整个xml文档
Element对象:所有标签
Attribute对象:所有属性 Node对象
Text对象:所有文本内容
常见的解析工具
JAXP : SUN公司提供的一套XML的解析的API
JDOM : 开源组织提供了一套XML的解析的API-jdom
DOM4J: 开源组织提供了一套XML的解析的API-dom4j
我们可以通过网站:https://dom4j.github.io/ 去下载dom4j
全称:Dom For Java
DomFJ
pull : 主要应用在Android手机端解析XML
DOM4J练习
需求:
- 解析这个xml文件,
- 将解析到的数据封装到学生对象中.
- 并将学生对象存储到ArrayList集合中
- 遍历集合
文档约束
什么是约束?
用来限定xml文件中可使用的标签以及属性。
告诉程序员,xml该怎么写。
约束的分类
- DTD
- schema
四、DTD约束
写出一个dtd约束文件
步骤:
1,创建一个文件,这个文件的后缀名为.dtd。
2,看xml文件中使用了哪些元素
<!ELEMENT> 可以定义元素
3,判断元素是简单元素还是复杂元素。
简单元素:没有子元素。
复杂元素:有子元素的元素;
- 能在xml中引入约束文档
- 能够简单阅读约束文档
- 根据约束编写xml文件
引入DTD约束的三种方法
- 引入本地dtd
<!DOCTYPE 根元素名称 SYSTEM ‘DTD文件的路径'>
- 在xml文件内部引入
<!DOCTYPE 根元素名称 [ dtd文件内容 ]>
- 引入网络dtd
<!DOCTYPE 根元素名称 [ dtd文件内容 ]>
- 能够简单阅读约束文档
- 根据约束编写xml文件
DTD语法规则
定义一个元素的格式为:<!ELEMENT 元素名 元素类型>
定义一个属性的格式为:<!ATTLIST 元素名称 属性名称 属性的类型 属性的约束>
属性的类型:
CDATA类型:普通的字符串
属性的约束:
#REQUIRED: 必须的
#IMPLIED: 属性不是必需的
#FIXED value:属性值是固定的
五、schema约束
schema和dtd的区别
- schema约束文件也是一个xml文件,符合xml的语法,这个文件的后缀名.xsd
- 一个xml中可以引用多个schema约束文件,多个schema使用名称空间区分(名称空间类似于java包名)
- dtd里面元素类型的取值比较单一常见的是PCDATA类型,但是在schema里面可以支持很多个数据类型
- schema 语法更加的复杂
Schema文件用来约束一个xml文件
同时也被别的文件约束着
schema入门案例
写出一个schema约束文件
步骤:
1,创建一个文件,这个文件的后缀名为.xsd。
2,定义文档声明
3,schema文件的根标签为: <schema>
4,在<schema>中定义属性: xmlns=http://www.w3.org/2001/XMLSchema
5,在<schema>中定义属性 : targetNamespace =唯一的url地址。 指定当前这个schema文件的名称空间。
6,在<schema>中定义属性 : elementFormDefault="qualified“ 表示当前schema文件是一个质量良好的文件。
7,通过element定义元素
8,判断当前元素是简单元素还是复杂元素
引入schema约束文件步骤:
步骤:
1,在根标签上定义属性
xmlns="http://www.w3.org/2001/XMLSchema-instance"
2,通过xmlns引入约束文件的名称空间
3,给某一个xmlns属性添加一个标识,用于区分不同的名称空间
格式为: xmlns:标识=“名称空间地址” 。
标识可以是任意的,但是一般取值都是xsi
4,通过xsi:schemaLocation指定名称空间所对应的约束文件路径
格式为:xsi:schemaLocation = "名称空间url 文件路径“
Schema定义属性
六 注解:
注解的优势
注解的优势
什么是注解
什么是注解
注解的主要作用:对我们的程序进行标注和解释。
自定义注解
自定义注解 --- 格式
Jdk提供的元注解
元注解
元注解:就是描述注解的注解。
利用注解优化配置文件
配置文件方式
当业务逻辑逐渐增多时,xml文件内容会逐渐变多,不利于后期维护。
利用注解简化配置文件
- 定义一个注解(@WebServlet),注解内有一个属性urlPatterns
- 在servlet类上去使用该注解
- 创建一个注解解析类
永远别往了最终的目的:把uri和servlet对象放到一个Map集合当中 当浏览器访问时,我们获取uri对应的servlet来处理当前业务
七、单元测试
Junit测试框架
unit是第三方公司开源出来的,用于对代码进行单元测试的工具(IDEA已经集成了junit框架)。相比于在main方法中测试有如下几个优点。
Junit是:一款可以帮助我们进行代码运行和程序结果预测的框架
使用步骤:
1.导入jar包;(可以手动导入,也可以让idea自动联网下载导入)
2.在类中的public,无返回值的,无参数的方法上面添加@Test注解即可;
3.手动执行带@Test注解的方法;
注意事项 :
1.方法必须是public权限
2.方法必须是void
3.方法必须是无参数
断言机制:
在调用方法的时候,我们可以预计方法返回的结果
使用断言机制就可以拿我们预计的结果和代码实际运行的结果进行比较
如果一致,则断言成功,如果不一致,则说明代码存在逻辑问题!
语法:
Assert.assertEquals("自定义信息提示",预计的结果,实际的结果);
其他注解:
如果我们希望在正常的测试方法之前和之后,做一些通用操作,可以利用@Before和@After实现,同时,如果是静态方法可以使用@BeforeClass和@AfterClass实现;
类注解解析
类注解解析主要分为以下三步:
第一步:使用类加载器加载类;
第二步:找到类上面的注解;
第三步:获取注解实例。
单元测试断言:
所谓断言:意思是程序员可以预测程序的运行结果,检查程序的运行结果是否与预期一致。
StringUtil类中新增一个测试方法
断言机制:Assert.assertEquals
断言:主要解决逻辑上的的问题的
由于Junit是第三方提供的,所以我们需要把jar包导入到我们的项目中,才能使用,具体步骤如下图所示: