java反射随意值_Java反射笔记

Java反射

反射库提供了一个丰富且精巧的工具集,可以用来编写能够动态操纵Java代码的程序。能够分析类能力的程序称为反射(reflective)。反射机制的功能极为强大,反射机制可以用来:

在运行时分析类的能力

在运行时检查对象,例如,编写一个适用于所有类的toString方法

实现泛型数组操作代码

利用Method对象

1、Class类

在程序运行期间,Java运行时系统始终为所有对象维护一个运行时类型标识。这个信息会跟踪每个对象所属的类。虚拟机利用运行时类型信息选择要执行的正确的方法。

可以使用一个特殊的Java类访问这些信息。保存这些信息的类名为Class。

三种获得Class类对象的方法:

class.getClass()

Class.forName(className)

class.class

虚拟机为每个类型管理一个唯一的Class对象。因此,可以使用==运算符实现两个类对象的比较。例如,

if(Employee.getClass()==Employee.class)//返回结果为true

如果有一个Class类型的对象,可以用它来构造类的实例。调用getConstructor方法将得到一个Constructor类型的对象,然后使用newInstance方法来构造一个实例。例如:

Class cl = Class.forName("java.util.Random");

Object obj = cl.getConstructor().newInstance;

如果这个类没有无参数的构造器,getConstructor方法会抛出一个异常。

API

java.lang.Class

static Class forName(String className)

返回一个Class对象,表示名为className的类

Constructor getConstructor(Class... paramterTypes)

生成一个对象,描述有指定参数类型的构造器

java.lang.reflect.Constructor

Object newInstance(Object... params)

将params传递到构造器,来构造这个构造器声明类的一个新实例

2、资源

类通常有一些关联的数据文件,例如

图像和声音文件

包含消息字符串和按钮标签的文本文件。

Class类提供了一个很有用的服务可以查找资源文件。下面给出必要的步骤:

获得拥有资源的类的Class对象,例如,ResourceTest.class

有些方法,如ImageIcon类的getImage方法,接受描述资源位置URL。则要调用

URL url = class.getResource("about.gif")

否则,使用getResourceAsStream方法得到一个输入流来读取文件中的数据

ResourceTest.java

/**

* 使用反射读取资源

*/

public class ResourceTest {

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

Class cl = ResourceTest.class;

URL url = cl.getResource("about.jpg");

ImageIcon icon = new ImageIcon(url);

InputStream stream = cl.getResourceAsStream("about.txt");//相对路径

byte[] bytes = new byte[1024];

stream.read(bytes);

String about = new String(bytes, "UTF-8");

InputStream stream2 = cl.getResourceAsStream("/com/company/reflection/about.txt");//绝对路径

stream2.read(bytes);

String title = new String(bytes, StandardCharsets.UTF_8).trim();

JOptionPane.showMessageDialog(null,about,title,JOptionPane.INFORMATION_MESSAGE,icon);

}

}

API

java.lang.Class

URL getResource(String name)

InputStream getResourceAsStream(String name)

找到与类位于同一位置的资源,返回一个可以用来加载资源的URL或者输入流。如果没有找到资源,则返回null,所以不会抛出异常或者I/O错误

3、利用反射分析类的能力

在java.lang.reflect包中有三个类Field、Method、Constructor分别用来描述类的字段、方法和构造器。这三个类都有一个叫做getName的方法,用来返回字段、方法或构造器的名称。

Field类有一个getType方法,用来返回描述字段类型的一个对象,这个对象的类型同样是Class。Method和Constructor类有报告参数类型的方法,Method类还有一个报告返回类型的方法。这三个类都有一个名为getModifiers的方法,它将返回一个整数,用不同的0/1位描述所使用的修饰符,如public和static。另外,还可以利用java.lang.reflect包中的Modifier类的静态方法分析getModifiers返回的这个整数。例如,可以使用Modifier类中的isPublic、isPrivate或isFinal判断方法或构造器是public、private还是final。我们需要做的就是在getModifiers返回的整数上调用Modifier类中适当的方法,另外,还可以利用Modifier.toString方法将修饰符打印出来。

