[TOC]
# 反射
> 是Java高级中必须掌握的技术
## Class类型
当我们执行一个Java的源文件时,会把该源文件翻译成字节码文件(class),再由JVM里的解释器进行解释执行.在解释的时候需要通过类加载(ClassLoader)把上面的class文件加载到内存中.
在这个class运行的过程中,它的所有信息(有哪些字段,有哪些方法.类名等)我们把它们叫做RTTI(Run-Time Type Identification 运行时类型信息).这些信息被封装在一个Class对象中.
## Class的获取方式
常用的有三种获取方式
```java
/**
*
*/
package com.hwua.demo;
/**
* @ClassName: Demo01
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 上午9:21:37
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class Demo01 {
public static void main(String[] args) {
try {
// -- 第一种方式
Class<?> clz1 = Class.forName("java.util.Scanner");
Demo01 d = new Demo01();
// -- 第二种方式 对象.getClass();
Class<? extends Demo01> clz2 = d.getClass();
// -- 第三种方式 类名.class
Class clz3 = Demo01.class;
} catch (ClassNotFoundException e) {
// -- 过程中会产生类找不到异常
e.printStackTrace();
}
}
}
```
## 通过Class对象获取运行时类型信息
### 获取对象
在Java中用于创建对象的方式有5种
* 使用new + 构造方法创建
* 使用反射创建(有两套写法)
* 使用反序列化
* 使用克隆创建
```java
/**
*
*/
package com.hwua.demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Scanner;
/**
* @ClassName: Demo02
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 上午9:27:27
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class Demo02 {
public static void main(String[] args) {
try {
// -- 加载java.util.Scanner到内存.
Class<?> clz = Class.forName("com.hwua.demo.Student");
// -- 通过Class对象来构造Student的对象.是利用无参构造方法.如果没有无参会报错!
// -- 利用构造方法对象构造对象
Object obj = clz.newInstance();
// -- 判断obj对象的真实类型是否是Scanner类型
if (obj instanceof Student) {
Student stu = (Student) obj;
stu.setSage(18);
stu.setSid(1);
stu.setSname("张三");
System.out.println(stu);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
```
### 获取字段
#### 调用字段的Set方法
```JAVA
/**
*
*/
package com.hwua.demo02;
import java.lang.reflect.Field;
/**
* @ClassName: Demo01
* @Description: 测试获取字段和调用字段的set方法
* @author: Administrator
* @date: 2019年4月19日 上午10:49:16
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class Demo01 {
public static void main(String[] args) {
// -- 1.获取Class对象
Class<?> clz = Dog.class;
// -- 2.通过Class对象获取所有的字段信息
/*
* Field 成员变量 字段 Local Variable 局部变量 Param 方法参数 Constant 常量 getFields()
* 获取的是都是非私有的字段
*/
// Field[] fields = clz.getFields();
// -- 可以获取私有的字段
Field[] fields = clz.getDeclaredFields();
Dog dog = null;
try {
dog = (Dog) clz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// -- 3.遍历数组
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
// -- 私有的设置可见.不然无法访问
f.setAccessible(true);
if (f.getName().equalsIgnoreCase("age")) {
try {
f.set(dog, 18);
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (f.getName().equalsIgnoreCase("name")) {
try {
f.set(dog, "旺财");
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (f.getName().equalsIgnoreCase("color")) {
try {
f.set(dog, "七彩斑斓");
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
System.out.println(dog);
}
}
```
# 工厂设计模式
## 工厂设计模式的作用
简单说就是帮我们创建对象.
## 为什么使用工厂
解耦合.我们所期望的软件是高内聚低耦合的.一个应用由N个模块组成.这N个模块的关联程度尽量降低.最好做到中间某个模块的移除,其它模块不受影响.热插拔.
假设有类A和类B.
```java
class A{
B b;
A(){
b = new B();
}
}
class B{}
```
如上所示,A的实例化是依赖B的实例化.如果B的对象构建失败A的构造方法结束执行.所以A的对象也没有创建成功!所以A是依赖于B的.
现在我们需要改变A和B的依赖关系.把B的创建交给工厂.A只需要接收工厂返回的对象就可以了.
这样就降低了A和B之间的依赖关系.
## 工厂的实现
> 简单工厂/静态工厂
### Switch Case的写法
```java
/**
*
*/
package com.hwua.demo02;
/**
* @ClassName: Animal
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 上午9:52:05
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class Animal {
public void method() {
System.out.println("This is animal");
}
}
/**
*
*/
package com.hwua.demo02;
/**
* @ClassName: Dog
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 上午9:52:09
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class Dog extends Animal {
/**
* <p>
* Title: method
* </p>
* <p>
* Description:
* </p>
*
* @see com.hwua.demo02.Animal#method()
*/
@Override
public void method() {
System.out.println("This is dog");
}
}
/**
*
*/
package com.hwua.demo02;
/**
* @ClassName: Cat
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 上午9:52:13
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class Cat extends Animal {
/**
* <p>
* Title: method
* </p>
* <p>
* Description:
* </p>
*
* @see com.hwua.demo02.Animal#method()
*/
@Override
public void method() {
System.out.println("This is cat");
}
}
/**
*
*/
package com.hwua.demo02;
/**
* @ClassName: Rabbit
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 上午9:52:17
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class Rabbit extends Animal {
/**
* <p>
* Title: method
* </p>
* <p>
* Description:
* </p>
*
* @see com.hwua.demo02.Animal#method()
*/
@Override
public void method() {
System.out.println("This is rabbit");
}
}
/**
*
*/
package com.hwua.demo02;
/**
* @ClassName: AnimalFactory
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 上午9:52:26
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class AnimalFactory {
public static Animal getAnimal(String str) {
Animal ai = null;
switch (str) {
case "animal":
ai = new Animal();
break;
case "dog":
System.out.println(1);
ai = new Dog();
break;
case "cat":
ai = new Cat();
break;
case "rabbit":
ai = new Rabbit();
break;
default:
ai = new Animal();
break;
}
return ai;
}
}
/**
*
*/
package com.hwua.demo02;
/**
* @ClassName: FactoryTest
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 上午9:55:40
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class FactoryTest {
public static void main(String[] args) {
Animal dog = AnimalFactory.getAnimal("rabbit");
dog.method();
}
}
```
### 反射的写法
#### SwitchCase写法的弊端
能够创建的对象一般都是存在继承关系的.并且由字符串来决定.不够方便和灵活
#### 反射+工厂
```java
/**
*
*/
package com.hwua.demo02;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* @ClassName: AnimalFactory
* @Description: 利用反射来实现实现工厂
* @author: Administrator
* @date: 2019年4月19日 上午9:52:26
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class AnimalFactory2 {
/**
* f
* @Title: getAnimal
* @Description: 利用传入的Class信息构建对象
* @param: clz
* @return: Object
* @throws
*/
public static Object getInstance(Class<?> clz) {
Object obj = null;
try {
//-- newIntance 本质:调用类中的无参构造
obj = clz.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}
/**
*
* @Title: getInstance
* @Description: 根据类型信息和参数来构建对象.
* @param: str 所要创建的对象的完整路径 包名.类名
* @param: parasm 构造方法的参数
* @return: Object 所构建的对象
* @throws
*/
public static Object getInstance(String str,Object... parasm) {
Object obj = null;
try {
Class<?> clz = Class.forName(str);
//-- 利用clz获取构造方法
Constructor<?> cons = clz.getConstructor(String.class);
obj = cons.newInstance(parasm[0]);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}
}
```
# 接口回调
## 回调概念
在开发中.方法的执行流程有三个方向
* 同步
> 方法A->方法B
* 异步
> 方法A<-方法B
* 回调
> 方法A->方法B->方法A
举一个很简单的例子.比如Boss安排员工办事,在员工执行完成后要告诉Boss工作完成了.
## 回调的代码实现
```java
/**
*
*/
package com.hwua.demo03;
/**
* @ClassName: CallBoss
* @Description: 联系Boss的行为接口
* @author: Administrator
* @date: 2019年4月19日 下午1:39:46
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public interface CallBoss {
void callBoss();
}
/**
*
*/
package com.hwua.demo03;
/**
* @ClassName: Boss
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 下午1:36:03
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class Boss implements CallBoss {
/**
*
* @Title: orderEmployeeDo @Description: 老板安排员工干活! @param: e 要干活的员工 @return:
* void @throws
*/
public void orderEmployeeDo(Employee e) {
System.out.println("Boss 下派任务");
e.doSomething();
}
/**
* <p>
* Title: callBoss
* </p>
* <p>
* Description:
* </p>
*
* @see com.hwua.demo03.CallBoss#callBoss()
*/
@Override
public void callBoss() {
System.out.println("Boss 说我知道了!");
}
}
/**
*
*/
package com.hwua.demo03;
/**
* @ClassName: Employee
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 下午1:36:14
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class Employee {
/**
* 提供成员变量. 类型是接口类型. 给员工提供联系老板的方式
*/
private CallBoss cb;
/**
* @Title: setCb <BR>
* @Description: please write your description <BR>
* @return: CallBoss <BR>
*/
public void setCb(CallBoss cb) {
this.cb = cb;
}
/**
* @Title: doSomething @Description: 员工干活 @param: @return: void @throws
*/
public void doSomething() {
for (int i = 0; i < 10; i++) {
System.out.println("员工干活中!..");
}
// -- 通知老板活干完了
cb.callBoss();
}
}
/**
*
*/
package com.hwua.demo03;
/**
* @ClassName: Test
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 下午1:38:34
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class Test {
public static void main(String[] args) {
Boss b = new Boss();
Employee e = new Employee();
e.setCb(b);
b.orderEmployeeDo(e);
}
}
```
## 修改Dao类通过回调来实现对象的封装
我们在Dao中需要对数据库做操作.当我们执行查询的语句时,会发现都需要写一段类似的代码
```java
while(rSet.next()){
对象.set(rSet.getString("字段名"));
}
```
当一个Dao中有10个查询方法时,上面的这段代码需要写10遍,如果有10实体类.那要写100遍.
这样会造成大量的代码重复.想要简化这一块的代码所以使用回调函数来修改Dao
```java
/**
*
*/
package com.hwua.demo04;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* @ClassName: ResultSetHandler
* @Description:定义回调接口用于处理结果集
* @author: Administrator
* @date: 2019年4月19日 下午1:50:36
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public interface ResultSetHandler<T> {
public List<T> handler(ResultSet rSet) throws SQLException;
}
```
在Dao的实现类上.我们去实现这个回调接口,并实现处理结果集的方法.
```java
/**
*
*/
package com.hwua.demo04;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName: StuDaoImpl
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 下午1:50:19
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class StuDaoImpl implements ResultSetHandler<Stu> {
/**
* <p>
* Title: handler
* </p>
* <p>
* Description:
* </p>
*
* @param rSet
* @return
* @throws SQLException
* @see com.hwua.demo04.ResultSetHandler#handler(java.sql.ResultSet)
*/
@Override
public List<Stu> handler(ResultSet rSet) throws SQLException {
List<Stu> stuList = new ArrayList<Stu>();
while (rSet.next()) {
Stu stu = new Stu();
stu.setSage(rSet.getInt("sage"));
stu.setSname(rSet.getString("sname"));
stu.setSgender(rSet.getString("sgender"));
stu.setSid(rSet.getString("sid"));
stuList.add(stu);
}
return stuList;
}
}
```
再提供查询数据的方法.
```java
public List<Stu> listStus() throws ClassNotFoundException, SQLException {
// -- 1.获取数据库连接
Connection conn = DbTools.getConnection();
// -- 2.提供SQL语句
String sql = "select * from stu";
// -- 3.通过连接获取PreparedStatement对象
PreparedStatement statement = conn.prepareStatement(sql);
// -- 4.替换占位符
// -- 5.执行SQL语句得到结果集 .结果集是永远不会为null的.
ResultSet rSet = statement.executeQuery();
// -- 6.遍历结果集 .
List<Stu> stuList = handler(rSet);
// -- 7.关闭结果集,关闭PreparedStatement
// -- 切记:关闭的顺序和开启的顺序正好相反!
if (!rSet.isClosed()) {
rSet.close();
}
if (statement != null || !statement.isClosed()) {
statement.close();
}
return stuList;
}
```
# JDBC Template
在Dao的方法中可以发现增删改的基本流程是一致的.查询的流程是独立的.我们可以封装工具类来作为模板类
## 查询的模板方法
```java
//-- 1.提供回调接口
/**
*
*/
package com.hwua.demo04;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* @ClassName: ResultSetHandler
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 下午1:50:36
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public interface ResultSetHandler<T> {
public List<T> handler(ResultSet rSet) throws SQLException;
}
//-- 2.提供Dao实现类
/**
*
*/
package com.hwua.demo04;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName: StuDaoImpl
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: Administrator
* @date: 2019年4月19日 下午1:50:19
*
* @Copyright: 2019 www.hwua.com Inc. All rights reserved.
*
*/
public class StuDaoImpl implements ResultSetHandler<Stu> {
/**
* <p>
* Title: handler
* </p>
* <p>
* Description:
* </p>
*
* @param rSet
* @return
* @throws SQLException
* @see com.hwua.demo04.ResultSetHandler#handler(java.sql.ResultSet)
*/
@Override
public List<Stu> handler(ResultSet rSet) throws SQLException {
List<Stu> stuList = new ArrayList<Stu>();
while (rSet.next()) {
Stu stu = new Stu();
stu.setSage(rSet.getInt("sage"));
stu.setSname(rSet.getString("sname"));
stu.setSgender(rSet.getString("sgender"));
stu.setSid(rSet.getString("sid"));
stuList.add(stu);
}
return stuList;
}
/**
*
* @Title: findStu 通用的查询方法
* @Description: 根据条件查找学生
* @param: sql 要执行的sql语句
* @param: params sql语句中的条件.
* @return: Stu 所查找到的学生对象或者null
* @throws SQLException
* @throws ClassNotFoundException
*/
public List<Stu> findStu(String sql, Object... params) throws ClassNotFoundException, SQLException {
// -- 1.拿连接
Connection conn = DbTools.getConnection();
// -- 2.预处理
PreparedStatement statement = conn.prepareStatement(sql);
// -- 3.先获取参数的元数据对象.
ParameterMetaData metaData = statement.getParameterMetaData();
// -- 4.通过元数据对象获取参数的数量
int parameterCount = metaData.getParameterCount();
// -- 5.循环遍历
for (int i = 0; i < parameterCount; i++) {
// -- 6.替换占位符 占位符的下标从1开始
statement.setObject(i + 1, params[i]);
}
// -- 7.执行sql语句
ResultSet set = statement.executeQuery();
// -- 8.通过回调处理结果集
List<Stu> stuList = handler(set);
// -- 9.返回结果集
return stuList;
}
}
```
## 增删改的模板方法
```java
public int updateStu(String sql, Object... params) throws ClassNotFoundException, SQLException {
// -- 1.拿连接
Connection conn = DbTools.getConnection();
// -- 2.预处理
PreparedStatement statement = conn.prepareStatement(sql);
// -- 3.先获取参数的元数据对象.
ParameterMetaData metaData = statement.getParameterMetaData();
// -- 4.通过元数据对象获取参数的数量
int parameterCount = metaData.getParameterCount();
// -- 5.循环遍历
for (int i = 0; i < parameterCount; i++) {
// -- 6.替换占位符 占位符的下标从1开始
statement.setObject(i + 1, params[i]);
}
// -- 7.执行sql语句
int columns = statement.executeUpdate();
return columns;
}
```