Java 反射学习《一》 Field详解
Java 反射学习《二》 Constructor详解
Java 反射学习《三》Method详解
如何获取Class对象
每个类在被加载之后,系统就会为该类生成一个Class对象,通过该Class对象,就可以访问大炮JVM中的这个类。
Java中获取Class对象的方式
-
使用Class的 public static Class<?> forName(String className),参数的值是某个类的全限定类名(必须添加完整包名)。
-
调用某个类的class属性来获取Class对象,如Person.class。
-
调用某个对象的的getClass()方法,该方法是java.lang.Object类中的一个方法,所以所有的Java对象都可以调用该方法,该方法将会返回该对象所属类对应的Class对象。
try {
Class p1 = Class.forName("com.company.Person");
System.out.println("p1:" + p1.toString());
}catch (Exception e){
}
Class p2 = Person.class;
Class p3 = (new Person("", 0, "")).getClass();
System.out.println("p2:" + p2.toString());
System.out.println("p3:" + p3.toString());
//输出
p1:class com.company.Person
p2:class com.company.Person
p3:class com.company.Person
如何获取父类Class
public class Person<T,U> {
public T name;
public U age;
}
public class Student extends Person<String,Integer>{
}
-
public native Class<? super T> getSuperclass() 返回直接继承的父类(没有包含泛型参数)
Class stuCls = Student.class.getSuperclass(); System.out.println(stuCls.getName()); //输出 //com.company.Person
-
public Type getGenericSuperclass() 返回直接继承的父类(包含泛型参数)
Type cls = Student.class.getGenericSuperclass(); System.out.println(cls.toString()); //输出 //com.company.Person<java.lang.String, java.lang.Integer>
-
Type的方法Type[] getActualTypeArguments(), 获取运行时期泛型的具体类型
Type cls = Student.class.getGenericSuperclass(); Type[] types = ((ParameterizedType) cls).getActualTypeArguments(); for (Type type : types) { System.out.println(type.getTypeName()); } //输出 Student继承 Person<String,Integer> //java.lang.String //java.lang.Integer
-
通过Class对象获取Field
-
public Field[] getDeclaredFields() throws SecurityException
返回所有由类或者接口声明的字段,这些变量包括public, protected, default, private修饰的字段,但是不包括继承的字段。返回的字段没有做排序。- 如果这个Class对象表示的类或者接口,没有声明变量,这个方法返回一个空数组。
- 如果这个Class对象表示的是数组,primitive,void类型,这个方法返回一个空组。
public class Person {
public String name;
public int age;
public String sex;
public Person(String name, int age,String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public void printNameAndAge(String name,int age){
System.out.println("name:" + name + " age:" + age);
}
}
Field[] perosnField = Person.class.getDeclaredFields();
for (int i = 0; i < perosnField.length; i++) {
System.out.println(perosnField[i].getName());
}
//输出
name
age
sex
public interface MyInterface {
final static String a = "a";
final static String b = "b";
final static String c = "c";
}
Field[] interfacefields = MyInterface.class.getDeclaredFields();
for (int i = 0; i < interfacefields.length; i++) {
System.out.println(interfacefields[i].getName());
}
//输出
a
b
c
-
public Field[] getFields() throws SecurityException
返回所有由类或者接口声明的public变量,返回的字段没有做排序。- 如果Class表示的类或者接口,没有可以访问的公共字段,则返回一个空数组。
- 如果Class表示的是一个类,则返回这类的父类和已经实现的的接口中的公共字段。
- 如果Class表示的是一个接口,则返回这个接口和父接口中的公共字段
public class Person {
public String name;
//以下这个字段不会输出
private int age;
private String sex;
public Person(String name, int age,String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public void printNameAndAge(String name,int age){
System.out.println("name:" + name + " age:" + age);
}
}
Field[] perosnField = Person.class.getFields();
for (int i = 0; i < perosnField.length; i++) {
System.out.println(perosnField[i].getName());
}
// 输出
name
public class Student extends Person implements MyInterface{
public String stuName;
private int stuAge;
public Student(String name, int age, String sex) {
super(name, age, sex);
}
}
Field[] stuField = Student.class.getFields();
for (int i = 0; i < stuField.length; i++) {
System.out.println(stuField[i].getName());
}
//输出
stuName
a
b
c
name
public interface SuperInterface {
final static String superA = "superA";
}
public interface MyInterface extends SuperInterface {
final static String a = "a";
final static String b = "b";
final static String c = "c";
}
Field[] myField = MyInterface.class.getFields();
for (int i = 0; i < myField.length; i++) {
System.out.println(myField[i].getName());
}
//输出
a
b
c
superA
-
public Field getDeclaredField(String name)
返回指定名称的Field,如果该Class所指向的对象是数组,找不到数组的length字段
int[] a = {1, 2, 3, 4};
Class cls = a.getClass();
Field[] fields = cls.getDeclaredFields();
for (int i = 0; i <fields.length ; i++) {
System.out.println(fields[i].getName());
}
try{
System.out.println(cls.getDeclaredField("length"));
}catch (Exception e){
}
//输出(没有任何输出)
- public Field getField(String name) 只能返回public修饰的 Field,和上面的getFields()对应,如果该Class所指向的对象是数组,找不到数组的length字段
int[] a = {1, 2, 3, 4};
Class cls = a.getClass();
Field[] fields = cls.getDeclaredFields();
for (int i = 0; i <fields.length ; i++) {
System.out.println(fields[i].getName());
}
try{
System.out.println(cls.getField("length"));
}catch (Exception e){
}
//输出(没有任何输出)
Class pcls = Person.class;
try{
System.out.println(pcls.getField("name").getName());
}catch (Exception e){
System.out.println(e.toString());
}
try{
System.out.println(pcls.getField("age").getName());
}catch (Exception e){
System.out.println(e.toString());
}
//输出
name
java.lang.NoSuchFieldException: age
Field的常用方法
- public String getName() 返回字段对应的变量名称
Class pcls = Person.class;
Field[] fields = pcls.getDeclaredFields();
for (Field field:fields) {
System.out.println(field.getName());
}
//输出
name
age
sex
pField
- public Class<?> getType() 字段的声明类型(Class)
Class pcls = Person.class;
Field[] fields = pcls.getDeclaredFields();
for (Field field:fields) {
System.out.println(field.getType());
}
//输出
class java.lang.String
int
class java.lang.String
class java.lang.String
- public Type getGenericType() 返回字段的声明的类型(Type)
Class pcls = Person.class;
Field[] fields = pcls.getDeclaredFields();
for (Field field:fields) {
System.out.println(field.getGenericType().getTypeName());
}
//输出
class java.lang.String
int
class java.lang.String
class java.lang.String
-
public int getModifiers() 获取成员变量的修饰符
成员变量可以被以下修饰符修饰:- 访问权限控制符:public, protected, private
- 限制只能有一个实例的:static
- 不允许修改的:final
- 不会被序列化:transient
- 线程共享数据的一致性:volatile
类似获取 Class 的修饰符,我们可以使用 Field.getModifiers() 方法 获取当前 成员变量的修饰符。返回 java.lang.reflect.Modifier 中定义的整形值。然后使用 Modifier.toString(int mod)解码成字符串
Class pcls = Person.class;
Field[] fields = pcls.getDeclaredFields();
for (Field field : fields) { System.out.println(Modifier.toString(field.getModifiers()));
}
//输出
public
private
private
private
-
boolean isEnumConstant() 如果此字段表示枚举类型的元素,则返回 true;否则返回 false。
-
boolean isSynthetic() 如果此字段是复合字段,则返回 true;否则返回 false。
-
<T extends Annotation> T getAnnotation(Class<T> annotationClass) 如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
-
Annotation[] getDeclaredAnnotations() 返回直接存在于此元素上的所有注释。
获取和修改Field的值
如果是使用private修饰的字段,在外部类是无法直接访问到这些成员属性的,想要获取和修改只能通过类的getters和setters方法进行。使用反射Field.setAccessible(true);可以解除这些限制。
Field的setAccessible()方法是从AccessibleObject类继承而来的(class Field extends AccessibleObject implements Member)。AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。
- 基本类型的的getters方法和setters方法:
********getters方法
//获取一个静态或实例 byte 字段的值。
byte getByte(Object obj)
// 获取 int 类型或另一个通过扩展转换可以转换为 int 类型的基本类型的静态或实例字段的值。
int getInt(Object obj)
//获取 short 类型或另一个通过扩展转换可以转换为 short 类型的基本类型的静态或实例字段的值。
short getShort(Object obj)
//获取 long 类型或另一个通过扩展转换可以转换为 long 类型的基本类型的静态或实例字段的值。
long getLong(Object obj)
//获取 float 类型或另一个通过扩展转换可以转换为 float 类型的基本类型的静态或实例字段的值。
float getFloat(Object obj)
//获取 double 类型或另一个通过扩展转换可以转换为 double 类型的基本类型的静态或实例字段的值。
double getDouble(Object obj)
//获取一个静态或实例 boolean 字段的值。
boolean getBoolean(Object obj)
//获取 char 类型或另一个通过扩展转换可以转换为 char 类型的基本类型的静态或实例字段的值。
char getChar(Object obj)
// ********setter方法
//将字段的值设置为指定对象上的一个 byte 值。
void setByte(Object obj, byte b)
// 将字段的值设置为指定对象上的一个 short 值。
void setShort(Object obj, short s)
//将字段的值设置为指定对象上的一个 int 值。
void setInt(Object obj, int i)
//将字段的值设置为指定对象上的一个 long 值。
void setLong(Object obj, long l)
//将字段的值设置为指定对象上的一个 float 值。
void setFloat(Object obj, float f)
//将字段的值设置为指定对象上的一个 double 值。
void setDouble(Object obj, double d)
//将字段的值设置为指定对象上的一个 boolean 值。
void setBoolean(Object obj, boolean z)
//将字段的值设置为指定对象上的一个 char 值。
void setChar(Object obj, char c)
- 引用类型的getters方法和setters方法:
//返回指定对象上此 Field 表示的字段的值。
//字段不是静态字段的话,要传入反射类的对象.如果传null是会报
//java.lang.NullPointerException
//但是如果字段是静态字段的话,传入任何对象都是可以的,包括null
Object get(Object obj)
//将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
void set(Object obj, Object value)
public class Person {
public String name;
private int age;
private String sex;
private String pField;
public Person(String name, int age,String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public void printNameAndAge(String name,int age){
System.out.println("name:" + name + " age:" + age);
}
public void print(){
System.out.println("name:" + name + " age:" + age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", pField='" + pField + '\'' +
'}';
}
}
public class FieldDemo {
public int a = 0;
long b = (long) 0.0;
protected float c = (float) 0.0;
private boolean d = false;
public final short e = 0;
//如果将e写成这个样子就能通个Field修改e的值
// public final short e = (short) (d ? 0 : 0);
public Person person = new Person("小明",20,"男");
@Override
public String toString() {
return "FieldDemo{" +
"a=" + a +
", b=" + b +
", c=" + c +
", d=" + d +
", e=" + e +
", person=" + person +
'}';
}
}
public static void main(String[] args) {
Class demoClass = FieldDemo.class;
FieldDemo demo = new FieldDemo();
System.out.println(demo);
try {
System.out.println("***********************");
Field a = demoClass.getDeclaredField("a");
System.out.println("a被修改前:" + a.getInt(demo));
a.setInt(demo, 10);
System.out.println("a被修改后:" + a.getInt(demo));
System.out.println("***********************");
Field b = demoClass.getDeclaredField("b");
System.out.println("b被修改前:" + b.getLong(demo));
b.setLong(demo, (long) 20.0);
System.out.println("b被修改后:" + b.getLong(demo));
System.out.println("***********************");
Field c = demoClass.getDeclaredField("c");
System.out.println("c被修改前:" + c.getFloat(demo));
c.setFloat(demo, (float) 30.0);
System.out.println("c被修改后:" + c.getFloat(demo));
System.out.println("***********************");
Field d = demoClass.getDeclaredField("d");
//d是私有属性,必须要设置setAccessible(true)否会抛出IllegalAccessException异常
d.setAccessible(true);
System.out.println("d被修改前:" + d.getBoolean(demo));
d.setBoolean(demo, true);
System.out.println("d被修改后:" + d.getBoolean(demo));
System.out.println("***********************");
//e是final修饰的,必须要设置setAccessible(true)否会抛出IllegalAccessException异常
Field e = demoClass.getDeclaredField("e");
e.setAccessible(true);
//这句话是不会生效的,也就是e的值还是0,这是因为在jvm中e被优化成了常量,也就是
// System.out.println(demo.e);就相当于System.out.println(0);
System.out.println("e被修改前:" + e.getShort(demo));
e.setShort(demo, (short) 40);
System.out.println("e被修改前:" + e.getShort(demo));
System.out.println("***********************");
Field person = demoClass.getDeclaredField("person");
Person p = new Person("小红",10,"女");
((Person)person.get(demo)).name = "小明明";
System.out.println("person 被修改前:" + person.get(demo));
person.set(demo,p);
System.out.println("person 被修改后:" + person.get(demo));
System.out.println(demo);
} catch (Exception e) {
e.printStackTrace();
}
}
//输出
***********************
a被修改前:0
a被修改后:10
***********************
b被修改前:0
b被修改后:20
***********************
c被修改前:0.0
c被修改后:30.0
***********************
d被修改前:false
d被修改后:true
***********************
e被修改前:0
e被修改前:40
***********************
person 被修改前:Person{name='小明明', age=20, sex='男', pField='null'}
person 被修改后:Person{name='小红', age=10, sex='女', pField='null'}
使用反射修改final + static修饰符的变量
public class Demo {
//防止被jvm编译成常量
private static boolean b = false;
public static final int a = b ? 0: 0;
}
public static void main(String[] args) {
Class class1 = Demo.class;
Demo demo = new Demo();
try {
Field field = class1.getDeclaredField("a");
field.setAccessible(true);
System.out.println(demo.a);
field.setInt(demo,10);
System.out.println(demo.a);
} catch (NoSuchFieldException | IllegalAccessException e){
e.printStackTrace();
}
}
//输出
java.lang.IllegalAccessException: Can not set static final int field com.company.Demo.a to (int)10
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:100)
at java.base/jdk.internal.reflect.UnsafeQualifiedStaticIntegerFieldAccessorImpl.setInt(UnsafeQualifiedStaticIntegerFieldAccessorImpl.java:129)
at java.base/java.lang.reflect.Field.setInt(Field.java:960)
public static void main(String[] args) {
Class class1 = Demo.class;
Demo demo = new Demo();
try {
Field field = class1.getDeclaredField("a");
field.setAccessible(true);
//修改修饰符
Field modifiers = field.getClass().getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
System.out.println(demo.a);
field.setInt(demo,10);
System.out.println(demo.a);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
//输出
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.company.Main (file:/Users/qli/Desktop/Android%e9%a1%b9%e7%9b%ae/JavaDemo/out/pro duction/JavaDemo/) to field java.lang.reflect.Field.modifiers
WARNING: Please consider reporting this to the maintainers of com.company.Main
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
0
10
网友评论