ReflectionTest.java

/**

* 使用反射分析类的能力

*/

public class ReflectionTest {

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

String name;

if(args.length>0) name = args[0];

else

{

Scanner in = new Scanner(System.in);

System.out.println("Enter class name (e.g. java.util.Date): ");

name = in.next();

}

Class cl = Class.forName(name);//使用name获取Class

Class supercl = cl.getSuperclass();//获取父类的class

String modifiers = Modifier.toString(cl.getModifiers());//获取修饰符

if(modifiers.length()>0) System.out.print(modifiers+" ");

System.out.print("class "+name);

if(supercl != null && supercl != Object.class) System.out.print(" extends "+supercl.getName());

System.out.print("\n{\n");

printConstructors(cl);

System.out.println();

printMethods(cl);

System.out.println();

printFields(cl);

System.out.println("}");

}

/**

* prints all constructors of a class

*/

public static void printConstructors(Class cl){

Constructor[] constructors = cl.getDeclaredConstructors();//获取全部构造器的数组

for(Constructor c : constructors){//遍历构造器数组

String name = c.getName();//获取构造器的name

System.out.print(" ");

String modifiers = Modifier.toString(c.getModifiers());//获取构造器的修饰符

if(modifiers.length()>0) System.out.print(modifiers+" ");

System.out.print(name+"(");

Class[] parameterTypes = c.getParameterTypes();//获取构造器的参数数组

for(int j = 0; j < parameterTypes.length; j++){//遍历参数数组

if(j>0) System.out.print(", ");//逗号分隔开

System.out.print(parameterTypes[j].getName());//打印参数name

}

System.out.println(");");

}

}

/**

* prints all methods of a class

*/

public static void printMethods(Class cl){

Method[] methods = cl.getDeclaredMethods();

for(Method m : methods){

Class> returnType = m.getReturnType();

String name = m.getName();

System.out.print(" ");

//print modifiers,return type and method name

String modifiers = Modifier.toString(m.getModifiers());

if(modifiers.length()>0) System.out.print(modifiers + " ");

System.out.print(returnType.getName() + " " + name + "(");

//print parameter types

Class[] parameterTypes = m.getParameterTypes();

for(int j = 0; j

if(j>0) System.out.print(", ");

System.out.print(parameterTypes[j].getName());

}

System.out.println(");");

}

}

/**

* prints all fields of a class

*/

public static void printFields(Class cl){

Field[] fields = cl.getDeclaredFields();

for(Field field : fields){

Class type = field.getType();

String name = field.getName();

System.out.print(" ");

String modifiers = Modifier.toString(field.getModifiers());

if(modifiers.length()>0) System.out.print(modifiers + " ");

System.out.println(type.getName() + " "+ name + ";");

}

}

}

输入

java.lang.Double

输出

public final class java.lang.Double extends java.lang.Number

{

public java.lang.Double(double);

public java.lang.Double(java.lang.String);

public boolean equals(java.lang.Object);

public static java.lang.String toString(double);

public java.lang.String toString();

public int hashCode();

public static int hashCode(double);

public static double min(double, double);

public static double max(double, double);

public static native long doubleToRawLongBits(double);

public static long doubleToLongBits(double);

public static native double longBitsToDouble(long);

public volatile int compareTo(java.lang.Object);

public int compareTo(java.lang.Double);

public byte byteValue();

public short shortValue();

public int intValue();

public long longValue();

public float floatValue();

public double doubleValue();

public static java.lang.Double valueOf(java.lang.String);

public static java.lang.Double valueOf(double);

public static java.lang.String toHexString(double);

public static int compare(double, double);

public static boolean isNaN(double);

public boolean isNaN();

public static boolean isFinite(double);

public static boolean isInfinite(double);

public boolean isInfinite();

public static double sum(double, double);

public static double parseDouble(java.lang.String);

public static final double POSITIVE_INFINITY;

public static final double NEGATIVE_INFINITY;

public static final double NaN;

public static final double MAX_VALUE;

public static final double MIN_NORMAL;

public static final double MIN_VALUE;

public static final int MAX_EXPONENT;

public static final int MIN_EXPONENT;

public static final int SIZE;

public static final int BYTES;

public static final java.lang.Class TYPE;

private final double value;

private static final long serialVersionUID;

}

