java反射深入剖析(推薦)
本篇文章依舊采用小例子來說明,因?yàn)槲沂冀K覺的,案例驅(qū)動(dòng)是最好的,要不然只看理論的話,看了也不懂,不過建議大家在看完文章之后,在回過頭去看看理論,會(huì)有更好的理解。
下面開始正文。
【案例1】通過一個(gè)對象獲得完整的包名和類名
package Reflect;
/**
* 通過一個(gè)對象獲得完整的包名和類名
* */
class Demo{
//other codes...
}
class hello{
public static void main(String[] args) {
Demo demo=new Demo();
System.out.println(demo.getClass().getName());
}
}
【運(yùn)行結(jié)果】:Reflect.Demo
添加一句:所有類的對象其實(shí)都是Class的實(shí)例。
【案例2】實(shí)例化Class類對象
package Reflect;
class Demo{
//other codes...
}
class hello{
public static void main(String[] args) {
Class<?> demo1=null;
Class<?> demo2=null;
Class<?> demo3=null;
try{
//一般盡量采用這種形式
demo1=Class.forName("Reflect.Demo");
}catch(Exception e){
e.printStackTrace();
}
demo2=new Demo().getClass();
demo3=Demo.class;
System.out.println("類名稱 "+demo1.getName());
System.out.println("類名稱 "+demo2.getName());
System.out.println("類名稱 "+demo3.getName());
}
}
【運(yùn)行結(jié)果】:
類名稱 Reflect.Demo
類名稱 Reflect.Demo
類名稱 Reflect.Demo
【案例3】通過Class實(shí)例化其他類的對象
通過無參構(gòu)造實(shí)例化對象
public Person(String name, int age) {
this.age=age;
this.name=name;
}
然后繼續(xù)運(yùn)行上面的程序,會(huì)出現(xiàn):

