1. 程式人生 > >JAVA反射使用例項和class.getResource()得到URL中含有中文和空格亂碼問題

JAVA反射使用例項和class.getResource()得到URL中含有中文和空格亂碼問題

JAVA反射使用例項

package invoke;

import java.lang.reflect.Method;

public class T1 {
 public static void main(String[] args) throws Exception {
  // 1.普通方法反射--invoke.T3類全路徑
  // new Class[]{String.class,String.class}等同String.class, String.class
  Method method = Class.forName("invoke.T3").getMethod("toStr",
    String.class, String.class);

  // new Object[]{"123","456"}等同"123", "456"
  Object o = method.invoke(T3.class.newInstance(), "123", "456");
  System.out.println("return:" + o.toString());
  // 直接呼叫
  T3.class.newInstance().toStr("aaaaaaaa", "bbbb");

  // 1.帶陣列的方法反射
  Method method1 = Class.forName("invoke.T3").getMethod("toStr",
    String[].class, int.class);
  Object obj = method1.invoke(T3.class.newInstance(), new String[] {
    "aa", "bb" }, 99);
  System.out.println("method1 return:" + obj);

  Method method2 = Class.forName("invoke.T3").getMethod("toStr",
    new Class[] { String[].class, int.class });
  method2.invoke(T3.class.newInstance(), new Object[] {
    new String[] { "cc", "dd" }, 999 });

  Method[] ms = Class.forName("invoke.T3").getMethods();
  for (Method method3 : ms) {
   System.out.println("method name:" + method3.getName());
   if (method3.getName().equals("toStr")) {
    method3.invoke(T3.class.newInstance(), "123", "456");
   }
  }
 }
}

class T3 {
 public T3() {
  System.out.println("**T3()***");
 }

 public String toStr(String s, String s1) {
  System.out.println(s + s1);
  return s + s1;
 }

 public String toStr(String[] ss, int i) {
  StringBuffer sb = new StringBuffer();
  for (int j = 0; j < ss.length; j++) {
   sb.append(" " + ss[j]);
  }
  System.out.print("String[]:" + sb.toString() + " i:" + i);

  return sb.append(i).toString();
 }
}

得到有引數構造方法的物件例項.
1.如T3有這樣的構造器
public T3(int id,String name,String password)
2.得到例項--通過有參構造器得到
T3 t3=T3.class.getConstructor(int.class,String.class,String.class).newInstance(1,"admin","admin");

getMethod(String name, Class<?>... parameterTypes)
返回一個 Method 物件,它反映此 Class 物件所表示的類或介面的指定公共成員方法。--這個只能得到公共方法.
getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一個 Method 物件,該物件反映此 Class 物件所表示的類或介面的指定已宣告方法。--這個可以得到所有定義的方法.
通過反射呼叫私用方法時要加上mothod.setAccessible(true);
其它得到欄位/構造器/類等也是一樣的.

射的基石——Class

如何得到位元組碼檔案的例項物件?

有三種方式:

類名.class 如:System.class

物件.getClass() 如:new Date().getClass();

Class.forName(" 類名") 如:Class.forName(" java.util.Date");

程式碼:

package com.hncu.day1;

import java.util.Date;


public class GetClass  {

 public static void main(String[] args) throws Exception{
  Class c1 = Date.class;//Date類的位元組碼檔案 他是一個Class型別的例項物件,
  GetClass gc = new GetClass();
  gc.getClass();
  
  System.out.println(gc.getClass());
  System.out.println(c1);
  System.out.println(Class.forName("com.hncu.day1.GetClass"));
 }

}

陣列型別的Class例項物件:

Class.isArray();

System.out.println(int[].class.isArray());//true

反射:

就是把java中的各種成分對映成相應的java類。

一個類中的組成成分:成員變數,方法,構造方法,包等資訊,也用一個個的java類來表示。

一個類中的的每個成員都已用相應的反射API類的一個實力物件來表示,通過呼叫Class累的方法可以得到這些例項物件後,得到例項物件後怎麼用是學習反射的要點.

Constructor類代表某個類的一個構造方法。

得到某個類的所有構造方法:

Constructor[] constructor = Class.forName("java.lang.String").getConstructor();

得到某一個構造方法:

Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);//得到StringBuffer類的建構函式