API

java.lang.Class

Field[] getFields()

返回这个类支持的公共字段

Field[] getDeclaredFields()

返回类中声明的全部字段

Method[] getMethods()

返回这个类支持的公共方法

Field[] getDeclaredMethods()

返回类中声明的全部方法

Constructor[] getConstructors()

返回这个类支持的公共构造器

Constructor[] getDeclaredConstructors()

返回类中声明的全部构造器

java.lang.reflect.Field

java.lang.reflect.Method

java.lang.reflect.Constructor

int getModifiers()

返回一个整数,描述这个构造器、方法或字段的修饰符。使用Modifier类中的方法来分析这个返回值

String getName()

返回一个表示构造器名、方法名或字段名的字符串

Class[] getParamterTypes() (在Constructor 和 Method classes 类中)

返回一个Class对象数组,其中各个对象表示参数的类型。

Class getReturnType() (在 Method 类中)

返回一个用于表示返回类型的Class对象

java.lang.reflect.Modifier

static String toString(int modifiers)

返回一个字符串,包含对应modifiers中位设置的修饰符

4、使用反射在运行时分析对象

在编写程序时,如果知道想要查看的字段名和类型,查看对象中指定字段的内容是一件很容易的事情。而利用反射机制可以查看在编译时还不知道的对象字段。

要做到这一点,关键方法时Field类中的get方法。如果f是一个Field类型的对象,obj是某个包含f字段的类的对象,f.get(obj)将返回一个对象,其值为obj的当前字段值。

ObjectAnalyzerTest.java

public class ObjectAnalyzerTest {

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

ArrayList squares = new ArrayList<>();

for (int i = 1; i <= 5; i++)

squares.add(i*i);

System.out.println(new ObjectAnalyzer().toString(squares));

}

}

ObjectAnalyzer.java

/**

* 使用反射在运行时分析对象

*/

public class ObjectAnalyzer {

private ArrayList visted = new ArrayList<>();

/**

* 将对象转换为列出所有字段的字符串表示形式

*/

public String toString(Object obj) throws IllegalAccessException {

if (obj == null) return null;

if (visted.contains(obj)) return "...";

visted.add(obj);

Class cl = obj.getClass();

if (cl == String.class) return (String)obj;

if (cl.isArray()){

String r = cl.getComponentType() + "[]{";// cl.getComponentType:返回表示数组的元素类型的Class

for (int i = 0; i< Array.getLength(obj); i++){

if (i > 0) r += ",";

Object val = Array.get(obj, i);

if (cl.getComponentType().isPrimitive()) r += val;// 如果是基本类型直接追加

else r += toString(val);// 如果不是基本类型递归调用toString方法

}

return r + "}";

}

String r = cl.getName();

// 检查此类和所有超类的字段

do{

r += "[";

Field[] fields = cl.getDeclaredFields();

AccessibleObject.setAccessible(fields,true);// 设置一个对象数组的可访问标志

// 获取所有字段的名称和值

for (Field field : fields){

if (!Modifier.isStatic(field.getModifiers())){

if (!r.endsWith("[")) r += ",";

r += field.getName() + "=";

Class type = field.getType();

Object val = field.get(obj);// 返回obj对象中用这个Field对象描述的字段的值

if (type.isPrimitive()) r += val;// 如果是基本类型直接追加

else r += toString(val);// 如果不是基本类型递归调用toString方法

}

}

r += "]";

cl = cl.getSuperclass();

}

while (cl != null);

return r;

}

}

输出

java.util.ArrayList[elementData=class java.lang.Object[]{java.lang.Integer[value=1][][],java.lang.Integer[value=4][][],java.lang.Integer[value=9][][],java.lang.Integer[value=16][][],java.lang.Integer[value=25][][],null,null,null,null,null},size=5][modCount=5][][]

API

java.lang.reflect.AccessibleObject

void setAccessible(boolean flag)

