使用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提供了更多的特性,也这只是一个简单的例子,具体的应用场景中,我们也需要因地制宜,否则,则为适得其反!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Java反射是一個強大的工具,它可以讓你存取類別的私有欄位和方法,從而揭露軟體的內部運作方式。這在逆向工程、軟體分析和調試等領域非常有用。要使用Java反射,首先需要匯入java.lang.reflect套件。然後,你可以使用Class.forName()方法來取得一個類別的Class物件。一旦你有了Class對象,你就可以使用各種方法來存取類別的欄位和方法。例如,你可以使用getDeclaredFields()方法來取得類別的所有字段,包括私有字段。你也可以使用getDeclaredMethods()方法

取得方法:1、建立一個範例對象;2、透過field.get(person)取得了欄位的值,其中person是範例對象,而field是Field對象,表示一個欄位;3、透過setAccessible(true)設定欄位為可存取狀態,即使是私有欄位也可以取得其值;4、遍歷欄位數組,可以取得每個欄位的名稱和對應的值,並列印出來即可。

Java反射機制原理是,當一個字節碼檔案載入到記憶體的時候,jvm會對該字節碼進行解剖,創建一個對象的Class對象,jvm把字節碼文件資訊都儲存到Class對像中,只要取得到Class對象,就能使用該對象設定對象的屬性或方法等。反射機制是,在運行狀態中對任意一個類,都知道這個類的所有屬性和方法,對於任意一個對象,能夠調用其任意屬性和方法,動態獲取資訊以及動態調用對象方法的功能。

深入理解Java反射機制的原理與應用一、反射機制的概念與原理反射機制是指在程式執行時動態地獲取類別的資訊、存取與操作類別的成員(屬性、方法、建構方法等)的能力。透過反射機制,我們可以在程式運行時動態地建立物件、呼叫方法和存取屬性,而不需要在編譯時知道類別的具體資訊。反射機制的核心是java.lang.reflect套件中的類別和介面。其中,Class類別代表一個類別的位元組

取得方法:1、建立一個Person類,透過反射取得了該類別的Class物件;2、使用getDeclaredFields方法取得了該類別的所有欄位;3、透過遍歷欄位數組,設定欄位為可存取狀態,然後使用get方法取得欄位的值,並列印欄位名稱和值即可。

透過Java反射機制建立物件步驟如下:載入目標類別:使用Class.forName()方法。取得建構子:使用getDeclaredConstructor()方法。建立物件:使用newInstance()方法傳遞參數。

Java中的NoSuchFieldException異常指的是反射過程中試圖存取不存在的欄位(Field)時拋出的例外狀況。在Java中,反射可以讓我們透過程式碼來操縱程式中的類別、方法、變數等,使得程式具有更高的靈活性和擴充性。但是,在使用反射時,如果存取的欄位不存在,則會拋出NoSuchFieldException異常。 NoSuchFieldException

java反射呼叫方法有:1、Class類別;2、Constructor類別;3、Method類別;4、Field類別;5、ClassLoader類別。詳細介紹:1、Class類,用於取得類別的信息,包括類別的名稱、成員變數和方法等,可以透過Class類的"newInstance()"方法建立類別的實例;2、Constructor類,用於取得建構函數的參數類型、修飾符和返回類型等資訊等等。