例項物件:

普通方式:String str = new String( new StringBuffer("abc"));

反射方式:

Constructor constructor = String.class.getConstructor(StringBuffer.class);

String str = (String)constructor.newInstance(new StringBuffer("abc"));

Filed 

Filed 類代表某個類中的一個成員變數。

import java.lang.reflect.Field;

public class ReflectDemo {
 private int x;
 public int y;

 public ReflectDemo(int x, int y) {
  this.x = x;
  this.y = y;
 }

 public static void main(String[] args) throws Exception {
  ReflectDemo rd = new ReflectDemo(3, 8);
  ReflectDemo rd1 = new ReflectDemo(4, 9);
  
  Field fieldX = rd.getClass().getDeclaredField("x");// 得到類中私有x的定義。
  Field fieldY = rd.getClass().getField("y");// 得到類中y的定義。

  System.out.println(fieldY.get(rd));// 得到rd物件y的值
  System.out.println(fieldY.get(rd1));// 得到rd1物件的y值

  
  fieldX.setAccessible(true);// 將fieldX設定為可見。
  System.out.println(fieldX.get(rd));// 得到rd物件中x的值
 }
}

利用反射獲取String 型別的成員變數後,修改字串中的字元。

import java.lang.reflect.Field;

public class ReflectDemo {

 Private String str1 = "reflect";
 Private String str2 = "reflectdemo";

 public static void main(String[] args) throws Exception {

  ReflectDemo rd = new ReflectDemo();
  changeValue(rd);
 }

 private static void changeValue(Object obj) throws Exception {
  Field[] fields = obj.getClass().getDeclaredFields();//獲取所有定義的成員變數
  for (Field field : fields) {
   if (field.getType() == String.class) {// 位元組碼使用== 使用的是一份位元組碼
    String oldValue = (String) field.get(obj);
    String newValue = oldValue.replace('r', 'R');
    field.set(obj, newValue);
   }
  }
  System.out.println(obj);
 }

 // 重寫toString方法
 public String toString() {
  return str1 + " " + str2;
 }
}

Method

代表某個類中的一個成員方法

得到類中的一個方法:

:Class.forName("java.lang.String").getMethod("charAt",int.class)

呼叫方法:

ü 普通方式:

str物件來呼叫,str.charAt(1);

ü 反射方式:

Method m =String.class.getMethod("charAt"int.class);

System.out.println(m.invoke(str1, 1));//為str1這個物件呼叫charAt方法引數為1,列印“r”,Str1 這個物件要用靜態修飾。

如果invoke方法的第一個引數為null ,表示該Method物件對應的是一個靜態方法。

(重點理解)接受陣列引數的成員方法進行反射:

import java.lang.reflect.Method;

 public class ReflectDemo2 {

 public static void main(String[] args) throws Exception {
  String startClassName = args[0];
  Method mainMethod = Class.forName(startClassName).getMethod("main", String[].class);
  mainMethod.invoke(null,new Object[]{new String[]{"hncu","nihao"}});
  //ReflectTest.maint(new String[]{"dkj","kdfj"});
  
 }

}
  class ReflectTest {
  public static void main(String[] args) {
   for(String s : args) {
    System.out.println(s);
   }
  }
 }

列印結果:

hncu
nihao

解決通過this.class.getResource()得到的URL中含有中文和空格亂碼問題

 ClassLoader的getResource方法使用了utf-8對路徑資訊進行了編碼,當路徑中存在中文和空格時,他會對這些字元進行轉換,這樣,得到的往往不是我們想要的真實路徑,在此,呼叫了URLDecoder的decode方法進行解碼,以便得到原始的中文及空格路徑

例如:結果是file:/C:/Documents%20and%20Settings/%e5%ba%84%e6%99%93%e6%af%85  
  /Local%20Settings/Temp/temp0.jar!/db/dmozdata.mdb  

而我們期望是 C:/Documents andsettigsd sdfsdfsdf sdfsdf sdfsd 等等

這裡我們只要在獲取到的例如: String configPath = this.getClass().getClassLoader().getResource("allowPath.xml").getFile();

把返回前decode下就可以了. 用utf-8編碼. 

Java程式碼
  1. configPath = java.net.URLDecoder.decode(configPath,"utf-8");