使用JAVA反射的利与弊

2023-11-15

[b][color=olive][size=large]在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方法
[/size][/color][/b]


[img]http://dl2.iteye.com/upload/attachment/0107/6180/75f01d25-0a9c-33b5-8893-092ae18d2fc6.png[/img]

实体类如下:
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 + "]";
}




}


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 + "]";
}



}



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();


}

}



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);


}



}

[b][color=green][size=large]
代码量是非常的少的,而且具有通用型,如果再有10个这个实体类,我们代码根本不用任何改动,只需要传入不同的实体类名字即可,当然这一点和Hibernate的自动化ORM非常接近了,在Hibnerate里,可以自动通过表生成类,也可以通过类生成数据库的表,原理其实就是利用了反射的特性,帮我们做了大量的重复工作,当然Hibnerate提供了更多的特性,也这只是一个简单的例子,具体的应用场景中,我们也需要因地制宜,否则,则为适得其反!

最后,大家来一起喊一句:
JAVA ,我爱你 ! [/size][/color][/b]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用JAVA反射的利与弊 的相关文章

  • 使用 ProcessBuilder 运行 msys.bat

    我正在尝试使用 ProcessBuilder 在 java 中运行 msys bat 当我使用程序运行 bat 文件时 出现以下错误 找不到 rxvt exe 或 sh exe 二进制文件 正在中止 按任意键继续 这是代码 ProcessB
  • war文件可以部署在任何服务器上吗?

    如果这个问题很愚蠢 请原谅我 假设我使用 Spring 框架和 MS SQL Server 数据库以及 WebSphere 应用程序服务器开发一个 J2EE Web 应用程序 我后来为此应用程序创建了一个 WAR 文件 我可以在不更改代码的
  • Oracle的服务器JRE包含JDK?

    我刚刚下载了适用于 Java SE 7 的 Oracle Server JRE link http www oracle com technetwork java javase downloads server jre7 downloads
  • JSF:初始请求和回发请求?

    请看一下 JSF 中的下面这行代码
  • 使用递归查找数组中的最大值

    对于我被要求解决的问题之一 我使用 for 循环找到了数组的最大值 所以我尝试使用递归来找到它 这就是我想到的 public static int findMax int a int head int last int max 0 if h
  • JFace DialogCellEditor:如何使按钮始终出现?

    我用的是JFaceDialogCellEditor在 JFace 的一行单元格中显示一个按钮TableViewer激活时会触发一个对话框 此行为适用于以下代码 但仅当显式选择托管按钮的表的单元格时才会显示该按钮 public class C
  • Jersey 2 - ContainerRequestFilter get 方法注解

    我试图获取 ContainerRequestFilter 对象中的方法注释 控制器 GET RolesAllowed ADMIN public String message return Hello rest12 容器请求过滤器 Provi
  • 使用 IcyStreamMeta 从 SHOUTcast 获取元数据

    我正在为 Android 编写一个应用程序 从 SHOUTcast mp3 流中获取元数据 我正在使用我在网上找到的一个非常漂亮的类 我稍微修改了一下 但我仍然有两个问题 1 我必须使用 TimerTask 不断 ping 服务器来更新元数
  • 关于线程的停止

    我开发了一个代码 它将在执行时启动两个线程 public class MyThread1 extends Thread extend thread class public synchronized void run synchronize
  • 如何在 El Capitan (OS X 10.11) 中设置 Android Studio?

    全新安装 El Capitan 10 11 尝试安装 Android Studio 版本 1 21 Error Android Studio was unable to find a valid JVM Please download it
  • 配置 logback 以遵循 Java 配置,即 Logback 的纯 Java 配置

    我只是不喜欢 Logback 的 XML 或 Groovy 配置 更喜欢用 Java 进行配置 这也是因为我将在初始化后的不同时间在运行时更改配置 似乎对 Logback 进行 Java 配置的唯一方法是进行某种初始化劫持根追加器 http
  • Android文件上传器与服务器端php

    我几个小时以来一直在寻找解决方案 但找不到任何解决方案 基本上 我想从我的 Android 设备上传文件到 http 网站 但是 我不知道如何做到这一点 我在设备上使用java 并且我想在服务器端使用PHP 我只想上传文件 而不是在服务器上
  • HTML 解析和删除锚标记,同时使用 Jsoup 保留内部 html

    我必须解析一些html并删除锚标记 但我需要保留锚标记的innerHTML 例如 如果我的 html 文本是 String html div p some text a href some link text a p div 现在我可以解析
  • java中的new关键字是多余的吗?

    我来自 C 所以 java 的一个特性我不太理解 我读过所有对象都必须使用关键字创建new 但基元除外 现在 如果编译器可以识别原始类型 并且不允许您在不调用其构造函数的情况下创建对象new 有这个关键字的原因是什么new根本吗 有人可以提
  • 通常可重用的注释或公共注释?

    有没有常用的注释 类似于 commons lang 如果没有 您是否见过在任何开源应用程序开发中有效使用注释 不是内置注释 的情况 我记得 Mifos 用它来进行交易 Mohan i think 休眠验证器 http www hiberna
  • 动态添加组件到 JDialog

    当用户单击 JDialog 上的按钮时 我在将组件添加到 JDialog 时遇到问题 基本上我希望它看起来像这样 然后 当用户单击 添加新字段 时 我希望它看起来像这样 我似乎无法打开添加新 JLabel 或 JTextField 的对话框
  • 光线追踪三角形

    我正在用java编写一个光线追踪器 并且我能够追踪球体 但我相信我追踪三角形的方式有问题 据我了解 这是基本算法 首先确定射线是否与plane三角形已打开 剪裁所有点 使它们与三角形位于同一平面上 因此xy以平面为例 根据沿着新平面向任意方
  • 正确使用Optional.ifPresent()

    我正在尝试理解ifPresent 的方法OptionalJava 8 中的 API 我有一个简单的逻辑 Optional
  • 如何获取eclipse中的工作空间路径? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我正在研究PDE Eclipse Plugin Project 我需要获取工作区路径 我的文本小部件 swt 应该设置为当前工作空间路径 如
  • Java - 全局、可重用的加载对话框

    我正在尝试实现一个全局加载对话框 我想调用一些静态函数来显示对话框和一些静态函数来关闭它 与此同时 我正在主线程或子线程中做一些工作 我尝试以下操作 但对话框没有更新 最后一次 在再次隐藏之前 它会更新 private static Run

