java display.getdefault()_java基础(十一 )-----反射——Java高级开发必须懂的
本文我們通過一個實際的例子來演示反射在編程中的應用,可能之前大家對反射的學習,僅僅是停留在概念層面,不知道反射究竟應用在哪,所以是一頭霧水。相信通過這篇教程,會讓你對反射有一個更深層次的認知。
概念
Java反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為Java語言的反射機制。
如何理解反射?簡單的一句話解釋,將傳統的開發思路反向逆轉。
傳統的方式是通過類創建對象:類 ---> 對象。
反射就是將這個過程逆轉,通過對象得到類:對象 ---> 類。
通過對象得到的這個類該如何表示?
使用Class類來表示,此類是Java反射的源頭,是用來描述其他類的類,Class類的每一個實例化對象就是對其他類的描述。
在Object類中定義了以下的方法,此方法將被所有子類繼承:
public final Class getClass()。
也就是說每一個類,都可以調用getClass()方法獲取對應的Class對象,用來描述目標類,我們將這個Class類叫做目標類的運行時類。
有了Class對象,能做什么?
調用Class對象的newInstance()方法,可以動態創建目標類的對象。
要求:
1)目標類必須有無參數構造方法。
2)外部方法有足夠的權限訪問目標類的構造方法。
除了動態創建目標類的對象,反射也可以動態調用對象的各種方法,訪問成員變量。
Java反射機制主要提供下面幾種用途:
在運行時判斷任意一個對象所屬的類
在運行時構造任意一個類的對象
在運行時判斷任意一個類所具有的成員變量和方法
在運行時調用任意一個對象的方法
反射相關的主要API
java.lang.Class:描述一個類。
java.lang.reflect.Method:描述類的方法。
java.lang.reflect.Field:描述類的成員變量。
java.lang.reflect.Constructor:描述類的構造方法。
Class用來描述目標類的結構,叫做目標類的運行時類。
Class的常用方法:
方法描述
public Class>[] getInterfaces()
返回運行時類實現的全部接口。
public Class Super T> getSuperclass()
返回運行時類的父類。
public Constructor[] getConstructors()
返回運行時類的public構造方法。
public Constructor[] getDeclaredConstructors()
返回運行時類的全部構造方法。
public Method[] getMethods()
返回運行時類的public方法。
public Method[] getDeclaredMethods()
返回運行時類的全部方法。
public Field[] getFields()
返回運行時類的public成員變量。
public Field[] getDeclaredFields()
返回運行時類的全部成員變量。
Method用來描述運行時類的方法。
Method的常用方法:
方法描述
public Class> getReturnType()
返回方法的返回值類型。
public Class>[] getParameterTypes()
返回方法的參數列表。
public int getModifiers()
返回方法的訪問權限修飾符。
public String getName();
返回方法名。
Field用來描述運行時類的成員變量。
Field的常用方法:
方法描述
public int getModifiers()
返回成員變量的訪問權限修飾符。
public Class> getType()
返回成員變量的數據類型。
public String getName()
返回成員變量的名稱。
反射的應用
反射在實際中的應用主要是動態創建對象,動態調用對象的方法。
1.創建對象:
調用Class類的newInstance()方法創建對象。
2.調用指定方法:
(1)通過Class類的getMethod(String name,Class…parameterTypes)方法獲取一個Method對象,并設置此方法操作時所需要的參數類型。
(2)調用Object invoke(Object obj, Object[] args)方法,并向方法中傳遞目標obj對象的參數信息。
首先看一個簡單的例子,通過這個例子來理解Java的反射機制是如何工作的。
packagecom.chenHao.reflection;importjava.lang.reflect.Method;/*** Java 反射練習。
*
*@authorchenHao*/
public classForNameTest {/*** 入口函數。
*
*@paramargs
* 參數
*@throwsException
* 錯誤信息*/
public static void main(String[] args) throwsException {//獲得Class
Class> cls = Class.forName("java.lang.String");//通過Class獲得所對應對象的方法
Method[] methods =cls.getMethods();//輸出每個方法名
for(Method method : methods) {
System.out.println(method);
}
}
}
輸出如下結果:
public booleanjava.lang.String.equals(java.lang.Object)publicjava.lang.String java.lang.String.toString()public intjava.lang.String.hashCode()public intjava.lang.String.compareTo(java.lang.String)public intjava.lang.String.compareTo(java.lang.Object)public int java.lang.String.indexOf(int)public int java.lang.String.indexOf(int,int)public intjava.lang.String.indexOf(java.lang.String)public int java.lang.String.indexOf(java.lang.String,int)public static java.lang.String java.lang.String.valueOf(int)public static java.lang.String java.lang.String.valueOf(char)public static java.lang.String java.lang.String.valueOf(boolean)public static java.lang.String java.lang.String.valueOf(float)public static java.lang.String java.lang.String.valueOf(char[],int,int)public static java.lang.String java.lang.String.valueOf(double)public static java.lang.String java.lang.String.valueOf(char[])public staticjava.lang.String java.lang.String.valueOf(java.lang.Object)public static java.lang.String java.lang.String.valueOf(long)public char java.lang.String.charAt(int)public int java.lang.String.codePointAt(int)public int java.lang.String.codePointBefore(int)public int java.lang.String.codePointCount(int,int)public intjava.lang.String.compareToIgnoreCase(java.lang.String)publicjava.lang.String java.lang.String.concat(java.lang.String)public booleanjava.lang.String.contains(java.lang.CharSequence)public booleanjava.lang.String.contentEquals(java.lang.CharSequence)public booleanjava.lang.String.contentEquals(java.lang.StringBuffer)public static java.lang.String java.lang.String.copyValueOf(char[])public static java.lang.String java.lang.String.copyValueOf(char[],int,int)public booleanjava.lang.String.endsWith(java.lang.String)public booleanjava.lang.String.equalsIgnoreCase(java.lang.String)public staticjava.lang.String java.lang.String.format(java.lang.String,java.lang.Object[])public staticjava.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[])public byte[] java.lang.String.getBytes(java.lang.String) throwsjava.io.UnsupportedEncodingExceptionpublic void java.lang.String.getBytes(int,int,byte[],int)public byte[] java.lang.String.getBytes()public byte[] java.lang.String.getBytes(java.nio.charset.Charset)public void java.lang.String.getChars(int,int,char[],int)public nativejava.lang.String java.lang.String.intern()public booleanjava.lang.String.isEmpty()public intjava.lang.String.lastIndexOf(java.lang.String)public int java.lang.String.lastIndexOf(int,int)public int java.lang.String.lastIndexOf(int)public int java.lang.String.lastIndexOf(java.lang.String,int)public intjava.lang.String.length()public booleanjava.lang.String.matches(java.lang.String)public int java.lang.String.offsetByCodePoints(int,int)public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int)public boolean java.lang.String.regionMatches(int,java.lang.String,int,int)publicjava.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence)public java.lang.String java.lang.String.replace(char,char)publicjava.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String)publicjava.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String)publicjava.lang.String[] java.lang.String.split(java.lang.String)public java.lang.String[] java.lang.String.split(java.lang.String,int)public booleanjava.lang.String.startsWith(java.lang.String)public boolean java.lang.String.startsWith(java.lang.String,int)public java.lang.CharSequence java.lang.String.subSequence(int,int)public java.lang.String java.lang.String.substring(int)public java.lang.String java.lang.String.substring(int,int)public char[] java.lang.String.toCharArray()publicjava.lang.String java.lang.String.toLowerCase()publicjava.lang.String java.lang.String.toLowerCase(java.util.Locale)publicjava.lang.String java.lang.String.toUpperCase()publicjava.lang.String java.lang.String.toUpperCase(java.util.Locale)publicjava.lang.String java.lang.String.trim()public final native void java.lang.Object.wait(long) throwsjava.lang.InterruptedExceptionpublic final void java.lang.Object.wait() throwsjava.lang.InterruptedExceptionpublic final void java.lang.Object.wait(long,int) throwsjava.lang.InterruptedExceptionpublic final nativejava.lang.Class java.lang.Object.getClass()public final native voidjava.lang.Object.notify()public final native void java.lang.Object.notifyAll()
這樣就列出了java.lang.String類的所有方法名、及其限制符、返回類型及拋出的異常。這個程序使用Class類forName方法載入指定的類,然后調用getMethods方法返回指定類的方法列表。java.lang.reflect.Method用來表述某個類中的單一方法。
使用java的反射機制,一般需要遵循三步:
獲得你想操作類的Class對象
通過第一步獲得的Class對象去取得操作類的方法或是屬性名
操作第二步取得的方法或是屬性
Java運行的時候,某個類無論生成多少個對象,他們都會對應同一個Class對象,它表示正在運行程序中的類和接口。如何取得操作類的Class對象,常用的有三種方式:
調用Class的靜態方法forName,如上例;
使用類的.class語法,如:Class?cls = String.class;
調用對象的getClass方法,如:String str = "abc";Class?cls = str .getClass();
下面將通過實例講述如何通過前面所訴的三步來執行某對象的某個方法:
1 packagecom.chenHao.reflection;2
3 importjava.lang.reflect.Method;4
5 /**
6 * Java 反射練習。7 *8 *@authorchenHao9 */
10 public classReflectionTest {11 public static void main(String[] args) throwsException {12 DisPlay disPlay = newDisPlay();13 //獲得Class
14 Class> cls =disPlay.getClass();15 //通過Class獲得DisPlay類的show方法
16 Method method = cls.getMethod("show", String.class);17 //調用show方法
18 method.invoke(disPlay, "chenHao");19 }20 }21
22 classDisPlay {23 public voidshow(String name) {24 System.out.println("Hello :" +name);25 }26 }
前面說過,Java程序的每個類都會有個Class對象與之對應。Java反射的第一步就是獲得這個Class對象,如代碼14行。當然,每個類的方法也必有一個Method對象與之對應。要通過反射的方式調用這個方法,就要首先獲得這個方法的Method對象,如代碼16行,然后用Method對象反過來調用這個方法,如代碼18行。
注意:16行getMethod方法的第一個參數是方法名,第二個是此方法的參數類型,如果是多個參數,接著添加參數就可以了,因為getMethod是可變參數方法。執行18行代碼的invoke方法,其實也就是執行show方法,注意invoke的第一個參數,是DisPlay類的一個對象,也就是調用DisPlay類哪個對象的show方法,第二個參數是給show方法傳遞的參數。類型和個數一定要與16行的getMethod方法一直。
上例講述了如何通過反射調用某個類的方法,下面將再通過一個實例講述如何在運行時創建類的一個對象,如何通過反射給某個類的屬性賦值:
1 packagecom.chenHao.reflection;2
3 importjava.lang.reflect.Field;4
5 /**
6 * Java 反射之屬性練習。7 *8 *@authorchenHao9 */
10 public classReflectionTest {11 public static void main(String[] args) throwsException {12 //建立學生對象
13 Student student = newStudent();14 //為學生對象賦值
15 student.setStuName("chenHao");16 student.setStuAge(24);17 //建立拷貝目標對象
18 Student destStudent =(Student) copyBean(student);19 //輸出拷貝結果
20 System.out.println(destStudent.getStuName() + ":"
21 +destStudent.getStuAge());22 }23
24 /**
25 * 拷貝學生對象信息。26 *27 *@paramfrom28 * 拷貝源對象29 *@paramdest30 * 拷貝目標對象31 *@throwsException32 * 例外33 */
34 private static Object copyBean(Object from) throwsException {35 //取得拷貝源對象的Class對象
36 Class> fromClass =from.getClass();37 //取得拷貝源對象的屬性列表
38 Field[] fromFields =fromClass.getDeclaredFields();39 //取得拷貝目標對象的Class對象
40 Object ints =fromClass.newInstance();41 for(Field fromField : fromFields) {42 //設置屬性的可訪問性
43 fromField.setAccessible(true);44 //將拷貝源對象的屬性的值賦給拷貝目標對象相應的屬性
45 fromField.set(ints, fromField.get(from));46 }47
48 returnints;49 }50 }51
52 /**
53 * 學生類。54 */
55 classStudent {56 /**姓名*/
57 privateString stuName;58 /**年齡*/
59 private intstuAge;60
61 publicString getStuName() {62 returnstuName;63 }64
65 public voidsetStuName(String stuName) {66 this.stuName =stuName;67 }68
69 public intgetStuAge() {70 returnstuAge;71 }72
73 public void setStuAge(intstuAge) {74 this.stuAge =stuAge;75 }76 }
注意:Field提供了get和set方法獲取和設置屬性的值,但是由于屬性是私有類型,所以需要設置屬性的可訪問性為true,如代碼50~51行。也可以在為整個fields設置可訪問性,在40行下面使用AccessibleObject的靜態方法setAccessible,如:AccessibleObject.setAccessible(fromFields, true);
簡化版的MyBatis工具
需求:
創建一個查詢數據庫的工具類,自動將SQL語句查詢出的結果集,封裝成不同的對象返回,一個簡化版的MyBatis工具。
思路:
工具類查詢方法的參數列表:Connection對象,SQL語句,目標運行時類對象clazz,數據表的id值。
1.通過Connection對象,SQL語句,id值查詢出對應的結果集。
2.利用反射機制調用clazz的無參構造方法創建目標對象。
3.獲取clazz的Filed,即目標類的所有成員變量。
4.找到與成員變量名相同的結果集字段,并獲取字段值。
5.通過成員變量名找到對應的setter方法。
6.利用反射機制調用setter方法完成賦值。
實現步驟:
1.導入mysql驅動,c3p0數據源相關jar包。
2.創建c3p0-config.xml。
root
root
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=UTF-8
5
5
5
10
20
5
3.創建數據表student,user。
DROP TABLE IF EXISTS`student`;CREATE TABLE`student` (
`id`int(11) NOT NULLAUTO_INCREMENT,
`name`varchar(11) DEFAULT NULL,
`address`varchar(11) DEFAULT NULL,
`tel`varchar(255) DEFAULT NULL,
`score`double(11,1) DEFAULT NULL,PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `user`;CREATE TABLE `user` (
`id`int(11) NOT NULLAUTO_INCREMENT,
`name`varchar(255) DEFAULT NULL,
`age`int(11) DEFAULT NULL,PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4.創建實體類Student,User。
packagecom.southwind.entity;public classStudent {private intid;privateString name;privateString address;privateString tel;private doublescore;public intgetId() {returnid;
}public void setId(intid) {this.id =id;
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}publicString getAddress() {returnaddress;
}public voidsetAddress(String address) {this.address =address;
}publicString getTel() {returntel;
}public voidsetTel(String tel) {this.tel =tel;
}public doublegetScore() {returnscore;
}public void setScore(doublescore) {this.score =score;
}
@OverridepublicString toString() {return "Student [id=" + id + ", name=" + name + ", address=" +address+ ", tel=" + tel + ", score=" + score + "]";
}
}
packagecom.southwind.entity;public classUser {private intid;privateString name;private intage;public intgetId() {returnid;
}public void setId(intid) {this.id =id;
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}public intgetAge() {returnage;
}public void setAge(intage) {this.age =age;
}
@OverridepublicString toString() {return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
5.創建JDBCTools工具類。
packagecom.southwind.util;importjava.sql.Connection;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.Statement;importcom.mchange.v2.c3p0.ComboPooledDataSource;public classJDBCTools {private staticComboPooledDataSource dataSource;static{
dataSource= new ComboPooledDataSource("testc3p0");
}/*** 獲取Connection
*@return
*/
public staticConnection getConnection(){try{returndataSource.getConnection();
}catch(SQLException e) {//TODO Auto-generated catch block
e.printStackTrace();
}return null;
}/*** 釋放資源
*@paramconn
*@paramstmt
*@paramrs*/
public static voidrelease(Connection conn,Statement stmt,ResultSet rs){if(conn != null){try{
conn.close();
}catch(SQLException e) {//TODO Auto-generated catch block
e.printStackTrace();
}
}if(stmt != null){try{
stmt.close();
}catch(SQLException e) {//TODO Auto-generated catch block
e.printStackTrace();
}
}if(rs != null){try{
rs.close();
}catch(SQLException e) {//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
6.創建數據庫查詢工具類MyQueryRunner,核心代碼。
packagecom.southwind.util;importjava.lang.reflect.Field;importjava.lang.reflect.Method;importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.ResultSet;importjava.sql.ResultSetMetaData;importjava.sql.SQLException;/*** 通用工具類
*@authorsouthwind
**/
public classMyQueryRunner {/*** 將結果集動態封裝成對象
*@paramconn
*@paramsql
*@paramclazz
*@paramid
*@return
*/
public Object query(Connection conn,String sql,Class clazz,intid){
PreparedStatement pstmt= null;
ResultSet rs= null;
Object obj= null;try{
pstmt=conn.prepareStatement(sql);
pstmt.setInt(1, id);
rs=pstmt.executeQuery();
obj=clazz.newInstance();if(rs.next()){//遍歷實體類屬性集合,依次將結果集中的值賦給屬性
Field[] fields =clazz.getDeclaredFields();//獲取ResultSet數據
ResultSetMetaData rsmd =rs.getMetaData();for(int i = 0; i < fields.length; i++){
Object value=setFieldValueByResultSet(fields[i],rsmd,rs);//通過屬性名找到對應的setter方法
String name =fields[i].getName();
name= name.substring(0, 1).toUpperCase() + name.substring(1);
String MethodName= "set"+name;
Method methodObj=clazz.getMethod(MethodName,fields[i].getType());//調用setter方法完成賦值
methodObj.invoke(obj, value);
}
}
}catch(Exception e) {//TODO Auto-generated catch block
e.printStackTrace();
}returnobj;
}/*** 根據將結果集中的值賦給對應的屬性
*@paramfield
*@paramrsmd
*@paramrs
*@return
*/
publicObject setFieldValueByResultSet(Field field,ResultSetMetaData rsmd,ResultSet rs){
Object result= null;try{int count =rsmd.getColumnCount();for(int i=1;i<=count;i++){//找到與屬性名相同的結果集字段
if(field.getName().equals(rsmd.getColumnName(i))){//獲取屬性的數據類型
String type =field.getType().getName();switch(type) {case "int":
result=rs.getInt(field.getName());break;case "java.lang.String":
result=rs.getString(field.getName());break;case "double":
result=rs.getDouble(field.getName());break;
}
}
}
}catch(SQLException e) {//TODO Auto-generated catch block
e.printStackTrace();
}returnresult;
}
}
7.測試
通過id查詢student表,調用工具方法,直接返回Student對象。
packagecom.southwind.test;importjava.sql.Connection;importcom.southwind.entity.Student;importcom.southwind.util.MyQueryRunner;importcom.southwind.util.JDBCTools;public classTest {public static voidmain(String[] args) {
Connection conn=JDBCTools.getConnection();
String sql= "select * from student where id = ?";
MyQueryRunner myQueryRunner= newMyQueryRunner();
Student student= (Student) myQueryRunner.query(conn, sql, Student.class, 1);
System.out.println(student);
}
}
通過id查詢user表,調用工具方法,直接返回User對象。
packagecom.southwind.test;importjava.sql.Connection;importcom.southwind.entity.User;importcom.southwind.util.MyQueryRunner;importcom.southwind.util.JDBCTools;public classTest {public static voidmain(String[] args) {
Connection conn=JDBCTools.getConnection();
String sql= "select * from users where id = ?";
MyQueryRunner myQueryRunner= newMyQueryRunner();
User user= (User) myQueryRunner.query(conn, sql, User.class, 30);
System.out.println(user);
}
}
至此,Java反射機制的常用機能(運行時調用對象的方法、類屬性的使用、創類類的對象)已經介紹完了。
補充:在獲得類的方法、屬性、構造函數時,會有getXXX和getgetDeclaredXXX兩種對應的方法。之間的區別在于前者返回的是訪問權限為public的方法和屬性,包括父類中的;但后者返回的是所有訪問權限的方法和屬性,不包括父類的。
總結
以上是生活随笔為你收集整理的java display.getdefault()_java基础(十一 )-----反射——Java高级开发必须懂的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: axios delete有请求体吗_关于
- 下一篇: java 自助更改密码 api_搭建ld