弄Spring时又遇到了它,之前留下的影响已经比较模糊,就比较系统在去弄一遍
class对象保存类型信息,反射的动态运行加载等的理论信息虽然看过一遍java编程思想,但仍有很多的不理解的地方
现在的情况结合和之前定下的基调,所以一切以实用为基本,理论理解为辅,先学会去用,再慢慢的理解理论
所有代码完成成功运行
主要的内容
1、获取class对象及类型信息
2、反射的基本实用,Method、Field和Constructor
3、简单使用反射对数据库新增保留功能的封装
1、获取class对象及类型信息,获取class对象的三种方法,获取类型信息有很多的get方法,例如getInterfaces() getSuperclass()获取接口和父类信息
//1、对象的getClass() 2、Class的静态方法forName() 3、.class方法
Class<?> c = object.getClass();
//Class<?> c1 = Class.forName("");
//Class<?> c2 = User.class;
//一、获取并操作方法
Method[] methods = c.getMethods();
Method method_1 = c.getMethod("testPrint", String.class);//方法名和参数类型
method_1.invoke(object, "TestTest");//调用这个方法,类的对象和传递的参数
//二、获取并操作属性
Field[] fields = c.getFields();
for(Field f : fields ){
System.out.println(f);
}
//get--获取的是访问权限是public,包括父类的 ; getDeclared--获取的是所有访问权限的,不包括父类
Field[] fields_2 = c.getDeclaredFields();
for(Field f : fields_2){
System.out.println(f);
}
AccessibleObject.setAccessible(fields_2, true);//设置private的课访问属性为true
for(Field f : fields_2){
if(f.getName() == "name"){
f.set(object, "ooooo");
}else if(f.getName() == "phone"){
f.set(object, "999999");
}else{
continue;
}
}
Method m2 = c.getMethod("setField");
m2.invoke(object);
for(Field f : fields_2){
System.out.println(f.get(object));//具体属性值
}
Field f1 = c.getDeclaredField("name");//根据属性名字单个获取
f1.setAccessible(true);
f1.set(object, "oooo");
Field f2 = c.getDeclaredField("phone");
f2.setAccessible(true);
f2.set(object, "123456");
Field[] fields_3 = new Field[2];
fields_3[0] = f1;
fields_3[1] = f2;
System.out.println(f1.get(object));
//三、创建类的实例
Object object_1 = c.newInstance();//创建无参构造函数实例
System.out.println(object_1.toString());
//创建有参构造函数实例
Object object_2 = c.getDeclaredConstructor(int.class,String.class,String.class).newInstance(1,"yyyy","8888");
System.out.println(object_2.toString());
String className = c.getName();
String tableName = className.substring(className.lastIndexOf(".")+1, className.length());
//看看几个的区别
System.out.println(object); //对象所属包,所属类,对象引用地址
System.out.println(c);//class对象。对象所属包,所属类
System.out.println(className);//class包名和类名
System.out.println(tableName);//取出其中的类名
for(Method method : methods){
System.out.println(method);
}
3、简单使用反射对数据库新增保留功能的封装
public void save(Object object) throws Exception{
//1、根据传过来的对象组装 插入的sql语句
//2、使用jdbc执行sql语句完成数据库操作
String sql = "INSERT INTO";
Class<?> c = object.getClass();
String className = c.getName();
//根据类名获得相应的表明
String tableName = className.substring(className.lastIndexOf(".")+1, className.length());
//如果要确实封装dao,实现save保存新增的方法,肯定不能出现具体的字段名,都是必须通过反射获得的
//如果在框架中组装sql然后执行,只是封装底层,直接使用ORM方式更加方便,使用相应的get和set方法
/*sql += " "+ tableName + " (id,name,password) VALUES (";
Method method_5 = c.getMethod("getId");
int id = (int) method_5.invoke(object);
Method method_3 = c.getMethod("getName");
String name = (String) method_3.invoke(object);
Method method_4 = c.getMethod("getPassword");
String password = (String) method_4.invoke(object);
sql += id + ",'" + name + "','" + password +"')";*/
//拼接sql有蛮多的问题,保持必要的空格和字符的引号。进过一次坑就回对这些有感觉了
//第一种有点类似于ssh框架下对sql的拼接
//第二种封装save,即直接传入参数调用save方法,拼接sql的工作交出去,实际的封装更好的表达,更兼容的数据格式,这里只是体现思想
sql += " "+ tableName + " (";
Method[] methods = c.getMethods();
//保存数据库中相应的字段名
List<String> nameList = new ArrayList<String>();
//保存相应的字段值
List<Object> valueList = new ArrayList<Object>();
for (Method method : methods) {
String methodName = method.getName();
if (methodName.startsWith("get") && !methodName.startsWith("getClass")) {
String fieldName = methodName.substring(3, methodName.length());
nameList.add(fieldName);
try {
Object value = method.invoke(object);
if (value instanceof String) {
valueList.add("'" + value + "'");
} else {
valueList.add(value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//拼接sql
for (int i = 0; i < nameList.size(); i++) {
if (i < nameList.size() - 1) {
sql += nameList.get(i) + ",";
} else {
sql += nameList.get(i) + ") values (";
}
}
for (int i = 0; i < valueList.size(); i++) {
if (i < valueList.size() - 1) {
sql += valueList.get(i) + ",";
} else {
sql += valueList.get(i) + ")";
}
}
try {
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(sql);
stmt.execute();
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.closeAll(rs, stmt, conn);
}
完整的代码
User类
package TestJDBC;
import java.sql.Date;
public class User {
private int id;
private String name;
private String password;
private String phone;
private Date birthday;
public User(int id, String name, String password, String phone, Date birthday){
this.id = id;
this.name = name;
this.password = password;
this.phone = phone;
this.birthday = birthday;
}
public User(){
}
public User(int id, String name, String password){
this.id = id;
this.name = name;
this.password = password;
}
public User(int id, String name, String password, String phone){
this.id = id;
this.name = name;
this.password = password;
this.phone = phone;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString(){
return id +" "+ name + " "+ phone + " " + password +" "+ birthday;
}
//为测试反射新建的方法
public void testPrint(String info){
System.out.println(info);
}
public void setField(){
System.out.println(name + "的电话是" +phone);
}
}
JDBC工具类JDBCUtil类
package TestJDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
//JDBC工具类, 加载驱动 建立连接 关闭资源 。方法都是static,可以直接调用
public final class JDBCUtil {
private static String DRIVER = "com.mysql.jdbc.Driver";
private static String URL = "jdbc:mysql://localhost:3306/test";
private static String USER_NAME = "admin";
private static String PASSWORD = "123456";
//注册驱动放在静态代码块中,保证只注册一次,当类装载到虚拟机中就会执行
static{
try {
Class.forName(DRIVER);
} catch (Exception e) {
e.printStackTrace();
}
}
//建立连接
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(URL, USER_NAME, PASSWORD);
}
//释放资源
public static void closeAll(ResultSet rs, Statement stmt, Connection conn){
try {
if(rs != null){
rs.close();
}
rs = null;
} catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if(stmt != null){
stmt.close();
}
stmt = null;
} catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if(conn != null){
conn.close();
}
conn = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
dao接口(习惯面向接口编程)
package ReflectTest;
public interface IDao {
public void save(Object object) throws Exception;
}
dao的实现类
package ReflectTest;
import java.lang.reflect.Method;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import TestJDBC.JDBCUtil;
import TestJDBC.User;
public class DaoForReflect implements IDao {
private static Connection conn = null;
private static PreparedStatement stmt = null;
private static ResultSet rs = null;
public void reflectTest(Object object) throws Exception{
//1、对象的getClass() 2、Class的静态方法forName() 3、.class方法
Class<?> c = object.getClass();
//Class<?> c1 = Class.forName("");
//Class<?> c2 = User.class;
//一、获取并操作方法
Method[] methods = c.getMethods();
Method method_1 = c.getMethod("testPrint", String.class);//方法名和参数类型
method_1.invoke(object, "TestTest");//调用这个方法,类的对象和传递的参数
//二、获取并操作属性
Field[] fields = c.getFields();
for(Field f : fields ){
System.out.println(f);
}
//get--获取的是访问权限是public,包括父类的 ; getDeclared--获取的是所有访问权限的,不包括父类
Field[] fields_2 = c.getDeclaredFields();
for(Field f : fields_2){
System.out.println(f);
}
AccessibleObject.setAccessible(fields_2, true);//设置private的课访问属性为true
for(Field f : fields_2){
if(f.getName() == "name"){
f.set(object, "ooooo");
}else if(f.getName() == "phone"){
f.set(object, "999999");
}else{
continue;
}
}
Method m2 = c.getMethod("setField");
m2.invoke(object);
for(Field f : fields_2){
System.out.println(f.get(object));//具体属性值
}
Field f1 = c.getDeclaredField("name");//根据属性名字单个获取
f1.setAccessible(true);
f1.set(object, "oooo");
Field f2 = c.getDeclaredField("phone");
f2.setAccessible(true);
f2.set(object, "123456");
Field[] fields_3 = new Field[2];
fields_3[0] = f1;
fields_3[1] = f2;
System.out.println(f1.get(object));
//三、创建类的实例
Object object_1 = c.newInstance();//创建无参构造函数实例
System.out.println(object_1.toString());
//创建有参构造函数实例
Object object_2 = c.getDeclaredConstructor(int.class,String.class,String.class).newInstance(1,"yyyy","8888");
System.out.println(object_2.toString());
String className = c.getName();
String tableName = className.substring(className.lastIndexOf(".")+1, className.length());
//看看几个的区别
System.out.println(object); //对象所属包,所属类,对象引用地址
System.out.println(c);//class对象。对象所属包,所属类
System.out.println(className);//class包名和类名
System.out.println(tableName);//取出其中的类名
for(Method method : methods){
System.out.println(method);
}
}
public void save(Object object) throws Exception{
//1、根据传过来的对象组装 插入的sql语句
//2、使用jdbc执行sql语句完成数据库操作
String sql = "INSERT INTO";
Class<?> c = object.getClass();
String className = c.getName();
//根据类名获得相应的表明
String tableName = className.substring(className.lastIndexOf(".")+1, className.length());
//如果要确实封装dao,实现save保存新增的方法,肯定不能出现具体的字段名,都是必须通过反射获得的
//如果在框架中组装sql然后执行,只是封装底层,直接使用ORM方式更加方便,使用相应的get和set方法
/*sql += " "+ tableName + " (id,name,password) VALUES (";
Method method_5 = c.getMethod("getId");
int id = (int) method_5.invoke(object);
Method method_3 = c.getMethod("getName");
String name = (String) method_3.invoke(object);
Method method_4 = c.getMethod("getPassword");
String password = (String) method_4.invoke(object);
sql += id + ",'" + name + "','" + password +"')";*/
//拼接sql有蛮多的问题,保持必要的空格和字符的引号。进过一次坑就回对这些有感觉了
//第一种有点类似于ssh框架下对sql的拼接
//第二种封装save,即直接传入参数调用save方法,拼接sql的工作交出去,实际的封装更好的表达,更兼容的数据格式,这里只是体现思想
sql += " "+ tableName + " (";
Method[] methods = c.getMethods();
//保存数据库中相应的字段名
List<String> nameList = new ArrayList<String>();
//保存相应的字段值
List<Object> valueList = new ArrayList<Object>();
for (Method method : methods) {
String methodName = method.getName();
if (methodName.startsWith("get") && !methodName.startsWith("getClass")) {
String fieldName = methodName.substring(3, methodName.length());
nameList.add(fieldName);
try {
Object value = method.invoke(object);
if (value instanceof String) {
valueList.add("'" + value + "'");
} else {
valueList.add(value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//拼接sql
for (int i = 0; i < nameList.size(); i++) {
if (i < nameList.size() - 1) {
sql += nameList.get(i) + ",";
} else {
sql += nameList.get(i) + ") values (";
}
}
for (int i = 0; i < valueList.size(); i++) {
if (i < valueList.size() - 1) {
sql += valueList.get(i) + ",";
} else {
sql += valueList.get(i) + ")";
}
}
try {
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(sql);
stmt.execute();
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.closeAll(rs, stmt, conn);
}
}
}
main类
package ReflectTest;
import TestJDBC.User;
//动态
public class Reflect {
public static void main(String[] args) throws Exception {
User user = new User(17,"yl","yll");
DaoForReflect dao = new DaoForReflect();
dao.save(user);
}
}
----------------------------------------------------------------OVER--------------------------------------------------------------------------