随机推荐

  • failed to load response data出现的问题

    分片上传的时候 状态码请求是200的状态 但是 出现了 failed to load response data 没有response的返回 原因是 我分片的 每片大小太大了 分成了10M 所以出现了这个问题 const chunkSize
  • 【2-3】《Java基础语法》——二进制、变量、数据类型、标识符、数据类型转换、特殊变量定义、方法、运算符、变量作用域、编程规范、转义字符

    文章目录 基础语法 一 二进制 1 补码 2 二进制与十进制的转换 二 变量概述 三 数据类型 1 分类 2 范围 四 标识符 1 命名规则 2 Java中的关键字 3 定义变量 4 变量练习 五 数据类型转换 六 特殊变量定义 1 flo
  • nn.Module模块

    1 模块化接口nn torch nn是pytorch中专门为神经网络设计的模块化接口 nn构建于autograd之上 可以用来定义和运行神经网络 2 nn Module nn Module是nn中十分重要的类 包含网络各层的定义及forwa
  • 大神之路-起始篇

    欢迎关注 WeiyiGeek 公众号 点击 下方卡片 即可关注我哟 设为 星标 每天带你 基础入门 到 进阶实践 再到 放弃学习 涉及 网络安全运维 应用开发 物联网IOT 学习路径 个人感悟 等知识 花开堪折直须折 莫待无花空折枝 作者主
  • rocketMQ启动报错,JavaHotSpot(TM) 64-Bit Server VM warning错误: 找不到或无法加载主类 Files\jdk1.8.0_161\\jre\lib\ext

    Java HotSpot TM 64 Bit Server VM warning Using the DefNew young collector with the CMS collector is deprecated and will
  • foreach用法_R语言--并行计算包(parallel、foreach)

    R语言是单核计算语言 在数据建模或计算过程中 常常出现相同或相似任务的重复计算 一般操作是for循环处理或采用apply族函数处理 为了更快完成计算 采用并行计算是更优的选择 本文采用R语言中的parallel包与foreach包实现并行计
  • ueditor-后台配置项返回格式出错,上传功能将不能正常使用!

    一 服务器环境 php centos apache 二 症状 ueditor编辑界面可以显示 但单图片上传按钮点击没反应 多图片上传显示 后台配置项返回格式出错 上传功能将不能正常使用 三 分析 1 打开浏览器调试模式 显示 后台配置项返回
  • Zookeeper——zookeeper基础

    在深入了解ZooKeeper的运作之前 让我们来看看ZooKeeper的基本概念 我们将在本章中讨论以下主题 Architecture 架构 Hierarchical namespace 层次命名空间 Session 会话 Watches
  • 剑指 Offer 06. 从尾到头打印链表

    从尾到头打印链表 蠢想法 解题思路 的节点顺序已经反转过来了 栈 package swordPointingToTheOffer import java util Stack 引用栈 public class six 初始化 Stack
  • MessageBoxA的用法

    一 函数原型 int fastcall MessageBox const char Text const char Caption int Flags 0x0 Flags表示对话框的按钮组合 取值有 MessageBox Flags def
  • 虚拟地址内存空间

    bss段详解 详细讲解
  • 一个简单的HttpClient使用案例

    HttpClient 是什么 HttpClient 是Apache Jakarta Common 下的子项目 可以用来提供高效的 最新的 功能丰富的支持 HTTP 协议的客户端编程工具包 并且它支持 HTTP 协议最新的版本和建议 该如何使
  • Web3-js的学习(5)-实现合约事件监听

    合约事件监听 latest 监听最新出块事件 pending 监听发布未进块事件 代码很简单 var Web3 require web3 var web3 new Web3 new Web3 providers HttpProvider h
  • 解决在Intellij IDEA中无法创建Servlet类的问题/New中没有Servlet类/创建不了Servlet类

    新手在学习Servlet相关知识的时候 一些课程往往会告知新手去使用IDEA自带的模板来创建Servlet 这样减少了注解等麻烦 降低了工作量 然而 如下图所示 很多人发现在自己的new一栏不存在Servlet类 如下图 网上的解决办法很多
  • 服务 -web服务器及ssh

    web服务器 文件共享 nfs samba 一般用于局域网中 ftp http 一般用于公网 tcp 80 httpd apache 1 完全开源 2 跨平台 3 支持多种编程语言 4 采用模块化的设计 5 安全稳定 IE www taob
  • 笔记/samba搭建

    1 安装 yum y install samba 2 配置 vim etc samba smb conf global 安全模式 user shared domain security user 认证模式 passdb backend td
  • autosar宏定义搜集

    1 AUTOSAR 长函数声明 2 教你如何阅读Autosar代码 1 概述 3 把AUTOSAR函数以及变量等定义的宏用脚本展开以提高可读性 4 Specification of Compiler Abstraction autosar
  • C语言满天星加月亮

    import java awt Color import java awt Graphics import javax swing JFrame import javax swing JPanel public class Stars pu
  • C++关键字 noexcept

    1 关键字noexcept 从C 11开始 我们能看到很多代码当中都有关键字noexcept 比如下面就是std initializer list的默认构造函数 其中使用了noexcept constexpr initializer lis
  • 使用JAVA反射的利与弊

    b color olive size large 在Java的20周年的纪念日的日子里 让我们来重新温习下Java里面的高级知识 Java肯定希望大家了解她 要不然你跟她天天相濡以沫了这么长时间 让她知道你竟然不了解她 不在乎她 那么她该有