设置或取消这个可访问对象的可访问标志,如果拒绝访问则抛出一个IllegalAccessException异常

static void setAccessible(AccessibleObject[] array, boolean flag)

这是一个便利方法,用于设置一个对象数组的可访问标志。

5、使用反射编写泛型数组代码

CopyOfTest.java

/**

* 使用反射编写泛型数组代码

*/

public class CopyOfTest {

public static void main(String[] args) {

int[] a = {1,2,3};

a = (int[]) goodCopyOf(a,10);

System.out.println(Arrays.toString(a));

String[] b = {"Tom","Dick","Harry"};

b = (String[]) goodCopyOf(b,10);

System.out.println(Arrays.toString(b));

//以下调用将生成异常

b = (String[]) badCopyOf(b,10);

}

public static Object[] badCopyOf(Object[] a, int newLength){

Object[] newArray = new Object[newLength];

System.arraycopy(a,0,newArray,0,Math.min(a.length,newLength));

return newArray;

}

public static Object goodCopyOf(Object a, int newLength){

Class cl = a.getClass();

if(!cl.isArray()) return null;

Class componentType = cl.getComponentType();// 返回表示数组的元素类型的Class

int length = Array.getLength(a);

Object newArray = Array.newInstance(componentType, newLength);// 使用反射包里的Array构造一个新数组,提供两个参数,一个是数组的元素类型,一个是数组的长度

System.arraycopy(a,0,newArray,0,Math.min(length,newLength));

return newArray;

}

}

输出

[1, 2, 3, 0, 0, 0, 0, 0, 0, 0]

[Tom, Dick, Harry, null, null, null, null, null, null, null]

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;

at com.company.reflection.CopyOfTest.main(CopyOfTest.java:20)

API

java.lang.reflect.Array

static Object get(Object array,int index)

static void set(Object array,int index,Object newValue)

static int getLength(Object array)

返回给定数组的长度

static Object newInstance(Class componentType,int Length)

返回一个有给定类型、给定大小的新数组

6、调用任意方法和构造器

Method类中有一个invoke方法,允许调用包装在Method对象中的方法。invoke方法的签名是:

Object invoke(Object obj,Object... args)

第一个参数是隐式参数,其余的对象提供了显示参数。

对于静态方法,第一个参数可以忽略,即可以将它设置为null。

MethodTableTest.java

/**

* 使用反射调用任意方法和构造器

*/

public class MethodTableTest {

public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

// 获取指向square和sqrt方法的方法指针

Method square = MethodTableTest.class.getMethod("square", double.class);// 平方

Method sqrt = Math.class.getMethod("sqrt", double.class);// 平方根

// 打印x和y值表

printTable(1,10,10,square);

printTable(1,10,10,sqrt);

}

public static double square(double x){

return x * x;

}

public static void printTable(double from, double to, int n, Method f) throws InvocationTargetException, IllegalAccessException {

// 打印该方法作为表头

System.out.println(f);

double dx = (to - from) / (n - 1);

for (double x = from; x <= 10; x += dx){

double y = (Double) f.invoke(null,x);

System.out.printf("%10.4f | %10.4f%n",x,y);

}

}

}

输出

public static double com.company.reflection.MethodTableTest.square(double)

1.0000 | 1.0000

2.0000 | 4.0000

3.0000 | 9.0000

4.0000 | 16.0000

5.0000 | 25.0000

6.0000 | 36.0000

7.0000 | 49.0000

8.0000 | 64.0000

9.0000 | 81.0000

10.0000 | 100.0000

public static double java.lang.Math.sqrt(double)

1.0000 | 1.0000

2.0000 | 1.4142

3.0000 | 1.7321

4.0000 | 2.0000

5.0000 | 2.2361

6.0000 | 2.4495

7.0000 | 2.6458

8.0000 | 2.8284

9.0000 | 3.0000

10.0000 | 3.1623

API

java.lang.reflect.Method

public Object invoke(Object implicitParamter, Object[] explicitParamters)

调用这个对象描述的方法,传入给定参数,并返回方法的返回值。对于静态方法,传入null作为隐式参数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值