济源做网站的公司,wordpress引入php,上海建站网站,网站开发技术都有哪些目录
一、反射
1.1 反射的概述#xff1a;
1.2 学习反射到底学什么#xff1f;
1.3 获取字节码文件对象的三种方式
1.4 字节码文件和字节码文件对象
1.5 获取构造方法
1.6 获取构造方法并创建对象
1.7 获取成员变量
1.8 获取成员变量并获取值和修改值
1.9 获取成员…目录
一、反射
1.1 反射的概述
1.2 学习反射到底学什么
1.3 获取字节码文件对象的三种方式
1.4 字节码文件和字节码文件对象
1.5 获取构造方法
1.6 获取构造方法并创建对象
1.7 获取成员变量
1.8 获取成员变量并获取值和修改值
1.9 获取成员方法
1.10 获取成员方法并运行
1.11 练习泛型擦除掌握概念了解代码
1.12 练习修改字符串的内容掌握概念了解代码
1.13 练习反射和配置文件结合动态获取的练习重点
1.14 利用发射保存对象中的信息重点
二、动态代理
2.1 好处
2.2 动态代理三要素
2.3 代码实现
2.4 额外扩展
2.5 动态代理的练习
三、日志
3.1 作用
3.2 使用步骤
3.3 日志级别
3.4 配置文件
四、类加载器
4.1类加载器
4.2类加载的完整过程
4.3类加载的分类【理解】
4.4双亲委派模型【理解】
4.5ClassLoader 中的两个方法【应用】
五、xml
5.1概述【理解】
5.2标签的规则【应用】
5.3语法规则【应用】
5.4xml解析【应用】
5.5DTD约束【理解】
5.6schema约束【理解】
六、单元测试Junit
6.1 什么是单元测试掌握
6.2 Junit的特点掌握
6.3 基本用法掌握
6.3.1手动导包掌握
6.3.2运行测试代码掌握
6.3.3Junit正确的打开方式正确的使用方式掌握
6.3.4正确的使用方式掌握
6.3.5实际开发中单元测试的使用方式掌握
6.3.6扩展点
七、注解
7.1 注释和注解的区别掌握
7.2 如何使用注解掌握
7.3 Java中已经存在的注解掌握
7.4 自定义注解了解
7.5 特殊属性掌握
7.6 元注解了解
7.6.1Target:
7.6.2Retention
7.7 模拟JUnit自带的Test注解了解
7.8 注解小结 一、反射
1.1 反射的概述
专业的解释了解一下
是在运行状态中对于任意一个类都能够知道这个类的所有属性和方法
对于任意一个对象都能够调用它的任意属性和方法
这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
通俗的理解掌握 利用反射创建的对象可以无视修饰符调用类里面的内容 可以跟配置文件结合起来使用把要创建的对象信息和方法写在配置文件中。 读取到什么类就创建什么类的对象 读取到什么方法就调用什么方法 此时当需求变更的时候不需要修改代码只要修改配置文件即可。
1.2 学习反射到底学什么
反射都是从class字节码文件中获取的内容。 如何获取class字节码文件的对象 利用反射如何获取构造方法创建对象 利用反射如何获取成员变量赋值获取值 利用反射如何获取成员方法运行
1.3 获取字节码文件对象的三种方式 Class这个类里面的静态方法forName“全类名”最常用 通过class属性获取 通过对象获取字节码文件对象
代码示例
//1.Class这个类里面的静态方法forName
//Class.forName(类的全类名) 全类名 包名 类名
Class clazz1 Class.forName(com.itheima.reflectdemo.Student);
//源代码阶段获取 --- 先把Student加载到内存中再获取字节码文件的对象
//clazz 就表示Student这个类的字节码文件对象。
//就是当Student.class这个文件加载到内存之后产生的字节码文件对象//2.通过class属性获取
//类名.class
Class clazz2 Student.class;//因为class文件在硬盘中是唯一的所以当这个文件加载到内存之后产生的对象也是唯一的
System.out.println(clazz1 clazz2);//true//3.通过Student对象获取字节码文件对象
Student s new Student();
Class clazz3 s.getClass();
System.out.println(clazz1 clazz2);//true
System.out.println(clazz2 clazz3);//true 1.4 字节码文件和字节码文件对象
java文件就是我们自己编写的java代码。
字节码文件就是通过java文件编译之后的class文件是在硬盘上真实存在的用眼睛能看到的
字节码文件对象当class文件加载到内存之后虚拟机自动创建出来的对象。
这个对象里面至少包含了构造方法成员变量成员方法。
而我们的反射获取的是什么字节码文件对象这个对象在内存中是唯一的。
1.5 获取构造方法
规则
get表示获取
Declared表示私有
最后的s表示所有复数形式
如果当前获取到的是私有的必须要临时修改访问权限否则无法使用
方法名说明Constructor?[] getConstructors()获得所有的构造只能public修饰Constructor?[] getDeclaredConstructors()获得所有的构造包含private修饰ConstructorT getConstructor(Class?... parameterTypes)获取指定构造只能public修饰ConstructorT getDeclaredConstructor(Class?... parameterTypes)获取指定构造包含private修饰
代码示例
public class ReflectDemo2 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {//1.获得整体class字节码文件对象Class clazz Class.forName(com.itheima.reflectdemo.Student);//2.获取构造方法对象//获取所有构造方法publicConstructor[] constructors1 clazz.getConstructors();for (Constructor constructor : constructors1) {System.out.println(constructor);}System.out.println();//获取所有构造带私有的Constructor[] constructors2 clazz.getDeclaredConstructors();for (Constructor constructor : constructors2) {System.out.println(constructor);}System.out.println();//获取指定的空参构造Constructor con1 clazz.getConstructor();System.out.println(con1);Constructor con2 clazz.getConstructor(String.class,int.class);System.out.println(con2);System.out.println();//获取指定的构造(所有构造都可以获取到包括public包括private)Constructor con3 clazz.getDeclaredConstructor();System.out.println(con3);//了解 System.out.println(con3 con1);//每一次获取构造方法对象的时候都会新new一个。Constructor con4 clazz.getDeclaredConstructor(String.class);System.out.println(con4);}
}
1.6 获取构造方法并创建对象
涉及到的方法newInstance
代码示例
//首先要有一个javabean类
public class Student {private String name;private int age;public Student() {}public Student(String name) {this.name name;}private Student(String name, int age) {this.name name;this.age age;}/*** 获取* return name*/public String getName() {return name;}/*** 设置* param name*/public void setName(String name) {this.name name;}/*** 获取* return age*/public int getAge() {return age;}/*** 设置* param age*/public void setAge(int age) {this.age age;}public String toString() {return Student{name name , age age };}
}//测试类中的代码
//需求1
//获取空参并创建对象//1.获取整体的字节码文件对象
Class clazz Class.forName(com.itheima.a02reflectdemo1.Student);
//2.获取空参的构造方法
Constructor con clazz.getConstructor();
//3.利用空参构造方法创建对象
Student stu (Student) con.newInstance();
System.out.println(stu);System.out.println();//测试类中的代码
//需求2
//获取带参构造并创建对象
//1.获取整体的字节码文件对象
Class clazz Class.forName(com.itheima.a02reflectdemo1.Student);
//2.获取有参构造方法
Constructor con clazz.getDeclaredConstructor(String.class, int.class);
//3.临时修改构造方法的访问权限暴力反射
con.setAccessible(true);
//4.直接创建对象
Student stu (Student) con.newInstance(zhangsan, 23);
System.out.println(stu);
1.7 获取成员变量
规则
get表示获取
Declared表示私有
最后的s表示所有复数形式
如果当前获取到的是私有的必须要临时修改访问权限否则无法使用
方法名
方法名说明Field[] getFields()返回所有成员变量对象的数组只能拿public的Field[] getDeclaredFields()返回所有成员变量对象的数组存在就能拿到Field getField(String name)返回单个成员变量对象只能拿public的Field getDeclaredField(String name)返回单个成员变量对象存在就能拿到
代码示例
public class ReflectDemo4 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {//获取成员变量对象//1.获取class对象Class clazz Class.forName(com.itheima.reflectdemo.Student);//2.获取成员变量的对象Field对象)只能获取public修饰的Field[] fields1 clazz.getFields();for (Field field : fields1) {System.out.println(field);}System.out.println();//获取成员变量的对象public privateField[] fields2 clazz.getDeclaredFields();for (Field field : fields2) {System.out.println(field);}System.out.println();//获得单个成员变量对象//如果获取的属性是不存在的那么会报异常//Field field3 clazz.getField(aaa);//System.out.println(field3);//NoSuchFieldExceptionField field4 clazz.getField(gender);System.out.println(field4);System.out.println();//获取单个成员变量私有Field field5 clazz.getDeclaredField(name);System.out.println(field5);}
}public class Student {private String name;private int age;public String gender;public String address;public Student() {}public Student(String name, int age, String address) {this.name name;this.age age;this.address address;}public Student(String name, int age, String gender, String address) {this.name name;this.age age;this.gender gender;this.address address;}/*** 获取* return name*/public String getName() {return name;}/*** 设置* param name*/public void setName(String name) {this.name name;}/*** 获取* return age*/public int getAge() {return age;}/*** 设置* param age*/public void setAge(int age) {this.age age;}/*** 获取* return gender*/public String getGender() {return gender;}/*** 设置* param gender*/public void setGender(String gender) {this.gender gender;}/*** 获取* return address*/public String getAddress() {return address;}/*** 设置* param address*/public void setAddress(String address) {this.address address;}public String toString() {return Student{name name , age age , gender gender , address address };}
}1.8 获取成员变量并获取值和修改值
方法说明void set(Object obj, Object value赋值Object get(Object obj)获取值
代码示例
public class ReflectDemo5 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {Student s new Student(zhangsan,23,广州);Student ss new Student(lisi,24,北京);//需求//利用反射获取成员变量并获取值和修改值//1.获取class对象Class clazz Class.forName(com.itheima.reflectdemo.Student);//2.获取name成员变量//field就表示name这个属性的对象Field field clazz.getDeclaredField(name);//临时修饰他的访问权限field.setAccessible(true);//3.设置(修改)name的值//参数一表示要修改哪个对象的name//参数二表示要修改为多少field.set(s,wangwu);//3.获取name的值//表示我要获取这个对象的name的值String result (String)field.get(s);//4.打印结果System.out.println(result);System.out.println(s);System.out.println(ss);}
}public class Student {private String name;private int age;public String gender;public String address;public Student() {}public Student(String name, int age, String address) {this.name name;this.age age;this.address address;}public Student(String name, int age, String gender, String address) {this.name name;this.age age;this.gender gender;this.address address;}/*** 获取* return name*/public String getName() {return name;}/*** 设置* param name*/public void setName(String name) {this.name name;}/*** 获取* return age*/public int getAge() {return age;}/*** 设置* param age*/public void setAge(int age) {this.age age;}/*** 获取* return gender*/public String getGender() {return gender;}/*** 设置* param gender*/public void setGender(String gender) {this.gender gender;}/*** 获取* return address*/public String getAddress() {return address;}/*** 设置* param address*/public void setAddress(String address) {this.address address;}public String toString() {return Student{name name , age age , gender gender , address address };}
}
1.9 获取成员方法
规则
get表示获取
Declared表示私有
最后的s表示所有复数形式
如果当前获取到的是私有的必须要临时修改访问权限否则无法使用
方法名说明Method[] getMethods()返回所有成员方法对象的数组只能拿public的Method[] getDeclaredMethods()返回所有成员方法对象的数组存在就能拿到Method getMethod(String name, Class?... parameterTypes)返回单个成员方法对象只能拿public的Method getDeclaredMethod(String name, Class?... parameterTypes)返回单个成员方法对象存在就能拿到
代码示例
public class ReflectDemo6 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {//1.获取class对象Class? clazz Class.forName(com.itheima.reflectdemo.Student);//2.获取方法//getMethods可以获取父类中public修饰的方法Method[] methods1 clazz.getMethods();for (Method method : methods1) {System.out.println(method);}System.out.println();//获取所有的方法包含私有//但是只能获取自己类中的方法Method[] methods2 clazz.getDeclaredMethods();for (Method method : methods2) {System.out.println(method);}System.out.println();//获取指定的方法空参Method method3 clazz.getMethod(sleep);System.out.println(method3);Method method4 clazz.getMethod(eat,String.class);System.out.println(method4);//获取指定的私有方法Method method5 clazz.getDeclaredMethod(playGame);System.out.println(method5);}
}1.10 获取成员方法并运行
方法
Object invoke(Object obj, Object... args) 运行方法
参数一用obj对象调用该方法
参数二调用方法的传递的参数如果没有就不写
返回值方法的返回值如果没有就不写
代码示例
package com.itheima.a02reflectdemo1;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class ReflectDemo6 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {//1.获取字节码文件对象Class clazz Class.forName(com.itheima.a02reflectdemo1.Student);//2.获取一个对象//需要用这个对象去调用方法Student s new Student();//3.获取一个指定的方法//参数一方法名//参数二参数列表如果没有可以不写Method eatMethod clazz.getMethod(eat,String.class);//运行//参数一表示方法的调用对象//参数二方法在运行时需要的实际参数//注意点如果方法有返回值那么需要接收invoke的结果//如果方法没有返回值则不需要接收String result (String) eatMethod.invoke(s, 重庆小面);System.out.println(result);}
}public class Student {private String name;private int age;public String gender;public String address;public Student() {}public Student(String name) {this.name name;}private Student(String name, int age) {this.name name;this.age age;}/*** 获取* return name*/public String getName() {return name;}/*** 设置* param name*/public void setName(String name) {this.name name;}/*** 获取* return age*/public int getAge() {return age;}/*** 设置* param age*/public void setAge(int age) {this.age age;}public String toString() {return Student{name name , age age };}private void study(){System.out.println(学生在学习);}private void sleep(){System.out.println(学生在睡觉);}public String eat(String something){System.out.println(学生在吃 something);return 学生已经吃完了非常happy;}
}
面试题
你觉得反射好不好好有两个方向
第一个方向无视修饰符访问类中的内容。但是这种操作在开发中一般不用都是框架底层来用的。
第二个方向反射可以跟配置文件结合起来使用动态的创建对象动态的调用方法。
1.11 练习泛型擦除掌握概念了解代码
理解掌握
集合中的泛型只在java文件中存在当编译成class文件之后就没有泛型了。
代码示例了解
package com.itheima.reflectdemo;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;public class ReflectDemo8 {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {//1.创建集合对象ArrayListInteger list new ArrayList();list.add(123);
// list.add(aaa);//2.利用反射运行add方法去添加字符串//因为反射使用的是class字节码文件//获取class对象Class clazz list.getClass();//获取add方法对象Method method clazz.getMethod(add, Object.class);//运行方法method.invoke(list,aaa);//打印集合System.out.println(list);}
}
1.12 练习修改字符串的内容掌握概念了解代码
在这个练习中我需要你掌握的是字符串不能修改的真正原因。
字符串在底层是一个byte类型的字节数组名字叫做value
private final byte[] value;
真正不能被修改的原因final和private
final修饰value表示value记录的地址值不能修改。
private修饰value而且没有对外提供getvalue和setvalue的方法。所以在外界不能获取或修改value记录的地址值。
如果要强行修改可以用反射
代码示例了解
String s abc;
String ss abc;
// private final byte[] value {97,98,99};
// 没有对外提供getvalue和setvalue的方法不能修改value记录的地址值
// 如果我们利用反射获取了value的地址值。
// 也是可以修改的final修饰的value
// 真正不可变的value数组的地址值里面的内容利用反射还是可以修改的比较危险//1.获取class对象
Class clazz s.getClass();//2.获取value成员变量private
Field field clazz.getDeclaredField(value);
//但是这种操作非常危险
//JDK高版本已经屏蔽了这种操作低版本还是可以的
//临时修改权限
field.setAccessible(true);//3.获取value记录的地址值
byte[] bytes (byte[]) field.get(s);
bytes[0] 100;System.out.println(s);//dbc
System.out.println(ss);//dbc
1.13 练习反射和配置文件结合动态获取的练习重点
需求: 利用反射根据文件中的不同类名和方法名创建不同的对象并调用方法。
分析:
①通过Properties加载配置文件
②得到类名和方法名
③通过类名反射得到Class对象
④通过Class对象创建一个对象
⑤通过Class对象得到方法
⑥调用方法
代码示例
public class ReflectDemo9 {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//1.读取配置文件的信息Properties prop new Properties();FileInputStream fis new FileInputStream(day14-code\\prop.properties);prop.load(fis);fis.close();System.out.println(prop);String classname prop.get(classname) ;String methodname prop.get(methodname) ;//2.获取字节码文件对象Class clazz Class.forName(classname);//3.要先创建这个类的对象Constructor con clazz.getDeclaredConstructor();con.setAccessible(true);Object o con.newInstance();System.out.println(o);//4.获取方法的对象Method method clazz.getDeclaredMethod(methodname);method.setAccessible(true);//5.运行方法method.invoke(o);}
}配置文件中的信息
classnamecom.itheima.a02reflectdemo1.Student
methodnamesleep
1.14 利用发射保存对象中的信息重点
public class MyReflectDemo {public static void main(String[] args) throws IllegalAccessException, IOException {/*对于任意一个对象都可以把对象所有的字段名和值保存到文件中去*/Student s new Student(小A,23,女,167.5,睡觉);Teacher t new Teacher(播妞,10000);saveObject(s);}//把对象里面所有的成员变量名和值保存到本地文件中public static void saveObject(Object obj) throws IllegalAccessException, IOException {//1.获取字节码文件的对象Class clazz obj.getClass();//2. 创建IO流BufferedWriter bw new BufferedWriter(new FileWriter(myreflect\\a.txt));//3. 获取所有的成员变量Field[] fields clazz.getDeclaredFields();for (Field field : fields) {field.setAccessible(true);//获取成员变量的名字String name field.getName();//获取成员变量的值Object value field.get(obj);//写出数据bw.write(name value);bw.newLine();}bw.close();}
}
public class Student {private String name;private int age;private char gender;private double height;private String hobby;public Student() {}public Student(String name, int age, char gender, double height, String hobby) {this.name name;this.age age;this.gender gender;this.height height;this.hobby hobby;}/*** 获取* return name*/public String getName() {return name;}/*** 设置* param name*/public void setName(String name) {this.name name;}/*** 获取* return age*/public int getAge() {return age;}/*** 设置* param age*/public void setAge(int age) {this.age age;}/*** 获取* return gender*/public char getGender() {return gender;}/*** 设置* param gender*/public void setGender(char gender) {this.gender gender;}/*** 获取* return height*/public double getHeight() {return height;}/*** 设置* param height*/public void setHeight(double height) {this.height height;}/*** 获取* return hobby*/public String getHobby() {return hobby;}/*** 设置* param hobby*/public void setHobby(String hobby) {this.hobby hobby;}public String toString() {return Student{name name , age age , gender gender , height height , hobby hobby };}
}
public class Teacher {private String name;private double salary;public Teacher() {}public Teacher(String name, double salary) {this.name name;this.salary salary;}/*** 获取* return name*/public String getName() {return name;}/*** 设置* param name*/public void setName(String name) {this.name name;}/*** 获取* return salary*/public double getSalary() {return salary;}/*** 设置* param salary*/public void setSalary(double salary) {this.salary salary;}public String toString() {return Teacher{name name , salary salary };}
}二、动态代理
2.1 好处
无侵入式的给方法增强功能
2.2 动态代理三要素
1真正干活的对象
2代理对象
3利用代理调用方法
切记一点代理可以增强或者拦截的方法都在接口中接口需要写在newProxyInstance的第二个参数里。
2.3 代码实现
public class Test {public static void main(String[] args) {/*需求外面的人想要大明星唱一首歌1. 获取代理的对象代理对象 ProxyUtil.createProxy(大明星的对象);2. 再调用代理的唱歌方法代理对象.唱歌的方法(只因你太美);*///1. 获取代理的对象BigStar bigStar new BigStar(鸡哥);Star proxy ProxyUtil.createProxy(bigStar);//2. 调用唱歌的方法String result proxy.sing(只因你太美);System.out.println(result);}
}
/*
*
* 类的作用
* 创建一个代理
*
* */
public class ProxyUtil {/*** 方法的作用* 给一个明星的对象创建一个代理** 形参* 被代理的明星对象** 返回值* 给明星创建的代理**** 需求* 外面的人想要大明星唱一首歌* 1. 获取代理的对象* 代理对象 ProxyUtil.createProxy(大明星的对象);* 2. 再调用代理的唱歌方法* 代理对象.唱歌的方法(只因你太美);* */public static Star createProxy(BigStar bigStar){/* java.lang.reflect.Proxy类提供了为对象产生代理对象的方法public static Object newProxyInstance(ClassLoader loader, Class?[] interfaces, InvocationHandler h)参数一用于指定用哪个类加载器去加载生成的代理类参数二指定接口这些接口用于指定生成的代理长什么也就是有哪些方法参数三用来指定生成的代理对象要干什么事情*/Star star (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),//参数一用于指定用哪个类加载器去加载生成的代理类new Class[]{Star.class},//参数二指定接口这些接口用于指定生成的代理长什么也就是有哪些方法//参数三用来指定生成的代理对象要干什么事情new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/** 参数一代理的对象* 参数二要运行的方法 sing* 参数三调用sing方法时传递的实参* */if(sing.equals(method.getName())){System.out.println(准备话筒收钱);}else if(dance.equals(method.getName())){System.out.println(准备场地收钱);}//去找大明星开始唱歌或者跳舞//代码的表现形式调用大明星里面唱歌或者跳舞的方法return method.invoke(bigStar,args);}});return star;}
}
public interface Star {//我们可以把所有想要被代理的方法定义在接口当中//唱歌public abstract String sing(String name);//跳舞public abstract void dance();
}
public class BigStar implements Star {private String name;public BigStar() {}public BigStar(String name) {this.name name;}//唱歌Overridepublic String sing(String name){System.out.println(this.name 正在唱 name);return 谢谢;}//跳舞Overridepublic void dance(){System.out.println(this.name 正在跳舞);}/*** 获取* return name*/public String getName() {return name;}/*** 设置* param name*/public void setName(String name) {this.name name;}public String toString() {return BigStar{name name };}
}2.4 额外扩展
动态代理还可以拦截方法
比如
在这个故事中经济人作为代理如果别人让邀请大明星去唱歌打篮球经纪人就增强功能。
但是如果别人让大明星去扫厕所经纪人就要拦截不会去调用大明星的方法。
/*
* 类的作用
* 创建一个代理
* */
public class ProxyUtil {public static Star createProxy(BigStar bigStar){public static Object newProxyInstance(ClassLoader loader, Class?[] interfaces, InvocationHandler h)Star star (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),new Class[]{Star.class},new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if(cleanWC.equals(method.getName())){System.out.println(拦截不调用大明星的方法);return null;}//如果是其他方法正常执行return method.invoke(bigStar,args);}});return star;}
}
2.5 动态代理的练习
对add方法进行增强对remove方法进行拦截对其他方法不拦截也不增强
public class MyProxyDemo1 {public static void main(String[] args) {//动态代码可以增强也可以拦截//1.创建真正干活的人ArrayListString list new ArrayList();//2.创建代理对象//参数一类加载器。当前类名.class.getClassLoader()// 找到是谁把当前的类加载到内存中了我再麻烦他帮我干一件事情把后面的代理类也加载到内存//参数二是一个数组在数组里面写接口的字节码文件对象。// 如果写了List那么表示代理可以代理List接口里面所有的方法对这些方法可以增强或者拦截// 但是一定要写ArrayList真实实现的接口// 假设在第二个参数中写了MyInter接口那么是错误的。// 因为ArrayList并没有实现这个接口那么就无法对这个接口里面的方法进行增强或拦截//参数三用来创建代理对象的匿名内部类List proxyList (List) Proxy.newProxyInstance(//参数一类加载器MyProxyDemo1.class.getClassLoader(),//参数二是一个数组表示代理对象能代理的方法范围new Class[]{List.class},//参数三本质就是代理对象new InvocationHandler() {Override//invoke方法参数的意义//参数一表示代理对象一般不用了解//参数二就是方法名我们可以对方法名进行判断是增强还是拦截//参数三就是下面第三步调用方法时传递的参数。//举例1//list.add(阿玮好帅);//此时参数二就是add这个方法名//此时参数三 args[0] 就是 阿玮好帅//举例2//list.set(1, aaa);//此时参数二就是set这个方法名//此时参数三 args[0] 就是 1 args[1]aaapublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//对add方法做一个增强统计耗时时间if (method.getName().equals(add)) {long start System.currentTimeMillis();//调用集合的方法真正的添加数据method.invoke(list, args);long end System.currentTimeMillis();System.out.println(耗时时间 (end - start));//需要进行返回返回值要跟真正增强或者拦截的方法保持一致return true;}else if(method.getName().equals(remove) args[0] instanceof Integer){System.out.println(拦截了按照索引删除的方法);return null;}else if(method.getName().equals(remove)){System.out.println(拦截了按照对象删除的方法);return false;}else{//如果当前调用的是其他方法,我们既不增强也不拦截method.invoke(list,args);return null;}}});//3.调用方法//如果调用者是list就好比绕过了第二步的代码直接添加元素//如果调用者是代理对象此时代理才能帮我们增强或者拦截//每次调用方法的时候都不会直接操作集合//而是先调用代理里面的invoke在invoke方法中进行判断可以增强或者拦截proxyList.add(aaa);proxyList.add(bbb);proxyList.add(ccc);proxyList.add(ddd);proxyList.remove(0);proxyList.remove(aaa);//打印集合System.out.println(list);}
}
三、日志
3.1 作用
跟输出语句一样可以把程序在运行过程中的详细信息都打印在控制台上。
利用log日志还可以把这些详细信息保存到文件和数据库中。
3.2 使用步骤
不是java的也不是自己写的是第三方提供的代码所以我们要导入jar包。 把第三方的代码导入到当前的项目当中 新建lib文件夹把jar粘贴到lib文件夹当中全选后右键点击选择add as a .... 检测导入成功导入成功后jar包可以展开。在项目重构界面可以看到导入的内容 把配置文件粘贴到src文件夹下 在代码中获取日志对象 调用方法打印日志
3.3 日志级别
TRACE, DEBUG, INFO, WARN, ERROR
还有两个特殊的
ALL输出所有日志
OFF关闭所有日志
日志级别从小到大的关系
TRACE DEBUG INFO WARN ERROR
3.4 配置文件
?xml version1.0 encodingUTF-8?
configuration!--CONSOLE 表示当前的日志信息是可以输出到控制台的。--appender nameCONSOLE classch.qos.logback.core.ConsoleAppender!--输出流对象 默认 System.out 改为 System.err--targetSystem.out/targetencoder!--格式化输出%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度%msg日志消息%n是换行符--pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %c [%thread] : %msg%n/pattern/encoder/appender!-- File是输出的方向通向文件的 --appender nameFILE classch.qos.logback.core.rolling.RollingFileAppenderencoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/patterncharsetutf-8/charset/encoder!--日志输出路径--fileC:/code/itheima-data.log/file!--指定日志文件拆分和压缩规则--rollingPolicyclassch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy!--通过指定压缩文件名称来确定分割文件方式--fileNamePatternC:/code/itheima-data2-%d{yyyy-MMdd}.log%i.gz/fileNamePattern!--文件拆分大小--maxFileSize1MB/maxFileSize/rollingPolicy/appender!--level:用来设置打印级别大小写无关TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF 默认debugroot可以包含零个或多个appender-ref元素标识这个输出位置将会被本日志级别控制。--root levelinfoappender-ref refCONSOLE/appender-ref refFILE //root
/configuration
四、类加载器
4.1类加载器 作用 负责将.class文件存储的物理文件加载在到内存中
4.2类加载的完整过程 类加载时机 简单理解字节码文件什么时候会被加载到内存中 有以下的几种情况 创建类的实例对象 调用类的类方法 访问类或者接口的类变量或者为该类变量赋值 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象 初始化某个类的子类 直接使用java.exe命令来运行某个主类 总结而言用到了就加载不用不加载 类加载过程 加载 通过包名 类名获取这个类准备用流进行传输 在这个类加载到内存中 加载完毕创建一个class对象 2.链接 验证 确保Class文件字节流中包含的信息符合当前虚拟机的要求并且不会危害虚拟机自身安全(文件中的信息是否符合虚拟机规范有没有安全隐患) 准备 负责为类的类变量被static修饰的变量分配内存并设置默认初始化值(初始化静态变量) 解析 将类的二进制数据流中的符号引用替换为直接引用 (本类中如果用到了其他类此时就需要找到对应的类) 3.初始化 根据程序员通过程序制定的主观计划去初始化类变量和其他资源 (静态变量赋值以及初始化其他资源) 小结 当一个类被使用的时候才会加载到内存 类加载的过程: 加载、验证、准备、解析、初始化
4.3类加载的分类【理解】 分类 Bootstrap class loader虚拟机的内置类加载器通常表示为null 并且没有父null Platform class loader平台类加载器,负责加载JDK中一些特殊的模块 System class loader系统类加载器,负责加载用户类路径上所指定的类库 类加载器的继承关系 System的父加载器为Platform Platform的父加载器为Bootstrap 代码演示 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);}
}
4.4双亲委派模型【理解】 介绍 如果一个类加载器收到了类加载请求它并不会自己先去加载而是把这个请求委托给父类的加载器去执行如果父类加载器还存在其父类加载器则进一步向上委托依次递归请求最终将到达顶层的启动类加载器如果父类加载器可以完成类加载任务就成功返回倘若父类加载器无法完成此加载任务子加载器才会尝试自己去加载这就是双亲委派模式
4.5ClassLoader 中的两个方法【应用】 方法介绍 方法名说明public static ClassLoader getSystemClassLoader()获取系统类加载器public InputStream getResourceAsStream(String name)加载某一个资源文件 示例代码 public class ClassLoaderDemo2 {public static void main(String[] args) throws IOException {//static ClassLoader getSystemClassLoader() 获取系统类加载器//InputStream getResourceAsStream(String name) 加载某一个资源文件//获取系统类加载器ClassLoader systemClassLoader ClassLoader.getSystemClassLoader();//利用加载器去加载一个指定的文件//参数文件的路径放在src的根目录下默认去那里加载//返回值字节流。InputStream is systemClassLoader.getResourceAsStream(prop.properties);Properties prop new Properties();prop.load(is);System.out.println(prop);is.close();}
}
五、xml
5.1概述【理解】 万维网联盟(W3C) 万维网联盟(W3C)创建于1994年又称W3C理事会。1994年10月在麻省理工学院计算机科学实验室成立。建立者 Tim Berners-Lee (蒂姆·伯纳斯·李)。是Web技术领域最具权威和影响力的国际中立性技术标准机构。到目前为止W3C已发布了200多项影响深远的Web技术标准及实施指南 如广为业界采用的超文本标记语言HTML标准通用标记语言下的一个应用、 可扩展标记语言XML标准通用标记语言下的一个子集 以及帮助残障人士有效获得Web信息的无障碍指南WCAG等 xml概述 XML的全称为(EXtensible Markup Language)是一种可扩展的标记语言标记语言: 通过标签来描述数据的一门语言(标签有时我们也将其称之为元素)可扩展标签的名字是可以自定义的,XML文件是由很多标签组成的,而标签名是可以自定义的 作用 用于进行存储数据和传输数据 作为软件的配置文件 作为配置文件的优势 可读性好 可维护性高 5.2标签的规则【应用】 标签由一对尖括号和合法标识符组成 student 标签必须成对出现 student /student
前边的是开始标签后边的是结束标签 特殊的标签可以不成对,但是必须有结束标记 address/ 标签中可以定义属性,属性和标签名空格隔开,属性值必须用引号引起来 student id1 /student 标签需要正确的嵌套 这是正确的: student id1 name张三/name /student
这是错误的: student id1name张三/student/name
5.3语法规则【应用】 语法规则 XML文件的后缀名为xml 文档声明必须是第一行第一列 ?xml version“1.0” encoding“UTF-8” standalone“yes”?version该属性是必须存在的encoding该属性不是必须的 打开当前xml文件的时候应该是使用什么字符编码表(一般取值都是UTF-8) standalone: 该属性不是必须的描述XML文件是否依赖其他的xml文件取值为yes/no 必须存在一个根标签有且只能有一个 XML文件中可以定义注释信息 XML文件中可以存在以下特殊字符 lt; 小于
gt; 大于
amp; 和号
apos; 单引号
quot; 引号 XML文件中可以存在CDATA区 ![CDATA[ …内容… ]] 示例代码 ?xml version1.0 encodingUTF-8 ?
!--注释的内容--
!--本xml文件用来描述多个学生信息--
students!--第一个学生信息--student id1name张三/nameage23/ageinfo学生lt; gt;gt;gt;gt;gt;gt;gt;gt;gt;gt;gt;的信息/infomessage ![CDATA[内容 ]]]/message/student!--第二个学生信息--student id2name李四/nameage24/age/student/students 5.4xml解析【应用】 概述 xml解析就是从xml中获取到数据 常见的解析思想 DOM(Document Object Model)文档对象模型:就是把文档的各个组成部分看做成对应的对象。会把xml文件全部加载到内存,在内存中形成一个树形结构,再获取对应的值 常见的解析工具 JAXP: SUN公司提供的一套XML的解析的API JDOM: 开源组织提供了一套XML的解析的API-jdom DOM4J: 开源组织提供了一套XML的解析的API-dom4j,全称Dom For Java pull: 主要应用在Android手机端解析XML 解析的准备工作 我们可以通过网站dom4j 去下载dom4j 今天的资料中已经提供,我们不用再单独下载了,直接使用即可 将提供好的dom4j-1.6.1.zip解压,找到里面的dom4j-1.6.1.jar 在idea中当前模块下新建一个libs文件夹,将jar包复制到文件夹中 选中jar包 - 右键 - 选择add as library即可 需求 解析提供好的xml文件 将解析到的数据封装到学生对象中 并将学生对象存储到ArrayList集合中 遍历集合 代码实现
?xml version1.0 encodingUTF-8 ?
!--注释的内容--
!--本xml文件用来描述多个学生信息--
students!--第一个学生信息--student id1name张三/nameage23/age/student!--第二个学生信息--student id2name李四/nameage24/age/student/students// 上边是已经准备好的student.xml文件
public class Student {private String id;private String name;private int age;public Student() {}public Student(String id, String name, int age) {this.id id;this.name name;this.age age;}public String getId() {return id;}public void setId(String id) {this.id id;}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;}Overridepublic String toString() {return Student{ id id \ , name name \ , age age };}
}/*** 利用dom4j解析xml文件*/
public class XmlParse {public static void main(String[] args) throws DocumentException {//1.获取一个解析器对象SAXReader saxReader new SAXReader();//2.利用解析器把xml文件加载到内存中,并返回一个文档对象Document document saxReader.read(new File(myxml\\xml\\student.xml));//3.获取到根标签Element rootElement document.getRootElement();//4.通过根标签来获取student标签//elements():可以获取调用者所有的子标签.会把这些子标签放到一个集合中返回.//elements(标签名):可以获取调用者所有的指定的子标签,会把这些子标签放到一个集合中并返回//List list rootElement.elements();ListElement studentElements rootElement.elements(student);//System.out.println(list.size());//用来装学生对象ArrayListStudent list new ArrayList();//5.遍历集合,得到每一个student标签for (Element element : studentElements) {//element依次表示每一个student标签//获取id这个属性Attribute attribute element.attribute(id);//获取id的属性值String id attribute.getValue();//获取name标签//element(标签名):获取调用者指定的子标签Element nameElement element.element(name);//获取这个标签的标签体内容String name nameElement.getText();//获取age标签Element ageElement element.element(age);//获取age标签的标签体内容String age ageElement.getText();// System.out.println(id);
// System.out.println(name);
// System.out.println(age);Student s new Student(id,name,Integer.parseInt(age));list.add(s);}//遍历操作for (Student student : list) {System.out.println(student);}}
}
5.5DTD约束【理解】 什么是约束 用来限定xml文件中可使用的标签以及属性 约束的分类 DTD schema 编写DTD约束 步骤 创建一个文件这个文件的后缀名为.dtd 看xml文件中使用了哪些元素 !ELEMENT 可以定义元素 判断元素是简单元素还是复杂元素 简单元素没有子元素。复杂元素有子元素的元素 代码实现 !ELEMENT persons (person)
!ELEMENT person (name,age)
!ELEMENT name (#PCDATA)
!ELEMENT age (#PCDATA) 引入DTD约束 引入DTD约束的三种方法 引入本地dtd !DOCTYPE 根元素名称 SYSTEM ‘DTD文件的路径 在xml文件内部引入 !DOCTYPE 根元素名称 [ dtd文件内容 ] 引入网络dtd !DOCTYPE 根元素的名称 PUBLIC DTD文件名称 DTD文档的URL 代码实现 引入本地DTD约束 // 这是persondtd.dtd文件中的内容,已经提前写好
!ELEMENT persons (person)
!ELEMENT person (name,age)
!ELEMENT name (#PCDATA)
!ELEMENT age (#PCDATA)// 在person1.xml文件中引入persondtd.dtd约束
?xml version1.0 encodingUTF-8 ?
!DOCTYPE persons SYSTEM persondtd.dtdpersonspersonname张三/nameage23/age/person/persons 在xml文件内部引入 ?xml version1.0 encodingUTF-8 ?
!DOCTYPE persons [!ELEMENT persons (person)!ELEMENT person (name,age)!ELEMENT name (#PCDATA)!ELEMENT age (#PCDATA)]personspersonname张三/nameage23/age/person/persons 引入网络dtd ?xml version1.0 encodingUTF-8 ?
!DOCTYPE persons PUBLIC dtd文件的名称 dtd文档的URLpersonspersonname张三/nameage23/age/person/persons
DTD语法 定义元素 定义一个元素的格式为!ELEMENT 元素名 元素类型简单元素 EMPTY: 表示标签体为空 ANY: 表示标签体可以为空也可以不为空 PCDATA: 表示该元素的内容部分为字符串 复杂元素 直接写子元素名称. 多个子元素可以使用,或者|隔开 ,表示定义子元素的顺序 ; |: 表示子元素只能出现任意一个 ?零次或一次, 一次或多次, *零次或多次;如果不写则表示出现一次 定义属性 格式 定义一个属性的格式为!ATTLIST 元素名称 属性名称 属性的类型 属性的约束属性的类型 CDATA类型普通的字符串 属性的约束: // #REQUIRED 必须的 // #IMPLIED 属性不是必需的 // #FIXED value属性值是固定的 代码实现 !ELEMENT persons (person)
!ELEMENT person (name,age)
!ELEMENT name (#PCDATA)
!ELEMENT age (#PCDATA)
!ATTLIST person id CDATA #REQUIRED?xml version1.0 encodingUTF-8 ?
!DOCTYPE persons SYSTEM persondtd.dtdpersonsperson id001name张三/nameage23/age/personperson id 002name张三/nameage23/age/person/persons5.6schema约束【理解】 schema和dtd的区别 schema约束文件也是一个xml文件符合xml的语法这个文件的后缀名.xsd 一个xml中可以引用多个schema约束文件多个schema使用名称空间区分名称空间类似于java包名 dtd里面元素类型的取值比较单一常见的是PCDATA类型但是在schema里面可以支持很多个数据类型 schema 语法更加的复杂
编写schema约束 步骤 1创建一个文件这个文件的后缀名为.xsd。2定义文档声明3schema文件的根标签为 schema4在schema中定义属性 xmlnshttp://www.w3.org/2001/XMLSchema5在schema中定义属性 targetNamespace 唯一的url地址指定当前这个schema文件的名称空间。6在schema中定义属性 elementFormDefaultqualified“表示当前schema文件是一个质量良好的文件。7通过element定义元素8判断当前元素是简单元素还是复杂元素 代码实现
?xml version1.0 encodingUTF-8 ?
schemaxmlnshttp://www.w3.org/2001/XMLSchematargetNamespacehttp://www.itheima.cn/javaseelementFormDefaultqualified
!--定义persons复杂元素--element namepersonscomplexTypesequence!--定义person复杂元素--element name personcomplexTypesequence!--定义name和age简单元素--element name name type string/elementelement name age type string/element/sequence/complexType/element/sequence/complexType/element/schema引入schema约束 步骤 1在根标签上定义属性xmlnshttp://www.w3.org/2001/XMLSchema-instance2通过xmlns引入约束文件的名称空间3给某一个xmlns属性添加一个标识用于区分不同的名称空间 格式为: xmlns:标识“名称空间地址” ,标识可以是任意的但是一般取值都是xsi4通过xsi:schemaLocation指定名称空间所对应的约束文件路径 格式为xsi:schemaLocation 名称空间url 文件路径“ 代码实现 ?xml version1.0 encodingUTF-8 ?personsxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlnshttp://www.itheima.cn/javasexsi:schemaLocationhttp://www.itheima.cn/javase person.xsd
personname张三/nameage23/age/person/personsschema约束定义属性 代码示例 ?xml version1.0 encodingUTF-8 ?
schemaxmlnshttp://www.w3.org/2001/XMLSchematargetNamespacehttp://www.itheima.cn/javaseelementFormDefaultqualified
!--定义persons复杂元素--element namepersonscomplexTypesequence!--定义person复杂元素--element name personcomplexTypesequence!--定义name和age简单元素--element name name type string/elementelement name age type string/element/sequence!--定义属性required( 必须的)/optional( 可选的)--attribute nameid typestring userequired/attribute/complexType/element/sequence/complexType/element/schema?xml version1.0 encodingUTF-8 ?
personsxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlnshttp://www.itheima.cn/javasexsi:schemaLocationhttp://www.itheima.cn/javase person.xsd
person id001name张三/nameage23/age/person/persons六、单元测试Junit
6.1 什么是单元测试掌握
对部分代码进行测试。
6.2 Junit的特点掌握 是一个第三方的工具。把别人写的代码导入项目中专业叫法导jar包 如果运行结果显示绿色表示运行结果是正确的。 如果运行结果显示红色表示运行结果是错误的。
6.3 基本用法掌握
1一定要先写一个方法。
2在这个方法的上面写Test
3鼠标点一下Test 按alt 回车点击Junit4
此时就可以自动导包。
如果自动导包失败连接外网或者自己手动导包
如果导包成功在左下角就会出现Junit4的相关jar包
6.3.1手动导包掌握
1在当前模块下右键新建一个文件夹lib
2把今天资料里面的两个jar包拷贝到lib文件夹里面
3选中两个jar右键点击add as a lib....
4到代码中找到Test按alt 回车再来导入。
6.3.2运行测试代码掌握 只能直接运行无参无返回值的非静态方法 想要运行谁就右键点击哪个方法。如果想要运行一个类里面所有的测试方法选择类名有点点击即可。
6.3.3Junit正确的打开方式正确的使用方式掌握
注意点并不是直接在要测试的方法上面直接加Test
原因因为要测试的方法有可能是有参数的有返回值或者是静态的。
6.3.4正确的使用方式掌握
1新建测试类
2新建测试方法要测试的方法名 Test methodTest
3在这个方法中直接调用要测试的方法
4在测试方法的上面写Test
代码示例
//真正用来测试的类
//测试用例测试类
public class JunitTest {//在这个类里面再写无参无返回值的非静态方法//在方法中调用想要测试的方法Testpublic void method2Test(){//调用要测试的方法JunitDemo1 jd new JunitDemo1();jd.method2(10);}
} 6.3.5实际开发中单元测试的使用方式掌握
需求测试File中的delete方法写的是否正确掌握
开发中的测试原则
不污染原数据。
代码示例
public class JunitDemo3 {//在实际开发中真正完整的单元测试该怎么写//前提//以后在工作的时候测试代码不能污染原数据。修改篡改//1.利用Before去对数据做一个初始化的动作//2.利用Test真正的去测试方法//3.利用After去还原数据//需求测试File类中的delete方法是否书写正确Beforepublic void beforemethod() throws IOException {//先备份File src new File(C:\\Users\\moon\\Desktop\\a.txt);File dest new File(C:\\Users\\moon\\Desktop\\copy.txt);FileInputStream fis new FileInputStream(src);FileOutputStream fos new FileOutputStream(dest);int b;while((b fis.read()) ! -1){fos.write(b);}fos.close();fis.close();}//作为一个标准的测试人员运行完单元测试之后不能污染原数据//需要达到下面两个要求//1.得到结果//2.a.txt还在而且其他的备份文件消失Testpublic void method(){File file new File(C:\\Users\\moon\\Desktop\\a.txt);boolean delete file.delete();//检查a.txt是否存在boolean exists file.exists();//只有同时满足了下面所有的断言才表示delete方法编写正确Assert.assertEquals(delete方法出错了,delete,true);Assert.assertEquals(delete方法出错了,exists,false);}Afterpublic void aftermethod() throws IOException {//还要对a.txt做一个还原File src new File(C:\\Users\\moon\\Desktop\\copy.txt);File dest new File(C:\\Users\\moon\\Desktop\\a.txt);FileInputStream fis new FileInputStream(src);FileOutputStream fos new FileOutputStream(dest);int b;while((b fis.read()) ! -1){fos.write(b);}fos.close();fis.close();//备份数据要删除src.delete();}
} 测试Properties类中的store方法是否书写正确
开发心得
1.Before 准备数据
2.Test 测试方法
3.After 还原 Before
准备数据 1.创建Properties的对象 2.put数据到集合当中 //只不过在下面的方法中我们也需要用到Properties的对象所以写完之后要挪到成员位置 Test
调用store方法保存数据到本地文件
断言1 判断当前文件是否存在 断言2 文件的大小一定是大于0 断言3 再次读取文件中的数据判断是否跟集合中一致
结论 如果所有的断言都通过了表示store方法是正确的 After
把本地文件给删除
6.3.6扩展点
在单元测试中相对路径是相对当前模块而言的。
代码示例
File file new File(aweihaoshuai.txt);
file.createNewFile();
//此时是把aweihaoshuai.txt这个文件新建到模块中了。 七、注解
7.1 注释和注解的区别掌握
共同点都可以对程序进行解释说明。
不同点注释是给程序员看的。只在Java中有效。在class文件中不存在注释的。
当编译之后会进行注释擦除。
注解是给虚拟机看的。当虚拟机看到注解之后就知道要做什么事情了。
7.2 如何使用注解掌握
在以前看过注解Override。
当子类重写父类方法的时候在重写的方法上面写Override。
当虚拟机看到Override的时候就知道下面的方法是重写的父类的。检查语法如果语法正确编译正常如果语法错误就会报错。
7.3 Java中已经存在的注解掌握
Override表示方法的重写
Deprecated表示修饰的方法已过时
SuppressWarnings(all)压制警告 除此之外还需要掌握第三方框架中提供的注解
比如Junit
Test 表示运行测试方法
Before 表示在Test之前运行进行数据的初始化
After 表示在Test之后运行进行数据的还原
7.4 自定义注解了解
自定义注解单独存在是没有什么意义的一般会跟反射结合起来使用会用发射去解析注解。
针对于注解只要掌握会使用别人已经写好的注解即可。
关于注解的解析一般是在框架的底层已经写好了。
7.5 特殊属性掌握
value
当注解中只有一个属性,并且属性名是value,使用注解时,可以省略value属性名
代码示例
//注解的定义
public interface Anno2 {public String value();public int age() default 23;
}//注解的使用
Anno2(123)
public class AnnoDemo2 {Anno2(123)public void method(){}
} 7.6 元注解了解
可以写在注解上面的注解
Target 指定注解能在哪里使用
Retention 可以理解为保留时间(生命周期)
7.6.1Target:
作用用来标识注解使用的位置如果没有使用该注解标识则自定义的注解可以使用在任意位置。
可使用的值定义在ElementType枚举类中常用值如下 TYPE类接口 FIELD, 成员变量 METHOD, 成员方法 PARAMETER, 方法参数 CONSTRUCTOR, 构造方法 LOCAL_VARIABLE, 局部变量
7.6.2Retention
作用用来标识注解的生命周期(有效范围)
可使用的值定义在RetentionPolicy枚举类中常用值如下 SOURCE注解只作用在源码阶段生成的字节码文件中不存在 CLASS注解作用在源码阶段字节码文件阶段运行阶段不存在默认值 RUNTIME注解作用在源码阶段字节码文件阶段运行阶段
注解的解析
7.7 模拟JUnit自带的Test注解了解
代码示例
Target(ElementType.METHOD)
Retention(RetentionPolicy.RUNTIME)
public interface MyTest {
}public class MyTestMethod {MyTestpublic void method1(){System.out.println(method1);}public void method2(){System.out.println(method2);}MyTestpublic void method3(){System.out.println(method3);}
}public class MyTestDemo {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {//1,获取class对象Class clazz Class.forName(com.itheima.test2.MyTestMethod);//获取对象Object o clazz.newInstance();//2.获取所有方法Method[] methods clazz.getDeclaredMethods();for (Method method : methods) {//method依次表示类里面的每一个方法method.setAccessible(true);//判断当前方法有没有MyTest注解if(method.isAnnotationPresent(MyTest.class)){method.invoke(o);}}}
}
7.8 注解小结
掌握如何使用已经存在的注解即可。
Override表示方法的重写
Deprecated表示修饰的方法已过时
SuppressWarnings(all)压制警告
Test表示要运行的方法
在以后的实际开发中注解是使用框架已经提供好的注解。
自定义注解解析注解很难的了解一般会出现在框架的底层。当以后我们要自己写一个框架的时候才会用到自定义注解解析注解。 文章转载自: http://www.morning.ttaes.cn.gov.cn.ttaes.cn http://www.morning.kpnpd.cn.gov.cn.kpnpd.cn http://www.morning.whothehellami.com.gov.cn.whothehellami.com http://www.morning.yrjfb.cn.gov.cn.yrjfb.cn http://www.morning.xfhms.cn.gov.cn.xfhms.cn http://www.morning.slysg.cn.gov.cn.slysg.cn http://www.morning.yuminfo.com.gov.cn.yuminfo.com http://www.morning.xnflx.cn.gov.cn.xnflx.cn http://www.morning.hwprz.cn.gov.cn.hwprz.cn http://www.morning.zgpgl.cn.gov.cn.zgpgl.cn http://www.morning.lwtfx.cn.gov.cn.lwtfx.cn http://www.morning.kyfrl.cn.gov.cn.kyfrl.cn http://www.morning.sfwfk.cn.gov.cn.sfwfk.cn http://www.morning.gprzp.cn.gov.cn.gprzp.cn http://www.morning.blqsr.cn.gov.cn.blqsr.cn http://www.morning.mmxt.cn.gov.cn.mmxt.cn http://www.morning.kpcxj.cn.gov.cn.kpcxj.cn http://www.morning.chmcq.cn.gov.cn.chmcq.cn http://www.morning.nkqnn.cn.gov.cn.nkqnn.cn http://www.morning.bnbtp.cn.gov.cn.bnbtp.cn http://www.morning.pqjlp.cn.gov.cn.pqjlp.cn http://www.morning.ywqw.cn.gov.cn.ywqw.cn http://www.morning.yzsdp.cn.gov.cn.yzsdp.cn http://www.morning.ygmw.cn.gov.cn.ygmw.cn http://www.morning.ypxyl.cn.gov.cn.ypxyl.cn http://www.morning.cwznh.cn.gov.cn.cwznh.cn http://www.morning.ptdzm.cn.gov.cn.ptdzm.cn http://www.morning.ntyks.cn.gov.cn.ntyks.cn http://www.morning.ylyzk.cn.gov.cn.ylyzk.cn http://www.morning.wkknm.cn.gov.cn.wkknm.cn http://www.morning.prplf.cn.gov.cn.prplf.cn http://www.morning.jrqcj.cn.gov.cn.jrqcj.cn http://www.morning.lsmgl.cn.gov.cn.lsmgl.cn http://www.morning.ghqyr.cn.gov.cn.ghqyr.cn http://www.morning.nstml.cn.gov.cn.nstml.cn http://www.morning.dwmmf.cn.gov.cn.dwmmf.cn http://www.morning.hyryq.cn.gov.cn.hyryq.cn http://www.morning.cczrw.cn.gov.cn.cczrw.cn http://www.morning.brxzt.cn.gov.cn.brxzt.cn http://www.morning.qgtfl.cn.gov.cn.qgtfl.cn http://www.morning.nnhfz.cn.gov.cn.nnhfz.cn http://www.morning.kmcfw.cn.gov.cn.kmcfw.cn http://www.morning.bylzr.cn.gov.cn.bylzr.cn http://www.morning.lksgz.cn.gov.cn.lksgz.cn http://www.morning.dmzzt.cn.gov.cn.dmzzt.cn http://www.morning.qmwzz.cn.gov.cn.qmwzz.cn http://www.morning.gczqt.cn.gov.cn.gczqt.cn http://www.morning.jrgxx.cn.gov.cn.jrgxx.cn http://www.morning.wdwfm.cn.gov.cn.wdwfm.cn http://www.morning.hjsrl.cn.gov.cn.hjsrl.cn http://www.morning.zbpqq.cn.gov.cn.zbpqq.cn http://www.morning.qytby.cn.gov.cn.qytby.cn http://www.morning.jcwhk.cn.gov.cn.jcwhk.cn http://www.morning.qkgwz.cn.gov.cn.qkgwz.cn http://www.morning.dwncg.cn.gov.cn.dwncg.cn http://www.morning.gthgf.cn.gov.cn.gthgf.cn http://www.morning.sthgm.cn.gov.cn.sthgm.cn http://www.morning.mqfkd.cn.gov.cn.mqfkd.cn http://www.morning.tcxk.cn.gov.cn.tcxk.cn http://www.morning.ggxbyhk.cn.gov.cn.ggxbyhk.cn http://www.morning.rccpl.cn.gov.cn.rccpl.cn http://www.morning.brxzt.cn.gov.cn.brxzt.cn http://www.morning.skdhm.cn.gov.cn.skdhm.cn http://www.morning.lhytw.cn.gov.cn.lhytw.cn http://www.morning.dpflt.cn.gov.cn.dpflt.cn http://www.morning.cnhgc.cn.gov.cn.cnhgc.cn http://www.morning.bflwj.cn.gov.cn.bflwj.cn http://www.morning.rnqbn.cn.gov.cn.rnqbn.cn http://www.morning.qjlkp.cn.gov.cn.qjlkp.cn http://www.morning.mywnk.cn.gov.cn.mywnk.cn http://www.morning.bsrp.cn.gov.cn.bsrp.cn http://www.morning.wgzgr.cn.gov.cn.wgzgr.cn http://www.morning.rkfwr.cn.gov.cn.rkfwr.cn http://www.morning.nydtt.cn.gov.cn.nydtt.cn http://www.morning.fllfc.cn.gov.cn.fllfc.cn http://www.morning.ngkgy.cn.gov.cn.ngkgy.cn http://www.morning.qxmys.cn.gov.cn.qxmys.cn http://www.morning.ryfq.cn.gov.cn.ryfq.cn http://www.morning.wgxtz.cn.gov.cn.wgxtz.cn http://www.morning.jokesm.com.gov.cn.jokesm.com