所以大家以后再編寫使用Class實(shí)例化其他類的對象的時(shí)候,一定要自己定義無參的構(gòu)造函數(shù)
【案例】通過Class調(diào)用其他類中的構(gòu)造函數(shù) (也可以通過這種方式通過Class創(chuàng)建其他類的對象)
package Reflect;
import java.lang.reflect.Constructor;
class Person{
public Person() {
}
public Person(String name){
this.name=name;
}
public Person(int age){
this.age=age;
}
public Person(String name, int age) {
this.age=age;
this.name=name;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString(){
return "["+this.name+" "+this.age+"]";
}
private String name;
private int age;
}
class hello{
public static void main(String[] args) {
Class<?> demo=null;
try{
demo=Class.forName("Reflect.Person");
}catch (Exception e) {
e.printStackTrace();
}
Person per1=null;
Person per2=null;
Person per3=null;
Person per4=null;
//取得全部的構(gòu)造函數(shù)
Constructor<?> cons[]=demo.getConstructors();
try{
per1=(Person)cons[0].newInstance();
per2=(Person)cons[1].newInstance("Rollen");
per3=(Person)cons[2].newInstance(20);
per4=(Person)cons[3].newInstance("Rollen",20);
}catch(Exception e){
e.printStackTrace();
}
System.out.println(per1);
System.out.println(per2);
System.out.println(per3);
System.out.println(per4);
}
}
【運(yùn)行結(jié)果】:
[null 0]
[Rollen 0]
[null 20]
[Rollen 20]
【案例】
返回一個(gè)類實(shí)現(xiàn)的接口:
package Reflect;
interface China{
public static final String name="Rollen";
public static int age=20;
public void sayChina();
public void sayHello(String name, int age);
}
class Person implements China{
public Person() {
}
public Person(String sex){
this.sex=sex;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public void sayChina(){
System.out.println("hello ,china");
}
@Override
public void sayHello(String name, int age){
System.out.println(name+" "+age);
}
private String sex;
}
class hello{
public static void main(String[] args) {
Class<?> demo=null;
try{
demo=Class.forName("Reflect.Person");
}catch (Exception e) {
e.printStackTrace();
}
//保存所有的接口
Class<?> intes[]=demo.getInterfaces();
for (int i = 0; i < intes.length; i++) {
System.out.println("實(shí)現(xiàn)的接口 "+intes[i].getName());
}
}
}
【運(yùn)行結(jié)果】:
實(shí)現(xiàn)的接口 Reflect.China
(注意,以下幾個(gè)例子,都會(huì)用到這個(gè)例子的Person類,所以為節(jié)省篇幅,此處不再粘貼Person的代碼部分,只粘貼主類hello的代碼)
【案例】:取得其他類中的父類
class hello{
public static void main(String[] args) {
Class<?> demo=null;
try{
demo=Class.forName("Reflect.Person");
}catch (Exception e) {
e.printStackTrace();
}
//取得父類
Class<?> temp=demo.getSuperclass();
System.out.println("繼承的父類為: "+temp.getName());
}
}
【運(yùn)行結(jié)果】
繼承的父類為: java.lang.Object
【案例】:獲得其他類中的全部構(gòu)造函數(shù)
這個(gè)例子需要在程序開頭添加import java.lang.reflect.*;
然后將主類編寫為:
class hello{
public static void main(String[] args) {
Class<?> demo=null;
try{
demo=Class.forName("Reflect.Person");
}catch (Exception e) {
e.printStackTrace();
}
Constructor<?>cons[]=demo.getConstructors();
for (int i = 0; i < cons.length; i++) {
System.out.println("構(gòu)造方法: "+cons[i]);
}
}
}
【運(yùn)行結(jié)果】:
構(gòu)造方法: public Reflect.Person()
構(gòu)造方法: public Reflect.Person(java.lang.String)
但是細(xì)心的讀者會(huì)發(fā)現(xiàn),上面的構(gòu)造函數(shù)沒有public 或者private這一類的修飾符
下面這個(gè)例子我們就來獲取修飾符
class hello{
public static void main(String[] args) {
Class<?> demo=null;
try{
demo=Class.forName("Reflect.Person");
}catch (Exception e) {
e.printStackTrace();
}
Constructor<?>cons[]=demo.getConstructors();
for (int i = 0; i < cons.length; i++) {
Class<?> p[]=cons[i].getParameterTypes();
System.out.print("構(gòu)造方法: ");
int mo=cons[i].getModifiers();
System.out.print(Modifier.toString(mo)+" ");
System.out.print(cons[i].getName());
System.out.print("(");
for(int j=0;j<p.length;++j){
System.out.print(p[j].getName()+" arg"+i);
if(j<p.length-1){
System.out.print(",");
}
}
System.out.println("){}");
}
}
}
【運(yùn)行結(jié)果】:
構(gòu)造方法: public Reflect.Person(){}
構(gòu)造方法: public Reflect.Person(java.lang.String arg1){}
有時(shí)候一個(gè)方法可能還有異常,呵呵。下面看看:
class hello{
public static void main(String[] args) {
Class<?> demo=null;
try{
demo=Class.forName("Reflect.Person");
}catch (Exception e) {
e.printStackTrace();
}
Method method[]=demo.getMethods();
for(int i=0;i<method.length;++i){
Class<?> returnType=method[i].getReturnType();
Class<?> para[]=method[i].getParameterTypes();
int temp=method[i].getModifiers();
System.out.print(Modifier.toString(temp)+" ");
System.out.print(returnType.getName()+" ");
System.out.print(method[i].getName()+" ");
System.out.print("(");
for(int j=0;j<para.length;++j){
System.out.print(para[j].getName()+" "+"arg"+j);
if(j<para.length-1){
System.out.print(",");
}
}
Class<?> exce[]=method[i].getExceptionTypes();
if(exce.length>0){
System.out.print(") throws ");
for(int k=0;k<exce.length;++k){
System.out.print(exce[k].getName()+" ");
if(k<exce.length-1){
System.out.print(",");
}
}
}else{
System.out.print(")");
}
System.out.println();
}
}
}

【案例】接下來讓我們?nèi)〉闷渌惖娜繉傩园?,最后我講這些整理在一起,也就是通過class取得一個(gè)類的全部框架
class hello {
public static void main(String[] args) {
Class<?> demo = null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("===============本類屬性========================");
// 取得本類的全部屬性
Field[] field = demo.getDeclaredFields();
for (int i = 0; i < field.length; i++) {
// 權(quán)限修飾符
int mo = field[i].getModifiers();
String priv = Modifier.toString(mo);
// 屬性類型
Class<?> type = field[i].getType();
System.out.println(priv + " " + type.getName() + " "
+ field[i].getName() + ";");
}
System.out.println("===============實(shí)現(xiàn)的接口或者父類的屬性========================");
// 取得實(shí)現(xiàn)的接口或者父類的屬性
Field[] filed1 = demo.getFields();
for (int j = 0; j < filed1.length; j++) {
// 權(quán)限修飾符
int mo = filed1[j].getModifiers();
String priv = Modifier.toString(mo);
// 屬性類型
Class<?> type = filed1[j].getType();
System.out.println(priv + " " + type.getName() + " "
+ filed1[j].getName() + ";");
}
}
}
【運(yùn)行結(jié)果】:
===============本類屬性========================
private java.lang.String sex;
===============實(shí)現(xiàn)的接口或者父類的屬性========================
public static final java.lang.String name;
public static final int age;
【案例】其實(shí)還可以通過反射調(diào)用其他類中的方法:
class hello {
public static void main(String[] args) {
Class<?> demo = null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
try{
//調(diào)用Person類中的sayChina方法
Method method=demo.getMethod("sayChina");
method.invoke(demo.newInstance());
//調(diào)用Person的sayHello方法
method=demo.getMethod("sayHello", String.class,int.class);
method.invoke(demo.newInstance(),"Rollen",20);
}catch (Exception e) {
e.printStackTrace();
}
}
}
【運(yùn)行結(jié)果】:
hello ,china
Rollen 20
【案例】調(diào)用其他類的set和get方法
class hello {
public static void main(String[] args) {
Class<?> demo = null;
Object obj=null;
try {
demo = Class.forName("Reflect.Person");
} catch (Exception e) {
e.printStackTrace();
}
try{
obj=demo.newInstance();
}catch (Exception e) {
e.printStackTrace();
}
setter(obj,"Sex","男",String.class);
getter(obj,"Sex");
}
/**
* @param obj
* 操作的對象
* @param att
* 操作的屬性
* */
public static void getter(Object obj, String att) {
try {
Method method = obj.getClass().getMethod("get" + att);
System.out.println(method.invoke(obj));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @param obj
* 操作的對象
* @param att
* 操作的屬性
* @param value
* 設(shè)置的值
* @param type
* 參數(shù)的屬性
* */
public static void setter(Object obj, String att, Object value,
Class<?> type) {
try {
Method method = obj.getClass().getMethod("set" + att, type);
method.invoke(obj, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}// end class
【運(yùn)行結(jié)果】:
男
【案例】通過反射操作屬性
class hello {
public static void main(String[] args) throws Exception {
Class<?> demo = null;
Object obj = null;
demo = Class.forName("Reflect.Person");
obj = demo.newInstance();
Field field = demo.getDeclaredField("sex");
field.setAccessible(true);
field.set(obj, "男");
System.out.println(field.get(obj));
}
}// end class
【案例】通過反射取得并修改數(shù)組的信息:
import java.lang.reflect.*;
class hello{
public static void main(String[] args) {
int[] temp={1,2,3,4,5};
Class<?>demo=temp.getClass().getComponentType();
System.out.println("數(shù)組類型: "+demo.getName());
System.out.println("數(shù)組長度 "+Array.getLength(temp));
System.out.println("數(shù)組的第一個(gè)元素: "+Array.get(temp, 0));
Array.set(temp, 0, 100);
System.out.println("修改之后數(shù)組第一個(gè)元素為: "+Array.get(temp, 0));
}
}
【運(yùn)行結(jié)果】:
數(shù)組類型: int
數(shù)組長度 5
數(shù)組的第一個(gè)元素: 1
修改之后數(shù)組第一個(gè)元素為: 100
【案例】通過反射修改數(shù)組大小
class hello{
public static void main(String[] args) {
int[] temp={1,2,3,4,5,6,7,8,9};
int[] newTemp=(int[])arrayInc(temp,15);
print(newTemp);
System.out.println("=====================");
String[] atr={"a","b","c"};
String[] str1=(String[])arrayInc(atr,8);
print(str1);
}
/**
* 修改數(shù)組大小
* */
public static Object arrayInc(Object obj,int len){
Class<?>arr=obj.getClass().getComponentType();
Object newArr=Array.newInstance(arr, len);
int co=Array.getLength(obj);
System.arraycopy(obj, 0, newArr, 0, co);
return newArr;
}
/**
* 打印
* */
public static void print(Object obj){
Class<?>c=obj.getClass();
if(!c.isArray()){
return;
}
System.out.println("數(shù)組長度為: "+Array.getLength(obj));
for (int i = 0; i < Array.getLength(obj); i++) {
System.out.print(Array.get(obj, i)+" ");
}
}
}
【運(yùn)行結(jié)果】:
數(shù)組長度為: 15
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
數(shù)組長度為: 8
a b c null null null null null
動(dòng)態(tài)代理
【案例】首先來看看如何獲得類加載器:
class test{
}
class hello{
public static void main(String[] args) {
test t=new test();
System.out.println("類加載器 "+t.getClass().getClassLoader().getClass().getName());
}
}
【程序輸出】:
類加載器 sun.misc.Launcher$AppClassLoader
其實(shí)在java中有三種類類加載器。
1)Bootstrap ClassLoader 此加載器采用c++編寫,一般開發(fā)中很少見。
2)Extension ClassLoader 用來進(jìn)行擴(kuò)展類的加載,一般對應(yīng)的是jre\lib\ext目錄中的類
3)AppClassLoader 加載classpath指定的類,是最常用的加載器。同時(shí)也是java中默認(rèn)的加載器。
如果想要完成動(dòng)態(tài)代理,首先需要定義一個(gè)InvocationHandler接口的子類,已完成代理的具體操作。
package Reflect;
import java.lang.reflect.*;
//定義項(xiàng)目接口
interface Subject {
public String say(String name, int age);
}
// 定義真實(shí)項(xiàng)目
class RealSubject implements Subject {
@Override
public String say(String name, int age) {
return name + " " + age;
}
}
class MyInvocationHandler implements InvocationHandler {
private Object obj = null;
public Object bind(Object obj) {
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object temp = method.invoke(this.obj, args);
return temp;
}
}
class hello {
public static void main(String[] args) {
MyInvocationHandler demo = new MyInvocationHandler();
Subject sub = (Subject) demo.bind(new RealSubject());
String info = sub.say("Rollen", 20);
System.out.println(info);
}
}
【運(yùn)行結(jié)果】:
Rollen 20
類的生命周期
在一個(gè)類編譯完成之后,下一步就需要開始使用類,如果要使用一個(gè)類,肯定離不開JVM。在程序執(zhí)行中JVM通過裝載,鏈接,初始化這3個(gè)步驟完成。
類的裝載是通過類加載器完成的,加載器將.class文件的二進(jìn)制文件裝入JVM的方法區(qū),并且在堆區(qū)創(chuàng)建描述這個(gè)類的java.lang.Class對象。用來封裝數(shù)據(jù)。 但是同一個(gè)類只會(huì)被類裝載器裝載以前
鏈接就是把二進(jìn)制數(shù)據(jù)組裝為可以運(yùn)行的狀態(tài)。
鏈接分為校驗(yàn),準(zhǔn)備,解析這3個(gè)階段
校驗(yàn)一般用來確認(rèn)此二進(jìn)制文件是否適合當(dāng)前的JVM(版本),
準(zhǔn)備就是為靜態(tài)成員分配內(nèi)存空間,。并設(shè)置默認(rèn)值
解析指的是轉(zhuǎn)換常量池中的代碼作為直接引用的過程,直到所有的符號(hào)引用都可以被運(yùn)行程序使用(建立完整的對應(yīng)關(guān)系)
完成之后,類型也就完成了初始化,初始化之后類的對象就可以正常使用了,直到一個(gè)對象不再使用之后,將被垃圾回收。釋放空間。
當(dāng)沒有任何引用指向Class對象時(shí)就會(huì)被卸載,結(jié)束類的生命周期
將反射用于工廠模式
先來看看,如果不用反射的時(shí)候,的工廠模式吧:
/**
* @author Rollen-Holt 設(shè)計(jì)模式之 工廠模式
*/
interface fruit{
public abstract void eat();
}
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
// 構(gòu)造工廠類
// 也就是說以后如果我們在添加其他的實(shí)例的時(shí)候只需要修改工廠類就行了
class Factory{
public static fruit getInstance(String fruitName){
fruit f=null;
if("Apple".equals(fruitName)){
f=new Apple();
}
if("Orange".equals(fruitName)){
f=new Orange();
}
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance("Orange");
f.eat();
}
}
這樣,當(dāng)我們在添加一個(gè)子類的時(shí)候,就需要修改工廠類了。如果我們添加太多的子類的時(shí)候,改的就會(huì)很多。
現(xiàn)在我們看看利用反射機(jī)制:
package Reflect;
interface fruit{
public abstract void eat();
}
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
class Factory{
public static fruit getInstance(String ClassName){
fruit f=null;
try{
f=(fruit)Class.forName(ClassName).newInstance();
}catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class hello{
public static void main(String[] a){
fruit f=Factory.getInstance("Reflect.Apple");
if(f!=null){
f.eat();
}
}
}
現(xiàn)在就算我們添加任意多個(gè)子類的時(shí)候,工廠類就不需要修改。
上面的愛嗎雖然可以通過反射取得接口的實(shí)例,但是需要傳入完整的包和類名。而且用戶也無法知道一個(gè)接口有多少個(gè)可以使用的子類,所以我們通過屬性文件的形式配置所需要的子類。
下面我們來看看: 結(jié)合屬性文件的工廠模式
首先創(chuàng)建一個(gè)fruit.properties的資源文件,
內(nèi)容為:
apple=Reflect.Apple orange=Reflect.Orange
然后編寫主類代碼:
package Reflect;
import java.io.*;
import java.util.*;
interface fruit{
public abstract void eat();
}
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
//操作屬性文件類
class init{
public static Properties getPro() throws FileNotFoundException, IOException{
Properties pro=new Properties();
File f=new File("fruit.properties");
if(f.exists()){
pro.load(new FileInputStream(f));
}else{
pro.setProperty("apple", "Reflect.Apple");
pro.setProperty("orange", "Reflect.Orange");
pro.store(new FileOutputStream(f), "FRUIT CLASS");
}
return pro;
}
}
class Factory{
public static fruit getInstance(String ClassName){
fruit f=null;
try{
f=(fruit)Class.forName(ClassName).newInstance();
}catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class hello{
public static void main(String[] a) throws FileNotFoundException, IOException{
Properties pro=init.getPro();
fruit f=Factory.getInstance(pro.getProperty("apple"));
if(f!=null){
f.eat();
}
}
}
以上這篇java反射深入剖析(推薦)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot如何根據(jù)用戶系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間
這篇文章主要介紹了SpringBoot如何根據(jù)用戶系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
springcloud中Ribbon和RestTemplate實(shí)現(xiàn)服務(wù)調(diào)用與負(fù)載均衡
這篇文章主要介紹了Ribbon和RestTemplate實(shí)現(xiàn)服務(wù)調(diào)用與負(fù)載均衡,想了解負(fù)載均衡的同學(xué)可以參考下2021-04-04
Spring學(xué)習(xí)筆記1之IOC詳解盡量使用注解以及java代碼
這篇文章主要介紹了Spring學(xué)習(xí)筆記1之IOC詳解盡量使用注解以及java代碼 的相關(guān)資料,需要的朋友可以參考下2016-07-07
基于Java方式實(shí)現(xiàn)數(shù)據(jù)同步
這篇文章主要為大家詳細(xì)介紹了基于Java方式實(shí)現(xiàn)數(shù)據(jù)同步,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
Spring事件發(fā)布監(jiān)聽,順序監(jiān)聽,異步監(jiān)聽方式
這篇文章主要介紹了Spring事件發(fā)布監(jiān)聽,順序監(jiān)聽,異步監(jiān)聽方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Java 仿天貓服裝商城系統(tǒng)的實(shí)現(xiàn)流程
讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+jsp+mysql+maven實(shí)現(xiàn)一個(gè)仿天貓服裝商城系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11
java基于jcifs.smb實(shí)現(xiàn)遠(yuǎn)程發(fā)送文件到服務(wù)器
這篇文章主要介紹了java基于jcifs.smb實(shí)現(xiàn)遠(yuǎn)程發(fā)送文件到服務(wù)器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01

