文章目录
- 1.配置文件properities
- 2.快速上手
- 3.常见方法
- 3.1读取配置文件
- 3.2获取k-v值
- 3.3修改k-v值
- 3.4unicode的说明
- 4.反射的引入
- 4.1传统写法
- 4.2反射的写法(初识)
- 4.3反射的介绍
- 4.4获得class类的方法
- 4.5所有类型的class对象
- 4.6类加载过程
- 4.7类初始化的过程
- 4.8类加载过程
- 4.9获取类的运行时结构
- 4.10动态创建对象
- 4.11获取成员属性方法
- 4.12性能测试
- 5.反射的应用
- 5.1操作泛型
- 5.2操作注解
- 6.注解annotation
- 6.1内置注解
- 6.2元注解
- 6.3自定义注解
- 6.3自定义注解
1.配置文件properities
这个properity是一个类:方便实现对于这个项目的相关的属性内容的设置;
例如我们想要使用这个程序对于这个数据库进行操作,我们的这个程序本来是针对于这个数据库01进行操作的,后来修改为这个对于02进行操作,如果我们没有使用这个配置文件,就需要在这个源码上面进行修改,这个不是我们想要看到的,如果我们引入了这个配置文件;
这个时候因为我们的这个程序是从这个配置文件里面读取内容的,因此这个程序的代码不需要进行修改,我们只需要把这个配置文件的这个用户名和密码修改为我们的db02数据库的就可以了;
2.快速上手
下面的这个就是我们的一个包包里面的配置文件:这个配置文件里面的信息就是我们的ip,用户名和密码;
我们在这个java文件里面,需要创建对象读取这个配置文件里面的内容,这个就涉及到了这个路径的指定,是从我们的这个src开始的,根据我们的这个目录结构进行修改即可;
然后我们使用这个while循环不断的从这个对象里面进行内容的读取,这个就会全部打印输出;
在上面的这个方式下,我们的打印输出的结果就是我们的这个配置文件里面的格式:
下面的这个就是另外一个打印输出的方法的展示:就是我们不是直接把这个配置文件里面的信息打印出来,而是按照我们想要的这个格式,使用这个split进行分割处理,进行拼接之后再打印出来;(这个刚开始的时候遇到了bug,就是因为这个配置文件每一行之间加上了空格,这样的话督导第二行没有了然后这个split[1]这个下标就会报错是越界,因此上面的这个配置文件里面的这个内容需进行修改为连续的三行,否则会报错);
但是即使这样,我们想要修改这个文件的用户名和方法还是不容易;因为这个需要我们的代码进行修改;
3.常见方法
3.1读取配置文件
我们首先需要创建一个类,读取我们的这个配置文件内容(new filereader里面的这个参数就是我们的这个配置文件的地址);
最后使用这个list方法把我们的这个读取的文件里面的内容打印到我们的这个对应的设备上面去;
3.2获取k-v值
在上面的这个基础上,我们可以使用这个getProperty方法,根据我们传递进去这个key参数,获得这个对应的value值,这个就是我们根据这个k获取到这个对应的value的一个方法;
3.3修改k-v值
这个表面上写的是修改,实际上是包含了这个添加新的这个k-v的情况的:
我们调用这个里面的serProperties方法对于这个key对应的value进行修改,如果这个key是存在的,这个就是修改对应的value数值;
如果这个key不存在,下面的这个password2就是不存在的,这个时候就是进行新的k-v的添加;
store表示把这个创建的对象存储到我们的这个配置文件里面去,第一个参数就是我们的路径,第二个参数写的是comment(这个是idea自带的)表示的就是注释的意思,我们使用null代替就可以了;
3.4unicode的说明
我们上面修改这个名字是中文,这个时候我们的这个配置文件里面显示的其实是这个unicode编码,并不是我们的中文,我们可以使用这个转换器进行查看结果是否正确;
我们使用这个转换工具就可以看到这个效果:
4.反射的引入
4.1传统写法
我们的这个反射是需要基于上面的这个类的,因此上面相当于就是介绍一下这个类的相关的用法;
下面的是是两个传统方法:
1)直接创建对象,调用这个对象里面的方法;
2)使用文件流读取,获取这个对应的value数值,并且打印出来;
4.2反射的写法(初识)
4.3反射的介绍
下面的这个就是我们自己定义一个实体类:
4.4获得class类的方法
4.5所有类型的class对象
2)元素类型一样,例如这个数组,个数不一样,但是这个类型一样,他们的这个class打印出来的这个hashcode还是一样的;
4.6类加载过程
上面的这个类加载的过程,分为三个步骤:
1)加载:就是生成在这个相关的数据,每一个类里面都是有自己的这个数据的;
2)链接:每一个类生成自己的这个Class对象,进行连接就是检查是不是有错误;
3)初始化:没有错误就会进行初始化,刚开始这个m初始化的是0.然后我们创建这个对象,这个对象就会找到自己的这个类对象,进行这个合并,刚开始是300,后来是100,因此这个最后打印输出的这个结果就是100;
4.7类初始化的过程
1)主动引用一定会发生这个类的初始化:下面的这个new对象和反射就是主动引用的过程;
2)被动引用不会进行类的初始化:下面的这个直接调用子类的这个静态变量,创建数组,以及常量的使用都是属于这个被动引用的范畴的,都是不会执行这个初始化的操作的;
4.8类加载过程
1)类加载的作用:把class文件的字节码的内容加载到我们的这个内存里面去,在这个堆区上面生成一个Class对象,这个对象就是我们的访问入口;
2)类缓存:一旦某一个类加载到了这个类加载器里面去,他就会维持一段时间,不过这个JVM的垃圾回收机制会对于这个Class对象进行处理;
4.9获取类的运行时结构
1)field就是获取这个类加载的时候的相关的属性,加上这个declare修饰就是强制获取,第一个只能获取到这个公共的方法,但是我们加上这个declare修饰之后即使是私有的方法,我们也是可以获取到的;
4.10动态创建对象
下面的这个就是需要有我们的无参数的构造器:
上面的这个是需要我们的这个类里面有无参数的构造方法,如果这个无参数的构造方法没有了,这个时候就会报错,下面的这个就是在原来的这个基础上面,我们自己写一个构造器出来,这样无论是有参数无参数,我们自己写的这个构造器都是可以传参的;
我们的这个构造器里面的参数就是我们的三个成员变量,我们创建对象的时候,就是用我们的这个构造器;
4.11获取成员属性方法
下面的这个就是我们使用无参数的构造器创建对象,setAccessible表示的就是关闭安全检查,即使我们的这个name是私有的,我们使用这个declared版本的还是可以得到的;
set相当于就是传递参数,第一个就是我们的这个对象,第二个参数就是这个对象的属性name具体值;
4.12性能测试
下面的这个是三个不同的方式的一个效率的对比:
1)test01就是普通方法;
2)test02就是反射,但是不关闭这个检测;
3)test03就是2的基础上面关闭这个检测的机制;
可以在自己的这个IDEA上面运行感受一下这个时间的耗费;
public class Test {public static void test01 () {User user = new User();long startTime = System.currentTimeMillis();for (int i = 0; i < 100000000; i++) {user.getName();}long endTime = System.currentTimeMillis();System.out.println("正常运行"+(endTime - startTime)+"ms");}public static void test02 () throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {User user = new User();Class c1=user.getClass();Method getName = c1.getDeclaredMethod("getName",null);//getName.setAccessible(true);long startTime = System.currentTimeMillis();for (int i = 0; i < 100000000; i++) {getName.invoke(user,null);}long endTime = System.currentTimeMillis();System.out.println("反射的方式,不关闭检测:"+(endTime - startTime)+"ms");}public static void test03 () throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {User user = new User();Class c1=user.getClass();Method getName = c1.getDeclaredMethod("getName",null);getName.setAccessible(true);long startTime = System.currentTimeMillis();for (int i = 0; i < 100000000; i++) {getName.invoke(user,null);}long endTime = System.currentTimeMillis();System.out.println("反射的方式,关闭检测:"+(endTime - startTime)+"ms");}public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {test01();test02();test03();}
}class User{String name;int age;int id;public User(String name, int age, int id) {};public User() {}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 int getId() {return id;}public void setId(int id) {this.id = id;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +", id=" + id +'}';}
}
5.反射的应用
5.1操作泛型
打印结果获取这个泛型的参数类型的相关的信息:
5.2操作注解
下面的这个实际上是基于一个数据库的;
我们可以获取这个方法的注解,以及这个相关的属性的注解
import java.lang.annotation.*;
import java.lang.reflect.Field;public class Test{public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {Class c1 = Class.forName("demo18.Test2");Annotation[] annotations = c1.getAnnotations();for (Annotation annotation : annotations) {System.out.println(annotation);}Tablekuang tablekuang = (Tablekuang)c1.getAnnotation(Tablekuang.class);String value = tablekuang.value();System.out.println(value);Field f = c1.getDeclaredField("name");Fieldkuang annotation = f.getAnnotation(Fieldkuang.class);System.out.println(annotation.columnName());System.out.println(annotation.type());System.out.println(annotation.length());}}
@Tablekuang("db_student")
class Test2 {@Fieldkuang(columnName = "student1",type="int",length=10)private int id;@Fieldkuang(columnName = "student2",type="int",length=10)private int age;@Fieldkuang(columnName = "student3",type="varchar",length=10)private String name;public Test2(){}public Test2(int id, int age, String name) {this.id = id;this.age = age;this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Test{" +"id=" + id +", age=" + age +", name='" + name + '\'' +'}';}
}@Target(ElementType.TYPE)
//生命周期
@Retention(RetentionPolicy.RUNTIME)
@interface Tablekuang{//下面的这个就是我们的注解,而不是方法String value();
}//下面的这个是对于属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldkuang{//下面的这个就是我们的注解,而不是方法String columnName();String type();int length();}
下面的这个就是获取我们的属性的注解,这个里面的name是可以进行修改的,如果是name我们获得的就是这个name的注解,如果是其他的成员变量,因为这个除了name还有我们的id和age,其他的两个属性也是可以获得对应的这个注解的,我们可以获取任何的字段的这个注解;
6.注解annotation
@override就是对于方法的重写,这个就是注解,我们经常使用,只是我们没有注意罢了;
下面的这个抑制警告的这个就是内置注解;override也是一个内置的注解;
6.1内置注解
6.2元注解
我们上面的这个注解就是模仿的这个下面的源代码进行书写的,就是定义这个interface,上面的这个target里面的这个参数表示的就是作用的范围;我们上面的这个例子里面的这个是method表示这个注解只能是作用在我们的这个方法的上面,因此上面我们把这个加在test类的外面的时候,这个注解就会报错;
当我们使用下面的这个类似于集合的方式进行表示的时候,这个的意思就是我们的这个注解不仅可以放在这个类上面,也是可以放到这个方法上面的;这个时候我们把这个注解放到这个test的外面,就不会报错了;
我们下面的这个retention表示这个注解生效的时间,也就是这个注解的生命周期,我们可以看到这个参数里面是有三个可选项的:我们一般写作这个runntime让这个注解的生命周期长一些;
下面的这个就是一个比较完整的演示:这个里面的@interface表示的是一个自定义的注解,我们后面还会遇到,其他的就是我们的元注解;
6.3自定义注解
们的这个注解不仅可以放在这个类上面,也是可以放到这个方法上面的;这个时候我们把这个注解放到这个test的外面,就不会报错了;
我们下面的这个retention表示这个注解生效的时间,也就是这个注解的生命周期,我们可以看到这个参数里面是有三个可选项的:我们一般写作这个runntime让这个注解的生命周期长一些;
下面的这个就是一个比较完整的演示:这个里面的@interface表示的是一个自定义的注解,我们后面还会遇到,其他的就是我们的元注解;