反射
Class对象: Class类我们可以创建该类的实例(对象)
可以获取该对象的所有属性信息(修饰符、属性名等)、所有方法信息(修饰符、返回值类型、
参数列表等) 一个.class 文件 只有一个 Class对象
获取Class 对象有3种方式
1. Class.fromName(“xxxx”) 通过包名获取
2 .类名.class 获取
3. 通过对象.getClass()来获取
// 加载.class 文件后
// 字符串 是全路径 (包名 + 类名)
Class<Emp> clazz = (Class<Emp>) Class.forName("cn.szsxt.demo01.Emp");
// 方式2
Class<Emp> clazz1 = Emp.class;
// 通过对象来获取 Clazz 对象
Emp emp = new Emp();
// 泛型的 (范围)上限
Class<Emp> clazz2 = (Class<Emp>) emp.getClass();
构造器
可以通过 class对象来获取属性 方法构造器
通过class获取构造器
// 获取class对象
Class<Emp> clazz = (Class<Emp>) Class.forName("cn.szsxt.demo01.Emp");
// 通过构造器 可以和创建对象
// 参数类型要给class类型
// int类型 不要给成 Integer.class 给 int.class
Constructor<Emp> c = clazz.getConstructor(int.class,String.class);
// 通过构造器创建对象
Emp emp = c.newInstance(1,"虚竹");
System.out.println(emp);
//获无参构造器
Constructor<Emp> c1 = clazz.getConstructor(null);
Emp emp2 = c1.newInstance(null);
//直接用 Class 对象 创建emp对象
Emp emp3 = clazz.newInstance(); // 内部是调用了 构造器创建对象
System.out.println(emp3.hashCode());
// 可以通过Class 对象 获取 构造器 对象
// Constructor 这个对象 封装构造器的信息
//获取所有的构造器
Constructor<Emp>[] cs = (Constructor<Emp>[]) clazz.getConstructors();
//遍历构造器
for (Constructor<Emp> c : cs) {
System.out.println(c);
// getName() 构造器的名字
// getParameterCount 构造器的参数个数
// getModifiers 构造器的修饰符 1 是 public 2 private 4 protected ...
System.out.println(c.getName() +""
+ "\t" +c.getParameterCount() + "\t"+c.getModifiers());
}
System.out.println("获取指定的构造器 ......");
// 获取值指定的构造器
Constructor<Emp> c2 = clazz.getConstructor(null);
System.out.println(c2);
System.out.println(c2.getParameterCount());
属性
通过 class 对象操作属性
// 获取class对象
Class<Emp> clazz = (Class<Emp>) Class.forName("cn.szsxt.demo01.Emp");
// 先拿到属性
// Field 封装属性的类
// test01(clazz);
//拿到属性操作属性
Field f = clazz.getDeclaredField("name");
writeGetMethode(f);
Emp emp = clazz.newInstance();
/**
* obj 属性是哪个对象的属性
* value 是属性的值
*/
// 设置 private 的安全检查 跳过
f.setAccessible(true);
f.set(emp, "程灵素");
/**
* 通过属性 拿到set方法
* @param f
*/
private static void writeGetMethode(Field f) {
StringBuffer sb = new StringBuffer();
//拿到属性的名字
String name = f.getName();
//拿到类型
String fType = f.getType().getName();
// 修饰符的拼接
sb.append("public ").append(fType).append(" ");
//get方法的拼接
sb.append("get").append( name.substring(0, 1).toUpperCase().concat(name.substring(1)));
// () 和 换行的拼接
sb.append("(").append("){\r\n");
// return 的拼接
sb.append("\treturn ").append(name).append(";\r\n");
sb.append("}");
System.out.println(sb.toString());
}
/**
* 通过 class对象拿到属性
* @param clazz
* @throws NoSuchFieldException
*/
private static void test01(Class<Emp> clazz) throws NoSuchFieldException {
// 获取所有的 公开属性
Field[] fs1 = clazz.getFields();
// 获取所有的属性 (private + public)
Field[] fs2 = clazz.getDeclaredFields();
for (Field f : fs2) {
// getName() 获取属性名称
// getModifiers() 属性修饰符
// getType 属性 的类型
System.out.println(f.getName() + "\t" + f.getModifiers() + "\t" + f.getType());
}
//拿到指定的属性
Field f = clazz.getDeclaredField("name");
System.out.println(f.getName());
}
方法
通过class 拿到 方法进行操作
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 获取class对象
Class<Emp> clazz = (Class<Emp>) Class.forName("cn.szsxt.demo01.Emp");
// test012(clazz);
// obj 是哪个对象
Emp emp = clazz.newInstance();
//操作方法
Method m = clazz.getDeclaredMethod("setName", String.class);
/**
* invoke 执行方法
* obj 方法的对象
* value 方法的参数
*/
m.invoke(emp, "张无忌");
System.out.println(emp);
}
/**
* 通过反射拿到 所有的 方法
* @param clazz
* @throws NoSuchMethodException
*/
private static void test012(Class<Emp> clazz) throws NoSuchMethodException {
//拿到所有的方法
// Method 封装方法的类 (方法描述的类)
Method[] ms = clazz.getDeclaredMethods();
//遍历所有的方法
for (Method m : ms) {
// getName 获取方法的名字
// getModifiers 获取方法的修饰符
// getParameterCount 获取方法的参数的个数
System.out.println(m.getName() + "\t" + m.getModifiers() + "\t" + m.getParameterCount());
// 获取方法返回类型
System.out.println(m.getReturnType());
System.out.println("$$$$$$$$$$");
}
// 获取指定的方法
Method m = clazz.getDeclaredMethod("setName", String.class);
System.out.println(m.getName());
}
通过反射 把一个map转成对象
public class Demo06 {
public static void main(String[] args) throws Exception {
Map<String,String> map = new HashMap<>();
map.put("id", "1");
map.put("name", "赵敏");
Emp emp = new Emp();
Class<Emp> clazz = (Class<Emp>) emp.getClass();
Emp e = mapToBean(map,clazz);
System.out.println(e);
}
/**
* 通过反射 把map的值赋值给对象
* @param map
* @param class1
* @return
*/
private static Emp mapToBean(Map<String, String> map, Class<Emp> clazz) throws Exception{
//创建对象
Emp emp = clazz.newInstance();
// 拿到属性
Field[] fs = clazz.getDeclaredFields();
for (Field f : fs) {
//拿到所有属性名称
String key = f.getName();
//通过属性名称 获取map中的value值
String value = map.get(key);
// 把value 赋值到 对象中
// 跳过 private安全检查
f.setAccessible(true);
//判断数据类型
if (f.getType() == int.class) {
// 把字符串转成int
int id = Integer.valueOf(value);
f.set(emp, id);
}
if (f.getType() == String.class) {
//直接操作
f.set(emp, value);
}
}
return emp;
}
}
注解
注解的作用:
1 标记
2. 编译检查
3. 反射中使用
@Override:
表示一个方法声明打算重写超类中的另一个方法声明。
如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。
标记这个方法是 父类的方法
// 标记这个方法 过时了 不推荐使用
// Date
@Deprecated
// 告诉编译器 不要警告我这个方法
@SuppressWarnings(“all”)
public void demo03() {
List list = new ArrayList();
}
通过反射 操作注解
public class Demo03 {
public static void main(String[] args) throws Exception {
// 拿到class对象
Person p = new Person();
Class<Person> clazz = (Class<Person>) p.getClass();
// 通过class 拿到所有的属性
Field[] fs = clazz.getDeclaredFields();
for (Field f : fs) {
// 拿到所有的属性对象
// 判断属性是否有MyAnnotion 注解
// 判断是否有注解方法的 api
// Method m;
// m.isAnnotationPresent(annotationClass)
// m.getAnnotation(annotationClass)
// 类判断是否有注解
// clazz.isAnnotationPresent(annotationClass)
// clazz.getAnnotation(annotationClass)
if (f.isAnnotationPresent(MyAnnotion.class)) {
// 拿到 属性上的注解对象
MyAnnotion anno = f.getAnnotation(MyAnnotion.class);
// 通过注解的属性拿到值
String value = anno.value();
f.setAccessible(true);
// 通过反射给属性赋值
f.set(p, value);
}
}
System.out.println(p);
}
}
Junit
测试类型
1.添加测试环境
-
add Junit jar 一般的开发工具都继承了 junit 直接添加就可以
-
方式1 手动添加
-
方式2 添加 junit 注解 报错提示让我 添加依赖的jar 包
public class Demo01Test {
//添加注解后 选中方法 Run as JunitTest
// 测试方法 要是 public 不能是 private static
@Test
public void demo01() {
// Error 测试 异常 error
// Failures
// 进度条 如果是绿色 通过(测试成功)
System.out.println("hello JUnit ");
// int a= 10/0;
}
@Test
public void demo02() {
Demo01 demo01 = new Demo01();
int add = demo01.add(2, 3);
System.out.println(add);
// 断言测试
// Failures 失败 (预期结果 和实际结果不一致 )
assertEquals(4, add);
}
// @before 测试 方法之前执行的方法 可以在初始方法中初始一些数据
// @After 在测试方法执行之后的方法 (释放资源)
@Before
public void init() {
System.out.println("测试 方法之前执行的方法 ");
}
@After
public void after() {
System.out.println("释放资源");
}
}
jdbc
连接 数据库
- 加载驱动
- 获取连接 (DriverManagaer )
public static void main(String[] args){
// 通过 Class.for(); 加载驱动 (jvm帮我们实现的)
try {
// 加载数据库的驱动类
Class.forName("oracle.jdbc.OracleDriver");
//获取连接
// DriverManager 管理一组 JDBC 驱动程序的基本服务
// jdbc:oracle:thin:@localhost:1521:orcl
// jdbc:oracle:thin 数据库协议
// @localhost:1521 + ip端口
// orcl 数据库的名字
// 与特定数据库的连接(会话)
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger");
System.out.println(conn);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
- 通过conn 拿到 statment (给数据库发送sql指令)
createStatement()
Statement st=conn.createStatement();
返回数据库中 响应的行数
int update =st.executeUpdate(sql) 执行sql的更新 (删除 修改 插入 )
ResultSet 数据库结果集的数据表
rs = st.executeQuery(sql); // 执行sql 查询语句
rs 可以使用列的索引编号或列的名称获取值
getInt 通过 列名的索引获取int值
if (rs.next()) { //获取下一行数据
//
// }
多行数据 可以 使用while循环
将光标从当前位置向前移一行 判断 下一行是否有数据
批处理
String insert1 = "insert into t_stu(id,name,info) values (4,'黄蓉','帮主')";
String insert2 = "insert into t_stu(id,name,info) values (5,'任盈盈','小姐')";
st.addBatch(insert1); // 添加批处理
st.addBatch(insert2);
int[] executeBatch = st.executeBatch(); // 执行批处理
statement 这个接口 容易出现sql的注入 (开发中不要使用这个 接口)
-
statement 有一个子接口 ps (PreparedStatement)
因为sql语句是用String拼接的,那么就可以在条件中 追加一个类似 OR 1=1 这种条件,
让整个判断 和一个结果为true的逻辑 进行 OR运算。
使得结果为true。这就是所谓的SQL注入。
ps的测试 : PreparedStatement优点 PreperedStatement可以避免SQL注入的问题;
PreparedStatement 可对SQL进行预编译,从而提高数据库的执行效率;
PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化
使用ps容易出错的地方:
-
1. ps设置 参数下标容易出错
-
2. ps设置参数 类型和 sql中的参数类型不一致
-
3. int executeUpdate(String sql) 和 executeUpdate() 带参数的是 st的方法 (sql字符拼接 执行时候 需要sql) 不带参数的是ps方法
-
(会提前预编译sql 不要在个sql)
rsmd 可以 获取 rs中的 列的信息
ResultSetMetaData rsmd = rs.getMetaData();
数据库连接池
public class Demo01 {
@Test
public void demo01() {
// 创建 c3p0 连接池对象
ComboPooledDataSource dataSource = new ComboPooledDataSource("oracle");
// 从 连接池中获取连接
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(conn);
}
}
事物
开启事务
conn.setAutoCommit(false);
提交事务
conn.commit();
事务回滚
conn.rollback();
// 创建 c3p0 连接池对象
static ComboPooledDataSource dataSource = new ComboPooledDataSource("oracle");
//创建一个 ThreadLocal
static ThreadLocal<Connection> th = new ThreadLocal<Connection>();
public static Connection getConn() {
// 从 连接池中获取连接
// 先 从 th 中获取 如果为空 在重连接池中拿
Connection conn = th.get();
if (conn == null) {
try {
//把 获取的conn 存到 ThreadLocal 中 存在这里 保存 统一线程中 使用统一conn
// ThreadLocal 内部有个map
// 通过当前的 线程 作为 key value 是存的内容
// 统一线程 key一致 value值 肯定一致
conn = dataSource.getConnection();
//把 conn存到th中
th.set(conn);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return conn;
}
xml的dom4j解析
public class Demo01 {
@Test
public void demo01() throws DocumentException {
// 拿到解析器
SAXReader saxReader = new SAXReader();
// 加载 xml 文件 拿到 doc 文档对象
Document doc = saxReader.read(new File("src/stus.xml"));
// doc 对象拿到 root节点
Element rootEle = doc.getRootElement();
// 获取 root 节点下面的 子节点 elements() 获取所有的root节点下面的子节点
List<Element> eles = rootEle.elements();
for (int i = 0; i < eles.size(); i++) {
Element ele = eles.get(i);
// 拿到节点的名字
// System.out.println(ele.getName());
// 拿到 stu节点的下面的 id 节点
Element idEle = ele.element("id");
// 拿到id 节点的 文本
String id = idEle.getText();
System.out.println(id);
// 拿到 stu 下面的name节点
Element nameEle = ele.element("name");
// 拿到id 节点的 文本
String name = nameEle.getText();
System.out.println(name);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<stus>
<stu>
<id>1</id>
<name>雷军</name>
<age>45</age>
</stu>
<stu>
<id>2</id>
<name>马云</name>
<age>52</age>
</stu>
</stus>