初识Java反射
Posted x_k
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初识Java反射相关的知识,希望对你有一定的参考价值。
Java反射原理是基于Class类而实现的,Class类代表了所有的类,通过Class类可以获取一个未知类的属性(Filed)、方法(method)、构造器(constructor)、修饰符(modifier)等。
一般情况下,需要创建一个类的实例对象,JVM会确认该类的Class对象是否加载完毕。未加载的话,JVM会根据类名查找.class文件,并载入内存,从而可以创建需要使用的类的对象。
以下代码验证均是在下面代码基础上验证。
接口:SingSong.java
package com.edu;
/**
* 唱歌
*
* @author xukai
*/
public interface SingSong
public static final long iid = -6564235491638363465L;
public void singSong();
父类:PeopleSuperClass
package com.edu;
/**
* 父类
*
* @author xukai
*/
public class PeopleSuperClass
public static final long fid = -6564335491638363465L;
/**
* 子类
*/
private People subPeople;
/**
* 父类
*/
private PeopleSuperClass superPeople;
public People getSubPeople()
return subPeople;
public void setSubPeople(People subPeople)
this.subPeople = subPeople;
public PeopleSuperClass getSuperPeople()
return superPeople;
public void setSuperPeople(PeopleSuperClass superPeople)
this.superPeople = superPeople;
子类:People
package com.edu;
/**
* 人类
*
* @author xukai
*/
public class People extends PeopleSuperClass implements SingSong
public static final long sid = -6564335491638363466L;
private String name;
private Integer age;
public String sex;
public People()
public People(String name, Integer age)
super();
this.name = name;
this.age = age;
public String getName()
return name;
public void setName(String name)
this.name = name;
public Integer getAge()
return age;
public void setAge(Integer age)
this.age = age;
@Override
public String toString()
return "People [name=" + name + ", age=" + age + ", sex=" + sex + "]";
public String helloWorld()
return name + " said:Hello World!";
@Override
public void singSong()
System.out.println("唱一首Until you");
public static void show()
System.out.println("I'm here");
public static void show(People p)
System.out.println(p.getName() + ",I'm here");
Class的创建和获取
创建:
1. 使用new关键字创建对象
2. 访问类的静态成员
3. 使用Class.forName()方法
获取:
1. Class.forName方法返回对象即为加载类的Class对象
2. 每个类的class静态属性
3. Object类的成员方法getClass()
package com.edu;
/**
* 获取Class对象
*
* @author xukai
*/
public class MyReflex
public static void main(String[] args)
// 访问People的静态成员class,加载类
System.out.println(People.class.getName());
// 1.Class.forName静态方法
Class<?> c1 = null;
try
c1 = Class.forName("com.edu.People");
catch (ClassNotFoundException e)
System.out.println("加载类路径错误");
// 2.class静态属性
Class<?> c2 = People.class;
// 3.Object的成员方法getClass()
People people = new People("xukai", 22);
Class<?> c3 = people.getClass();
System.out.println("c1=c2 is " + (c1 == c2));
System.out.println("c1=c3 is " + (c1 == c3));
System.out.println("c2=c3 is " + (c2 == c3));
控制台信息:
从上图可以看出,通过几种创建Class的方式返回的对象都是同一个。换句话说一个类对应的Class对象是否只存在一个?有待研究
获取类的成员变量
- 通过Class的方法getDeclareField()
- 通过Class的方法getDeclareFields()
package com.edu;
import java.lang.reflect.Field;
/**
* 获取成员变量Field
*
* @author xukai
*/
public class MyField
public static void main(String[] args)
Class<?> c = People.class;
/**
* 获取所有成员变量<br>
* 1.getDeclaredField(),getDeclaredFields(),作用域对此方法无影响,不会访问父类字段<br>
* 2.getFields(),getFields(),只能访问公共成员字段,即作用域为public,访问父类字段
*/
getDeclaredField(c);
System.out.println("------------------华丽的分割线-----------------");
getField(c);
// 通过Filed操作私有成员变量
People p = new People("xukai", 22);
try
Field fName = c.getDeclaredField("name");
Field fAge = c.getDeclaredField("age");
try
// 设置可访问性
fName.setAccessible(true);
fAge.setAccessible(true);
fName.set(p, "rj");
fAge.set(p, 25);
System.out.println(p.toString());
catch (IllegalArgumentException e)
e.printStackTrace();
catch (IllegalAccessException e)
e.printStackTrace();
catch (NoSuchFieldException e)
e.printStackTrace();
catch (SecurityException e)
e.printStackTrace();
/**
* 扫描本类的所有成员变量
*
* @param c
* Class
*/
private static void getDeclaredField(Class<?> c)
Field[] fields = c.getDeclaredFields();
for (Field field : fields)
try
System.out.println("Field[] name=" + field.getName());
Field singleField = c.getDeclaredField(field.getName());
System.out.println("Field name=" + singleField.getName());
catch (NoSuchFieldException e)
e.printStackTrace();
catch (SecurityException e)
/**
* 如果存在安全管理器s<br>
* 1.调用 s.checkMemberAccess(this, Member.DECLARED) 拒绝访问已声明字段<br>
* 2.调用者的类加载器不同于也不是当前类的类加载器的一个祖先, 并且对 s.checkPackageAccess()
* 的调用拒绝访问该类的包<br>
*/
e.printStackTrace();
/**
* 只能访问公共成员字段,即作用域为public<br>
* 1.搜索当前类的公共成员变量 2.搜索实现的接口的公共成员变量 3.搜索父类的公共成员变量
*
* @param c
* Class
*/
private static void getField(Class<?> c)
Field[] fields = c.getFields();
for (Field field : fields)
try
System.out.println("Field[] name=" + field.getName());
Field singleField = c.getField(field.getName());
System.out.println("Field name=" + singleField.getName());
catch (NoSuchFieldException e)
e.printStackTrace();
catch (SecurityException e)
e.printStackTrace();
控制台信息:
需要注意getDeclaredFiled和getFiled的区别
方法 | 作用域限制 | 访问实现接口成员变量 | 访问继承父类成员变量 |
---|---|---|---|
getDeclaredFiled | 无 | 不能 | 不能 |
getDeclaredFileds | 无 | 不能 | 不能 |
getFiled | 限制为公共public | 能 | 能 |
getFileds | 限制为公共public | 能 | 能 |
获取类的方法(method)
- 通过Class的方法getMethod()
- 通过Class的方法getMethods()
package com.edu;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 获取类的方法
*
* @author xukai
*/
public class MyMethod
public static void main(String[] args)
Class<?> c = People.class;
Method[] methods = c.getMethods();
for (Method method : methods)
System.out.println(method + "\\t\\t" + method.getName());
System.out.println("------割-----");
try
// getMethod(String name, Class<?>... parameterTypes),第二个参数为方法参数
Method method = c.getMethod("show", new People("zj", 23).getClass());
System.out.println(method);
try
// 使用invoke调用方法
System.out.println("------割-----");
// 调用show方法
method.invoke(new People("xukai", 22), new People("zj", 23));
catch (IllegalAccessException e)
e.printStackTrace();
catch (IllegalArgumentException e)
e.printStackTrace();
catch (InvocationTargetException e)
e.printStackTrace();
catch (NoSuchMethodException e)
e.printStackTrace();
catch (SecurityException e)
e.printStackTrace();
控制台信息:
需要注意getMethod(String name, Class<\\?>… parameterTypes)的第二个参数为Class类型。
Method.invoke(Object obj, Object… args)第一个参数为调用对象,第二个参数为方法参数
反射的简单应用
创建一个类的实例对象
package com.edu;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
/**
* 使用反射实例化一个对象<br>
* 建议使用newInstance方法创建对象,在使用setters方法赋值
*
* @author xukai
*/
public class ReflexApplication
public static void main(String[] args)
Class<? extends People> c = People.class;
People p = null;
// 1.使用Class.newInstance创建对象
try
/**
* 使用此方法可以有效地绕过编译时的异常检查,而在其他情况下编译器都会执行该检查<br>
* 调用空参构造方法
*/
p = c.newInstance();
System.out.println(p);
catch (InstantiationException e)
e.printStackTrace();
catch (IllegalAccessException e)
e.printStackTrace();
// 2.使用带参数构造方法
try
Constructor<? extends People> con = c.getConstructor(new String("zhouyang").getClass(),
new Integer(23).getClass());
try
p = con.newInstance("ft", 24);
System.out.println("constructor create: " + p);
catch (InstantiationException e)
e.printStackTrace();
catch (IllegalAccessException e)
e.printStackTrace();
catch (IllegalArgumentException e)
e.printStackTrace();
catch (InvocationTargetException e)
e.printStackTrace();
catch (NoSuchMethodException e)
e.printStackTrace();
catch (SecurityException e)
e.printStackTrace();
// 使用反射重写toString()
People people = new People("zt", 23);
System.out.println(people);
overrideToString(people);
/**
* 使用反射重写toString
*
* @param obj
* 重写对象
*/
public static void overrideToString(Object obj)
StringBuffer sb = new StringBuffer();
Field[] fields = obj.getClass().getDeclaredFields();
sb.append(obj.getClass().getSimpleName() + "[");
for (Field f : fields)
try
if (!f.isAccessible())
f.setAccessible(true);
sb.append(f.getName());
sb.append("=");
sb.append(f.get(obj));
sb.append(", ");
catch (IllegalArgumentException e)
e.printStackTrace();
catch (IllegalAccessException e)
e.printStackTrace();
sb.append("]");
System.out.println(sb);
控制台信息:
一般使用Constructor创建实例太过于麻烦,常用newInstance创建实例,然后通过setter方法给成员变量赋值。
以上是关于初识Java反射的主要内容,如果未能解决你的问题,请参考以下文章