`
qindongliang1922
  • 浏览: 2188619 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
7265517b-f87e-3137-b62c-5c6e30e26109
证道Lucene4
浏览量:117663
097be4a0-491e-39c0-89ff-3456fadf8262
证道Hadoop
浏览量:126070
41c37529-f6d8-32e4-8563-3b42b2712a50
证道shell编程
浏览量:60024
43832365-bc15-3f5d-b3cd-c9161722a70c
ELK修真
浏览量:71399
社区版块
存档分类
最新评论

使用JAVA反射的利与弊

    博客分类:
  • JAVA
阅读更多
在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方法





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

}


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

最后,大家来一起喊一句:
JAVA ,我爱你 !

  • 大小: 47.9 KB
2
1
分享到:
评论
4 楼 windshome 2015-04-23  
让上层代码传递类名,这种方式本身就很糟糕,例如:

Dog d1=(Dog)getOneObject("com.qin.model.Dog", "id", "1"); 

当然,这需要在上边封一层来做也可以。
3 楼 bonait 2015-04-17  
不错,写的很好。www.zipim168.com
2 楼 qindongliang1922 2015-04-16  
windshome 写道
假如你的程序都是简单的CURD当然可以,实际业务中很难说的。

不同的实体,是用于不同业务的。站在业务角度分析和设计才是关键,只是业务分析清楚之后,可以使用文中这种实现来支撑。ORM被人诟病“ORM已死”就是因为这东西很容易对程序员来讲遮蔽了业务。


你说的没错,业务角度分析和设计是重要,不过,业务的最终还会反映到代码上,本文只是一个单纯的技术上的例子,如果要非要把业务因素加进去,那么10个人就会有10种不同的业务,100人就会有100种不同的业务,具体的怎么应用,肯定会像文中所说,因地制宜
1 楼 windshome 2015-04-16  
假如你的程序都是简单的CURD当然可以,实际业务中很难说的。

不同的实体,是用于不同业务的。站在业务角度分析和设计才是关键,只是业务分析清楚之后,可以使用文中这种实现来支撑。ORM被人诟病“ORM已死”就是因为这东西很容易对程序员来讲遮蔽了业务。

相关推荐

    java反射 java反射 java反射java反射

    Java反射是Java编程语言中的一个重要特性,它允许程序在运行时动态地获取类的信息并操作类的对象。在Java中,反射机制提供了强大的能力,包括在运行时检查类的结构、创建对象实例、调用方法以及访问和修改字段值。...

    java 反射的使用

    以下是对Java反射使用及相关知识点的详细阐述: 1. **获取Class对象** - `Class.forName(String className)`: 通过全限定类名获取Class对象。 - `object.getClass()`: 对象的`getClass()`方法返回该对象的Class...

    JAVA反射机制的入门代码

    Java反射机制是Java编程语言中的一个强大特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。这个特性使得Java具有了高度的灵活性和动态性,尤其是在处理元数据、创建对象、调用私有方法...

    Java反射性能测试分析

    ### Java反射性能测试分析 #### 引言 Java反射机制是Java编程语言中一个强大的特性,它允许程序在运行时动态地访问、检测和修改类、接口、字段和方法等对象。然而,反射操作通常会引入额外的开销,这在性能敏感的...

    java反射,获取所有属性、方法以及List集合类

    本篇文章将深入探讨如何使用Java反射来获取一个类的所有属性、方法,并处理List集合类。 首先,让我们了解Java反射的基础概念。在Java中,`java.lang.Class`类代表运行时的类信息。我们可以使用`Class.forName()`...

    Java反射机制总结

    以下是一个简单的Java反射示例,展示了如何使用反射来获取类的信息: ```java import java.lang.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.for...

    java反射机制.zip

    java反射机制java反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制.zipjava反射机制...

    java反射机制应用

    ### Java反射机制应用详解 #### 一、Java反射机制简介 Java反射机制是Java语言提供的一种能在运行时分析类信息并动态操作对象的功能。通过反射,我们可以在程序运行期间获取类的信息(如类名、方法名等),创建...

    Java反射 JavaBean对象自动生成插入,更新,删除,查询sql语句操作.docx

    在Java反射JavaBean对象自动生成插入、更新、删除、查询sql语句操作中,主要使用了Java反射机制来获取JavaBean对象的信息,然后根据这些信息生成对应的sql语句。例如,通过Java反射机制可以获取JavaBean对象的成员...

    java反射.pdf

    ### Java反射机制详解 #### 一、什么是Java反射? Java反射是Java编程语言的一个特性,它允许运行时检查和操作程序结构(类、字段、方法等)。反射的主要用途包括但不限于:动态实例化对象、访问私有成员、调用...

    北大青鸟java反射机制

    Java反射机制是Java编程语言中的一个强大工具,它允许程序在运行时检查并操作类、接口、字段和方法等对象。在"北大青鸟java反射机制"的学习资料中,我们将会深入探讨这一核心特性。 首先,我们要理解反射的核心概念...

    Java反射简单例子

    下面我们将详细探讨Java反射的基本概念、使用场景以及如何通过`ReflectTest.java`这个简单的例子来理解反射。 ### 1. 反射的基本概念 反射机制允许我们在运行时检查类的信息,包括类名、方法名、参数类型等,并且...

    java之反射优化(缓存思路)源码

    2. **软引用**:使用Java的`SoftReference`可以创建一个弱化的缓存,这样在内存紧张时,JVM会自动回收这些不再使用的反射对象,以释放内存。 ```java public class ReflectionUtil { private static Map, ...

    通过Java反射机制获取JavaBean对象

    1.通过Java反射机制获取JavaBean对象。 2.通过JavaBean全路径字符串获取JavaBean对象。 3.获取JavaBean注解信息

    Java反射案例

    这个案例将深入探讨如何使用Java反射来实现一些实用的功能。 1. **获取类信息**: 反射机制首先从Class对象开始,它是所有Java类的元数据。通过`Class.forName()`方法或`类名.class`可以获取到Class对象。一旦有了...

    Java 反射-动态代理

    了解了Java反射和动态代理的基本概念后,实践中我们需要谨慎使用,因为它们会带来一定的性能开销,并可能破坏封装性。然而,只要合理运用,它们能极大地提高代码的灵活性和可扩展性,是Java开发中的利器。 在提供的...

    Java反射与动态代理

    Java反射是Java编程语言中的一个强大特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射机制的核心类包括`Class`、`Field`、`Method`和`Constructor`,它们分别代表类、...

    java反射.ppt

    Java反射是Java编程语言的一个重要特性,它允许在运行时检查和操作类、接口、字段和方法等对象。反射提供了一种动态访问和修改程序的能力,使得代码可以在不知道具体类的情况下,对对象进行操作。 1. **Class类的...

    Java反射机制的学习

    要使用Java反射,首先需要获取到`Class`对象,这是反射操作的基础。以下是一些获取`Class`对象的方法: 1. `getClass()`:每个对象都有`getClass()`方法,可以直接获取对象所属的类的`Class`实例。 2. `Class....

    java反射的demo代码

    Java反射是Java编程语言中的一个强大特性,它允许我们在运行时检查类、接口、字段和方法的信息,并且能够在运行时动态地创建对象和调用方法。这个特性在处理不确定类型、插件系统、序列化、元数据处理以及许多其他...

Global site tag (gtag.js) - Google Analytics