首页
Web开发
Windows程序
编程语言
数据库
移动开发
系统相关
微信
其他好文
会员
首页
>
编程语言
> 详细
使用JAVA反射的利与弊
时间:
2015-04-16 17:58:48
阅读:
187
评论:
0
收藏:
0
[点我收藏+]
标签:
在Java的20周年的纪念日的日子里,让我们来重新温习下Java里面的高级知识,Java肯定希望大家了解她,要不然你跟她天天相濡以沫了这么长时间,让她知道你竟然不了解她,不在乎她,那么她该有多伤心呢,所以我们不应该做一个负心汉,更不应该做一个忘恩负义的人,她教会了你生存的技能,所以我们也应该将她发扬光大!
Java的核心技能有如下几项:
(1)JVM的调优
(2)类加载器
(3)反射
(4)动态编译
(5)动态代理
(6)注解
(7)多线程
(8)IO,NIO,Socket,Channel等网络编程
除了JAVA的基础,面向对象的思想外,这些既是java里面核心技术,也是面试时候,面试官经常爱问的几个知识,了解,熟悉和掌握他们的重要性不言而喻,今天就先来谈谈反射。
反射给java提供了,运行时获取一个类实例的可能,这一点非常灵活,你仅仅传一个类的全包名路径,就能通过反射,来获取对应的类实例,我们一般会用Class类,来调用这个被反射的Objcet类下的,构造方法,属性,或方法等,反射在一些开源框架里用的非常之多,Spring,Struts,Hibnerate,MyBatics都有它的影子,反射虽然很灵活,能够使得写的代码,变的大幅精简,所以在用的时候,一定要注意具体的应用场景,反射的优缺点如下:
优点:
(1)能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
(2)与Java动态编译相结合,可以实现无比强大的功能
缺点:
(1)使用反射的性能较低
(2)使用反射相对来说不安全
(3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性
任何事物,都有两面性,反射的优点,也同是就是它的缺点,所以,没有好与坏,只有最合适的场景,一阴一阳,才是天道平衡的条件。
下面来看个,使用java反射,来自动封装数据库对应的表的例子,初学java的人都会给每个实体类建立一个Dao对象,来专门操作这个对象对应的表,这样做没错,很好,是分层,分工明确的一个表现,但是如果有几十个实体类,那么这种重复增删改查的工作,就会大大增加,散仙初入门的时候也有如此的感受,虽然我们可以通过,抽象类和接口,使用适配器的设计模式来简化重复的代码,但是不可避免的就是类的臃肿了,下面看看如何使用反射来搞定这么多实体类的重复的增删改查的代码:
使用前提:
(1)每一个实体类都会对应一个数据库表
(2)每个表的列,与对应的实体类的属性名是一样的
(3)实体类要提供基本的get或set方法
实体类如下:
Java代码
package
com.qin.model;
public
class
Dog {
private
int
id;
private
String name;
private
String type;
private
String color;
private
int
weight;
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 getType() {
return
type;
}
public
void
setType(String type) {
this
.type = type;
}
public
String getColor() {
return
color;
}
public
void
setColor(String color) {
this
.color = color;
}
public
int
getWeight() {
return
weight;
}
public
void
setWeight(
int
weight) {
this
.weight = weight;
}
public
Dog() {
// TODO Auto-generated constructor stub
}
public
Dog(
int
id, String name, String type, String color,
int
weight) {
super
();
this
.id = id;
this
.name = name;
this
.type = type;
this
.color = color;
this
.weight = weight;
}
@Override
public
String toString() {
return
"Dog [id="
+ id +
", name="
+ name +
", type="
+ type +
", color="
+ color +
", weight="
+ weight +
"]"
;
}
}
Java代码
package
com.qin.model;
public
class
Person {
private
int
id;
private
String name;
private
int
age;
private
String address;
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
int
getAge() {
return
age;
}
public
void
setAge(
int
age) {
this
.age = age;
}
public
String getAddress() {
return
address;
}
public
void
setAddress(String address) {
this
.address = address;
}
public
Person() {
// TODO Auto-generated constructor stub
}
public
Person(
int
id, String name,
int
age, String address) {
super
();
this
.id = id;
this
.name = name;
this
.age = age;
this
.address = address;
}
@Override
public
String toString() {
return
"Person [id="
+ id +
", name="
+ name +
", age="
+ age
+
", address="
+ address +
"]"
;
}
}
Java代码
package
com.qin.db;
import
java.sql.Connection;
import
java.sql.DriverManager;
import
java.sql.PreparedStatement;
import
java.sql.ResultSet;
/**
* 数据库连接的
* 测试类
* @author qindongliang
*
*
* **/
public
class
ConnectionFactory {
public
static
Connection getCon()
throws
Exception{
Class.forName(
"com.mysql.jdbc.Driver"
);
//加上字符串编码指定,防止乱码
Connection connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/rate?characterEncoding=utf8"
,
"root"
,
"qin"
);
return
connection;
}
public
static
void
main(String[] args)
throws
Exception {
Class.forName(
"com.mysql.jdbc.Driver"
);
Connection connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/rate"
,
"root"
,
"qin"
);
System.out.println(connection);
connection.close();
}
}
Java代码
package
com.qin.commons;
import
java.lang.reflect.Field;
import
java.lang.reflect.Method;
import
java.sql.Connection;
import
java.sql.PreparedStatement;
import
java.sql.ResultSet;
import
java.util.ArrayList;
import
java.util.List;
import
com.qin.db.ConnectionFactory;
import
com.qin.model.Dog;
import
com.qin.model.Person;
/***
* 反射自动查询和封装的类
*@author qindongliang
*
* */
public
class
CommonSupport {
/**
* @param obj需要保存的对象
* @param string 保存对象的sql语句
* */
public
static
String createSqlByObject(Object obj){
StringBuffer sb=
new
StringBuffer(
"insert into "
);
//得到对象的类
Class c=obj.getClass();
//得到对象中的所有方法
Method[] ms=c.getMethods();
//得到对象中所有的属性,虽然在这个里面就能获取所有的字段名,但不建议这么用,破坏类的封装性
Field[] fs=c.getDeclaredFields();
//得到对象类的名字
String cname=c.getName();
System.out.println(
"类名字: "
+cname);
//表名字
String tableName=cname.split(
"\\."
)[cname.split(
"\\."
).length-
1
];
System.out.println(
"表名字: "
+tableName);
//追加表名和(左边的符号
sb.append(tableName).append(
" ("
);
//存放列名的集合
List<String> columns=
new
ArrayList<String>();
//存放值的集合
List values=
new
ArrayList();
//遍历方法
for
(Method m:ms){
String methodName=m.getName();
//获取每一个方法名
//只得到具有get方法的属性,getClass除外
if
(methodName.startsWith(
"get"
)&&!methodName.startsWith(
"getClass"
)){
//System.out.println("属性名:"+methodName);
String fieldName = methodName.substring(
3
, methodName.length());
// System.out.println("字段名:"+fieldName);
columns.add(fieldName);
//将列名添加到列名的集合里
try
{
Object value=m.invoke(obj,
null
);
//System.out.println("执行方法返回的值:"+value);
if
(value
instanceof
String){
// System.out.println("字符串类型字段值:"+value);
values.add(
"‘"
+value+
"‘"
);
//加上两个单引号,代表是字符串类型的
}
else
{
// System.out.println("数值类型字段值:"+value);
values.add(value);
//数值类型的则直接添加
}
}
catch
(Exception e){
e.printStackTrace();
}
}
}
for
(
int
i=
0
;i<columns.size();i++){
String column=columns.get(i);
Object value=values.get(i);
System.out.println(
"列名:"
+column+
" 值: "
+value);
}
//拼接列名
for
(
int
i=
0
;i<columns.size();i++){
if
(i==columns.size()-
1
){
sb.append(columns.get(i)).append(
" ) "
);
}
else
{
sb.append(columns.get(i)).append(
" , "
);
}
}
System.out.println(
" 拼接列名后的sql:"
+sb.toString());
sb.append(
" values ( "
);
//拼接值
for
(
int
i=
0
;i<values.size();i++){
if
(i==values.size()-
1
){
sb.append(values.get(i)).append(
" ) "
);
}
else
{
sb.append(values.get(i)).append(
" , "
);
}
}
System.out.println(
" 拼接值后的sql:"
+sb.toString());
//返回组装的sql语句
return
sb.toString();
}
/**
* 将对象保存在数据库中
* @param obj 保存的对象
* **/
public
static
void
addOne(Object obj){
try
{
Connection con=ConnectionFactory.getCon();
String sql=createSqlByObject(obj);
PreparedStatement ps=con.prepareStatement(sql);
int
result=ps.executeUpdate();
if
(result==
1
){
System.out.println(
"保存成功!"
);
}
else
{
System.out.println(
"保存失败!"
);
}
ps.close();
con.close();
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 根据类名字和一个查询条件
* 自动封装一个Bean对象
* @param columnName 列名
* @param value 列值
* @return {@link Object}
*
* */
public
static
Object getOneObject(String className,String columnName,String value){
String tableName=className.split(
"\\."
)[className.split(
"\\."
).length-
1
];
System.out.println(
"表名字: "
+tableName);
//根据类名来创建对象
Class c=
null
;
try
{
c=Class.forName(className);
//反射生成一个类实例
}
catch
(Exception e){
e.printStackTrace();
}
//拼接sql语句
StringBuffer sb=
new
StringBuffer();
sb.append(
"select * from "
)
.append(tableName)
.append(
" where "
)
.append(columnName).append(
" = "
).append(
"‘"
).append(value).append(
"‘"
);
String querySql=sb.toString();
System.out.println(
"查询的sql语句为:"
+querySql);
Object obj=
null
;
try
{
Connection con=ConnectionFactory.getCon();
//得到一个数据库连接
PreparedStatement ps=con.prepareStatement(querySql);
//预编译语句
ResultSet rs=ps.executeQuery();
//执行查询
//得到对象的所有的方法
Method ms[]=c.getMethods();
if
(rs.next()){
//生成一个实例
obj=c.newInstance();
for
(Method m:ms){
String mName=m.getName();
if
(mName.startsWith(
"set"
)){
//根据方法名字自动提取表中对应的列名
String cname = mName.substring(
3
, mName.length());
//打印set的方法名
// System.out.println(cname);
//得到方法的参数类型
Class[] params=m.getParameterTypes();
// for(Class cp : params){
// System.out.println(cp.toString());
// }
//如果参数是String类型,则从结果集中,按照列名取到的值,进行set
//从params[0]的第一个值,能得到该数的参数类型
if
(params[
0
]==String.
class
){
//
m.invoke(obj, rs.getString(cname));
//如果判断出来是int形,则使用int
}
else
if
(params[
0
]==
int
.
class
){
m.invoke(obj, rs.getInt(cname));
}
}
}
}
else
{
System.out.println(
"请注意:"
+columnName+
"="
+value+
"的条件,没有查询到数据!!"
);
}
rs.close();
ps.close();
con.close();
}
catch
(Exception e){
e.printStackTrace();
}
return
obj;
}
public
static
void
main(String[] args)
throws
Exception{
//====================添加======================
Dog d=
new
Dog(
21
,
"小不点"
,
"藏獒"
,
"灰色"
,
25
);
Person p=
new
Person(
6
,
"大象hadoop"
,
10
,
"家住Apache基金组织"
);
//createSqlByObject(d);
//addOne(d);给dog表添加一条数据
//addOne(p);//给person表添加一条数据
//=======================查询=======================
//强制转换为原始类
// Dog d1=(Dog)getOneObject("com.qin.model.Dog", "id", "1");
// System.out.println(d1);
Person d1=(Person)getOneObject(
"com.qin.model.Person"
,
"id"
,
"1"
);
//Person d1=(Person)getOneObject("com.qin.model.Person", "name", "王婷");
System.out.println(d1);
}
}
代码量是非常的少的,而且具有通用型,如果再有10个这个实体类,我们代码根本不用任何改动,只需要传入不同的实体类名字即可,当然这一点和Hibernate的自动化ORM非常接近了,在Hibnerate里,可以自动通过表生成类,也可以通过类生成数据库的表,原理其实就是利用了反射的特性,帮我们做了大量的重复工作,当然Hibnerate提供了更多的特性,也这只是一个简单的例子,具体的应用场景中,我们也需要因地制宜,否则,则为适得其反!
最后,大家来一起喊一句:
JAVA ,我爱你 !
使用JAVA反射的利与弊
标签:
原文地址:http://my.oschina.net/u/1027043/blog/402458
踩
(
0
)
赞
(
0
)
举报
评论
一句话评论(
0
)
登录后才能评论!
分享档案
更多>
2021年07月29日 (22)
2021年07月28日 (40)
2021年07月27日 (32)
2021年07月26日 (79)
2021年07月23日 (29)
2021年07月22日 (30)
2021年07月21日 (42)
2021年07月20日 (16)
2021年07月19日 (90)
2021年07月16日 (35)
周排行
更多
Spring Cloud 从入门到精通(一)Nacos 服务中心初探
2021-07-29
基础的排序算法
2021-07-29
SpringBoot|常用配置介绍
2021-07-29
关于 .NET 与 JAVA 在 JIT 编译上的一些差异
2021-07-29
C语言常用函数-toupper()将字符转换为大写英文字母函数
2021-07-29
《手把手教你》系列技巧篇(十)-java+ selenium自动化测试-元素定位大法之By class name(详细教程)
2021-07-28
4-1 YAML配置文件 注入 JavaBean中
2021-07-28
【python】 用来将对象持久化的 pickle 模块
2021-07-28
马拉车算法
2021-07-28
用Python进行冒泡排序
2021-07-28
友情链接
兰亭集智
国之画
百度统计
站长统计
阿里云
chrome插件
新版天听网
关于我们
-
联系我们
-
留言反馈
© 2014
mamicode.com
版权所有 联系我们:gaon5@hotmail.com
迷上了代码!