发表于: 2020-11-05 16:08:56
1 1300
今天完成的事情:
2.除了CRUD的基本单元测试,加上根据学员名字,学号去查找报名贴的单元测试
//根据名字查找用户
@Test
public void testFindStudentByname() throws Exception{
//通过配置资源对象获取studentDao对象
StudentQueryMapper studentQueryMapper = (StudentQueryMapper)applicationContext.getBean("studentQueryMapper");
//调用studentDao的方法
Student student=studentQueryMapper.findStudentByname("静夜思");
//输出用户信息
System.out.println(student);
}
//根据学号查询用户
@Test
public void testFindStudentByStudentId() throws Exception{
//通过配置资源对象获取studentDao对象
StudentQueryMapper studentQueryMapper = (StudentQueryMapper)applicationContext.getBean("studentQueryMapper");
//调用studentDao的方法
Student student=studentQueryMapper.findStudentByStudentId(21);
//输出用户信息
System.out.println(student);
}
5.分别使用Mybatis的配置文件和Annotation方式去配置数据库
这里先了解了一下注解是什么,但最后发现,其实并没有用到多少注解的内容。
什么是java注解
“注解(也成为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后的某个时刻非常方便的使用这些数据”。
举个例子,比如你新爷的女儿有很多彩色小球,都散落在地上了,你新爷跟她说,把红色的球都放到箱子里。然后你新爷的女儿屁颠儿屁颠儿的就去找红色的球,然后放到箱子里。这个过程就是Java注解的工作过程。这个红色就是球的标签,JAVA注解就是一段代码的标签。
举个例子,注释我们都知道,注释是对程序的一些说明,是为了让程序员看得懂程序而编写的。
而注解也是对程序的说明,不过是给计算机看的,计算机通过注解得到信息,可以把注解理解为标签,给类、方法、成员变量贴上标签,对他们进行一些说明。
在使用 Junit 单元测试时,我们在每一个单元测试的方法上都要加上一个@Test 注解,这个注解就是告诉测试程序这个方法是测试方法,是可以用作单元测试的,可以直接运行。
把相同的代码放在一起,贴上标签,使用的时候就可以很方便拿出来。分门别类
Java注解的目的
使用Java注解一般来说主要有三种目的
构建时指示: RetentionPolicy.SOURCE
编译期指示: RetentionPolicy.CLASS
运行时指示: RetentionPolicy.RUNTIME
- 提供信息给编译器: 编译器可以利用注解来探测错误和警告信息。
- 编译阶段时的处理: 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。
- 运行时的处理: 某些注解可以在程序运行的时候接受代码的提取。
Java注解可以用在构建期。当构建我们的工程时,构建进程会编译源码、生成xml文件,打包编译后的代码和文件到jar包。构建过程一般由构建工具自动完成,常用的构建工具有ant、maven。构建工具在构建时会自动扫描我们的代码,当遇到构建期注解时,会根据注解的内容生成源码或者其它文件。
基本注解
JAVA1.8之前,内置了三个基本注解,1.7新增了@SafeVarargs,1.8新增了@FunctionalInterface
@Overried:表示当前的方法定义将覆盖超类中的方法。如果你不小心拼写错误,或者方法中签名对不上被覆盖的方法,编译器就会发出错误提示。
@Deprected: 如果你使用了该注解标记的元素,那么编译器会发出警告信息。
@SuppressWarnings: 关闭不当的编译器警告信息。
@SafeVarargs:参数安全类型注解。它的目的是提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生 unchecked 这样的警告。
@FunctionalInterface:用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。
仅用上面的几种内置的基本注解显然不能满足我们日常开发需求,也不是JAVA提供注解的真正目的。我们日常开发过程中还是要定义自己的注解,帮助我们提高代码开发效率。
元注解
@Target,@Retention两个注解其实是由 Java 提供的 元注解 ,所谓元注解就是注解的注解,可能有点懵,我这样解释一下:
比如在类上面使用注解是表述类或描述类的一些信息,而元注解在注解中的使用就是用来表述或定义注解的一些信息。
@Retention:只能用于修饰注解定义,用于指定被修饰的注解可以保留多长时间。
RetentionPolicy.CLASS:表明注解会被记录在class文件中,但VM(虚拟机)在运行时不会被保留该注解,该内容不会被加载到虚拟机中。在不手动指定注解的生命周期时,默认注解声明周期都是该值
RetentionPolicy.SOURCE:表明注解被编译器丢弃(该类型的注解信息只会保留在源码里).源码经过编译后,注解信息就会被丢弃,不会保留在class文件中
RetentionPolicy. RUNTIME:表明该注解会被记录在class文件中而且在VM(虚拟机)运行时会被保留.虚拟机会加载class文件中的该注解的内容,可以使用反射机制读取该注解的内容
@Target:
ElementType.ANNOTATION_TYPE:表明该注解可用于注解之上
ElementType.CONSTRUCTOR:表明可用于构造函数之上
ElementType.FIELD:表明该注解可用于字段,包括enum常量之上
ElementType.LOCAL_VARIABLE:表明该注解可用于局部变量之上
ElementType.METHOD:表明该注解可用于方法之上
ElementType.PACKAGE:表明该注解可以用于包之上
ElementType.PARAMETER:表明该注解可用于类型参数
ElementType.TYPE:表明该注解可以用于类、接口、(包括注解类型)或枚举类型之上
@Inherited
@Inherited 负责指定注解可以被继承,但不是真正意义上的继承,注解本质上是不可以继承的,我们无法使用extends标识符继承自 @interface 。这里的继承指得是可以让子类通过反射使用Class对象中的getAnnotations() 获取父类被@Inherited修饰的注解
@Documented
说明该注解将被包含在javadoc中。和注释一样,注解虽然会在源码中显示,但是 javadoc 命令生成的文档默认会隐藏注解内容,如果我们想让某个注解在 javadoc 中可显示,在注解中定义即可.备注: java 的 api 文档就是用这个生成的
注解的基本使用
在 Java 中,注解的语法格式为: @+注解名,如@Override。
一般来说,注解的使用主要分为以下三类:
- 编写文档。在代码的文档注释里使用 Java 提供的注解,然后使用 javadoc 命令生成doc文档。
- 编译检查。通过代码里标识的注解能够让编译器实现编译检查,如 【Override】命令检查是否为继承重写的方法。
- 代码分析。通过代码里标识的注解对代码进行分析,处理。
在现代的主流框架中,如Spring ,大量使用了注解来简化代码,那么现在我们就来分析注解具体的一些我们应该学习的地方。
通过注解来配置数据库
创建接口,这里使用的是注解@select
在mybatis-config.xml文件里去注册,也就是告诉程序这个接口在哪
编写AnnotationMybatis
package com.noteligible.annotation;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import com.noteligible.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class AnnotationMybatis {
public static SqlSession getSqlSession() {
String resource = "src/main/resources/Mybatis-config.xml";
InputStream is = null;
try {
is = new FileInputStream(resource);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//构建sqlSession的工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
return sessionFactory.openSession();
}
public static void main(String[] args) {
SqlSession sqlSession = getSqlSession();
//得到UserMapperI接口的实现类对象,UserMapperI接口的实现类对象由sqlSession.getMapper(UserMapperI.class)动态构建出来
Mapper1 mapper1 = sqlSession.getMapper(Mapper1.class);
//建对象
User user = new User();
//调用对象
user.setId(2);
User s = mapper1.queryUserById(user.getId());
System.out.println(s);
//使用SqlSession执行完SQL之后需要关闭SqlSession
sqlSession.close();
}
}
9.给姓名建索引,思考一下还应该给哪些数据建索引 28.数据库里插入100万条数据,对比建索引和不建索引的效率查别。再插入3000万条数据,然后是2亿条,别说话,用心去感受数据库的性能。
直接上2亿条
不创建索引查询需要18.295s
创建索引之后0.042s,18.295/0.042=435.59,这差距,太大了
创建索引花了256s
之后了解一下反射,所以没做完任务
Java反射
1. 反射的出现
将类的各个组成部分封装成其他对象,这就是java的反射机制,通过反射,我们可以得到每个类的各个组成部分。
由于反射的这些优秀特性,现代的主流Web框架 Spring / MyBatis 等都使用了反射,可以说,反射是框架的灵魂。
1.1 Java代码经历的三个过程
这里可能听的还是很迷糊,反射是什么?作用在什么地方?要搞清楚这个问题,我们首先看一张图:
这描写一个代码从编译到运行的过程,Java程序编译后会生成字节码文件,也就是class文件。但这时候class文件依然在硬盘上,这是需要类加载器ClassLoader把它加载内存当中,在内存中我们可以创建一个对象来表示字节码文件, 负责存储描述字节码文件中的信息。这个对象为Class 类的对象,在Java的api中,可以找到这个类:
在被加载类的 Class 对象中,包含了这个类所有共同的类型信息。什么是共同的类型信息呢?就比如每个类的成员变量,构造方法,成员方法,类名….等等。
这里我们也要注意一个点,一个class字节码文件对应一个Class对象,也就是说,无论你创建了多少个实例对象,在JVM或者说内存中只会存在一个Class对象,其负责描述类的共同类型信息。具体对应关系看下图:
反射的思想
类在被使用前,应先被类加载器加载到内存中以Class对象的方式存在,Class 对象将类的成员变量,构造函数,成员方法封装成不同的对象。
那么我们可不可以这样想,当一个Person类的对象在使用时,由于其共有的Class 对象中将该对象的成员变量,构造函数,成员方法等封装成了对象,我们是不是可以通过操作这些封装好的对象来操控Person对象中的相关信息?
答案时肯定的,这也就是反射的实现思想,在程序的运行过程中,能够知道程序的所有属性和方法,也能够随时调用改变其中的属性和方法,这就是反射机制
使用反射的优点如下:
- 可以在程序的运行过程中去操作这些对象
- 可以解耦,提高程序的可扩展性
反射的基本使用
创建一个person类
public class Person {
private String name;
public int age;
/**
* 用作测试Filed类的使用
*/
public int height = 180;
protected String sex = "male";
public int weight = 120;
String hobby = "篮球";
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(String name) {
this.name = name;
}
public Person() {
}
public void show(){
System.out.println("你好,我是况博凯");
}
private String showNation(String nation){
System.out.println("我的国籍是:" + nation);
return nation;
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
", sex='" + sex + '\'' +
", weight=" + weight +
", hobby='" + hobby + '\'' +
'}';
}
}
创建一个 ReflectDemo1类
public class ReflectDemo1 {
/**
* 三种不同的获取Class对象的方式:
* 1、Class.forName("全类名") :将字节码文件加载进内存,返回Class对象。
* 2、类名.class:通过类名的属性class获取
* 3、对象名.getClass():利用Object类中定义的getClass()方法
*/
public static void main(String[] args) throws ClassNotFoundException {
//1.Class.forName("类名")
//注意这里的字符串是全类名,也就是包名+类名,我这直接写类名的原因是我没有定义包。
Class cla1 = Class.forName("Person");
System.out.println(cla1);
//2.类名.class
Class cla2 = Person.class;
System.out.println(cla2);
//3.对象名.getClass()
Person p = new Person();
Class cla3 = p.getClass();
System.out.println(cla3);
//判断三个对象是否相等
System.out.println(cla1 == cla2);
System.out.println(cla1 == cla3);
System.out.println(cla2 == cla3);
}
}
运行结果
这说明三个对象都是同一个对象,对于同一个类,它在依次运行的时候只会被加载一次,且只存在一个class对象。
下面还了解了一些成员变量Field对象的使用,构造方法Constructor对象的使用,成员方法Method对象的使用,对类名的获取。但是没能太理解,就不贴上了了
明天计划的事情:
回家一趟
遇到的问题:
问师兄解决了
收获:了解注解和反射,补任务一
评论