java反射的深入(二)
通过反射调用类的方法
在正常情况下一个类的对象功能产生之后,就可以直接调用类中的方法了,若想要调用,则必须知道方法名称,之后用Class类中的 getMethod()方法 ,
public Method getMethod(String name ,Class<?> … parameterTypes)
然后invoke(Method对象)来执行方法,
接上例:
package com.java.reflect;
import java.lang.reflect.Method;
public class InvokesayChinaDemo {
public static void main(String[] args) {
Class<?> c1 = null;
try {
c1 = Class.forName("com.java.reflect.PersonDemo1");// 实例化对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
Method met = c1.getMethod("sayChina");// 找到sayChina方法
met.invoke(c1.newInstance());// 调用方法
} catch (Exception e) {
e.printStackTrace();
}
}
}
通过Class类的getMethod()方法根据一个类中的方法名称可以取得Method对象,并通过invoke调用指定的方法,但是在使用invoke()方法的时候必须传入一个类的实例化对象,因为在sayChina()方法上没有任何的参数,所以没有设定参数类型和参数内容。
改进后:
package com.java.reflect;
import java.lang.reflect.Method;
public class InvokesayChinaDemo {
public static void main(String[] args) {
Class<?> c1 = null;
try {
c1 = Class.forName("com.java.reflect.PersonDemo1");// 实例化Class对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
Method met = c1.getMethod("sayChina");// 找到sayChina方法
met.invoke(c1.newInstance());// 调用方法
Method meth = c1.getMethod("sayHello", String.class, int.class);
String rv = null;
rv = (String) meth.invoke(c1.newInstance(), "汪兵", 25);//调用方法
System.out.println(rv);
} catch (Exception e) {
e.printStackTrace();
}
}
}
通过反射调用类setter和getter
package com.java.reflect;
import java.lang.reflect.Method;
public class InvokeSetterGetterDemo {
public static void main(String[] args) {
Class<?> c1 = null;
Object obj = null;
try {
c1 = Class.forName("com.java.reflect.PersonDemo1");// 实例化Class对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
obj = c1.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
setter(obj, "name", "李兴华", String.class);// 设置setter方法
setter(obj, "age", 25, int.class);// 设置setter方法
System.out.println("年龄:");
getter(obj, "age");
System.out.println("姓名:");
getter(obj, "name");
}
public static void getter(Object obj, String att) {
try {
Method met = obj.getClass().getMethod("get" + initStr(att));
System.out.println(met.invoke(obj));// 调出getter的内容
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Object obj:要操作的对象 String att:要操作的属性 Object value:设置属性值
* Class<?>type:设置属性类型
*/
public static void setter(Object obj, String att, Object value,
Class<?> type) {
Method met = null;
try {
met = obj.getClass().getMethod("set" + initStr(att), type);// 得到setter方法
// 设置setter内容
met.invoke(obj, value);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String initStr(String old) {// 将单词的首字母大写
String str = old.substring(0, 1).toUpperCase() + old.substring(1);
return str;
}
}
通过反射调用属性
如果现在假设要操作一个类中的属性,则也可以通过Filed完成,而不必麻烦的通过setter和getter方法
得到公共属性:
public Field getField (String name )
得到本类属性:
public Field getDeclaredField (String name )
取得属性内容:
public Object get(Object obj)
设置属性内容:
public void set(object obj,object value)
package com.java.reflect;
import java.lang.reflect.Field;
public class InvokeFieldDemo {
public static void main(String[] args) {
Class<?> c1 = null;
Object obj = null;
try {
c1 = Class.forName("com.java.reflect.PersonDemo1");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
obj = c1.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Field nameField = null;
Field ageField = null;
try {
nameField = c1.getDeclaredField("name");
ageField = c1.getDeclaredField("age");
nameField.setAccessible(true);// 设置私有属性可见
ageField.setAccessible(true);
nameField.set(obj, "sdfsdfsd");
ageField.set(obj, 23);
System.out.println("姓名:" + nameField.get(obj));
System.out.println("年龄" + ageField.get(obj));
} catch (NoSuchFieldException | SecurityException
| IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
通过反射操作数组
反射机制不光只使用在类中,也可以应用在任意的引用数据类型上,当然包含了数组,数组使用Array类完成
public Class<?> getComponentType()
得到数组指定下标的内容:
public static Object get(Object array,
int index)
throws IllegalArgumentException,
ArrayIndexOutOfBoundsException
public static void set(Object array,
int index,
boolean z)
throws IllegalArgumentException,
ArrayIndexOutOfBoundsException
开辟新的数组:
public static Object newInstance(Class<?> componentType,
int... dimensions)
throws IllegalArgumentException,
NegativeArraySizeException
取得数组的内容:
package com.java.reflect;
import java.lang.reflect.Array;
public class ClassArrayDemo {
public static void main(String[] args) {
int temp[] = { 1, 2, 3 };
Class<?> c = temp.getClass().getComponentType();// 取得数组的Class对象
System.out.println("类型:" + c.getName());// 取得数组类型的名称
System.out.println("长度:" + Array.getLength(temp));
System.out.println("第一个内容是:" + Array.getInt(temp, 1));// 得到第一个数组的内容
Array.set(temp, 2, 20);
System.out.println(temp[2]);
}
}
使用Array类还可以修改数组的大小:(实际上就是新建一个新的数组,将旧的数据复制进去)
package com.java.reflect;
import java.lang.reflect.Array;
public class ChangeArrayDemo {
public static void main(String[] args) {
int temp[] = { 1, 2, 3 };
int newTemp[] = (int[]) arrayInc(temp, 5);// 重新开辟空间
print(newTemp);
}
public static Object arrayInc(Object obj, int len) {// 建立新的数组并拷贝
Class<?> c = obj.getClass();
Class<?> arr = c.getComponentType();// 得到数组的Class
Object newO = Array.newInstance(arr, len);// 拷贝内容
int co = Array.getLength(obj);
System.arraycopy(obj, 0, newO, 0, co);// 拷贝数组
return newO;
}
public static void print(Object obj) {// 数组输出
Class<?> c = obj.getClass();
if (!c.isArray()) {// 判断是否是数组
return;
}
Class<?> arr = c.getComponentType();
System.out.println(arr.getName() + "数组长度是:" + Array.getLength(obj));
for (int i = 0; i < Array.getLength(obj); i++) {
System.out.print(Array.get(obj, i) + "、");// 通过Array输出
}
}
}
代理设计:
一个操作的接口有两个子类,其中一个是真是主题的实现类,另一个是代理类,代理实现类要完成比真实主体实现类更多的内容,而且本身还需要处理一些与具体业务有关的程序代码。
package com.java.reflect;
interface Subject {
public String say(String name, int age);
}
class RealSubject implements Subject {
@Override
public String say(String name, int age) {
return "姓名:" + name + ",年龄:" + age;
}
}
class ProxySubject implements Subject {
private Subject sub = null;
public ProxySubject(Subject sub) {
this.sub = sub;
}
@Override
public String say(String name, int age) {
return this.sub.say(name, age);
}
}
public class DyProxyDemo {
public static void main(String[] args) {
Subject sub = new ProxySubject(new RealSubject());
String info = sub.say("李兴华", 99);
System.out.println(info);
}
}
以上代码称为静态代理,一个代理只能为一个接口服务,
InvocationHandler接口:
public interface InvocationHandler{
Object invoke(Object proxy,
Method method,
Object[] args)
throws Throwable
}
Object proxy:被代理的接口
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject
Proxy类
是专门完成代理的操作类,可以通过此类为一个或者多个接口动态地生成实现类,此类提供如下的方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 得到的InvocationHandle接口子类实例
类加载器:
图1
工厂设计模式:
实例:
package com.java.reflect;
interface Fruit {
public void eat();
}
class Apple implements Fruit {
public void eat() {
System.out.println("eat apple");
}
}
class Orange implements Fruit {
public void eat() {
System.out.println("eat orange");
}
}
// 工厂类
class Factory {
public static Fruit getInstance(String className) {
Fruit fruit = null;
fruit = null;
if ("apple".equals(className)) {
fruit = new Apple();
}
if ("orange".equals(className)) {
fruit = new Apple();
}
return fruit;
}
}
public class FactoryDemo01 {
public static void main(String[] args) {
Fruit f = Factory.getInstance("apple");
if (f != null) {
f.eat();
}
}
}
如果扩充了一个子类,则肯定要修改工厂类,如果希望扩充子类时不用修改工厂类的话,则必须使用反射完成。
例子:
package com.java.reflect;
interface Fruit {
public void eat();
}
class Apple implements Fruit {
public void eat() {
System.out.println("eat apple");
}
}
class Orange implements Fruit {
public void eat() {
System.out.println("eat orange");
}
}
// 工厂类
class Factory {
public static Fruit getInstance(String className) {
Fruit fruit = null;
/**
* if ("apple".equals(className)) { fruit = new Apple(); }
*
* if ("orange".equals(className)) { fruit = new Apple(); } return
* fruit; }
*/
try { fruit = (Fruit) Class.forName(className).newInstance(); } catch (Exception e) { e.printStackTrace(); } return fruit; }
}
public class FactoryDemo01 {
public static void main(String[] args) {
Fruit f = Factory.getInstance("com.java.reflect.Apple");
if (f != null) {
f.eat();
}
}
}
以上在扩充子类时,不用修改工厂类,但是输入完整的“包.类”名称,比较麻烦,此时可以通过一些拍之文件的方式保存这些完整的类的路径。
图2
package com.java.reflectFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
interface Fruit {
public void eat();
}
class Apple implements Fruit {
public void eat() {
System.out.println("eat apple");
}
}
class Orange implements Fruit {
public void eat() {
System.out.println("eat orange");
}
}
class Init {
public static Properties getPro() {
Properties pro = new Properties();
File f = new File("F:/JAVA深入学习/fruit.properties");// 找到属性文件
/**
* 配置文件的内容 apple =com.java.reflectFactory.Apple
* orange=com.java.reflectFactory.Orange
* */
if (f.exists()) {// 如果文件存在
try {
pro.load(new FileInputStream(f));
} catch (IOException e) {
e.printStackTrace();
}
} else {
pro.setProperty("apple", "com.java.reflectFactory.Apple");
pro.setProperty("orage", "com.java.reflectFactory.Orange");
try {
pro.store(new FileOutputStream(f), "FRUIT CLASS");
} catch (IOException e) {
e.printStackTrace();
}
}
return pro;
}
}
// 工厂类
class Factory {
public static Fruit getInstance(String className) {
Fruit fruit = null;
try {
fruit = (Fruit) Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return fruit;
}
}
public class FactoryDemo02 {
public static void main(String[] args) {
Properties pro = Init.getPro();
Fruit f = Factory.getInstance(pro.getProperty("apple"));
if (f != null) {
f.eat();
}
}
}
配置文件与程序相分离的!
还没有评论,来说两句吧...