反射学习笔记

1、访问字段

对任意的一个Object实例,获取了它的Class,就可以获取一切信息,通过反射读写字段会破坏对象的封装性。
Java提供了一下方法来通过Class实例获取字段信息:

  • Field getField(name): 根据字段名获取某个public的field(包括父类)
  • Field getDeclaredField(name): 根据字段名获取当前类的某个field(不包括父类)
  • Field[] getFields(): 获取所有public的field(包括父类)
  • Field[] getDeclaredFields(): 获取当前类的所有字段(不包括父类)
public class FieldTest {
    
    public static void main(String[] args) throws NoSuchFieldException {
        Class clazz = Student.class;
        System.out.println(clazz.getField("age"));
        System.out.println(clazz.getField("name"));
        System.out.println(clazz.getDeclaredField("address"));
    }

    class Student extends Person{
        public int age;
        private String address;
    }

    class Person{
        public String name;
    }
}

运行结果:
public int Reflect.FieldTest$Student.age
public java.lang.String Reflect.FieldTest$Person.name
private java.lang.String Reflect.FieldTest$Student.address

获取到一个Field对象,可以通过Field对象获取到该对象的名称、类型、修饰符、值等信息。

  • getName(): 返回字段名称
  • getType(): 返回字段类型,是一个Class实例
  • getModifiers(): 返回字段的修饰符,是一个int,不同bit表示不同含义
 		Field s = String.class.getDeclaredField("value");
        int j = s.getModifiers();
        System.out.println(s.getName());
        System.out.println(s.getType());
        System.out.println(Modifier.isPublic(j));
        System.out.println(Modifier.isAbstract(j));
        System.out.println(Modifier.isPrivate(j));
        System.out.println(Modifier.isStatic(j));

执行结果:
value
class [C
false
false
true
false

使用get(Object)方法获取Field的值

 	Object person = new Person("Mark");
    Class claz = person.getClass();
    Field fie = claz.getDeclaredField("name");
    fie.setAccessible(true);//无论是public或者private,一律允许访问
    Object value = fie.get(person);
    System.out.println(value);
	static class Person{
        public String name;

        public Person(String name){
            this.name = name;
        }
    }
执行结果:
Mark

使用Field.set(Object,Object)实现设置字段值,第一个参数是指定的实例,第二个参数是待修改的值。

 Person person = new Person("Mark");
 System.out.println(person.getName());
 Class claz = person.getClass();
 Field fie = claz.getDeclaredField("name");
 fie.setAccessible(true);//无论是public或者private,一律允许访问
 //设置字段值
 fie.set(person, "John");
 System.out.println(person.getName());
 
 运行结果:
 Mark
 John

2、 调用方法

通过Class实例可以获取所有Method的信息,Java提供了一下几个方法来获取Method。

  • Method getMothod(name, Class…): 获取某个public的Method(包括父类)
  • Method getDeclaredMethod(name, Class…): 获取当前类的某个Method(不包括父类)
  • Method[] getMethods(): 获取所有public的Method(包括父类)
  • Method[] getDeclareMethods(): 获取当前类的所有Method(不包括父类)
//反射获取方法
public class MethodTest {

    public static void main(String[] args) throws NoSuchMethodException {
        Class clazz = Student.class;
        //有参public方法
        System.out.println(clazz.getMethod("getScore", String.class));
        //有参private方法
        System.out.println(clazz.getDeclaredMethod("getPhone", int.class));
        //无参public父类方法
        System.out.println(clazz.getMethod("getName"));
    }

    class Student extends Person{
        public int getScore(String score){
            return 100;
        }

        private int getPhone(int phone){
            return 12345;
        }
    }

    class Person{
        public String getName(){
            return "Mark";
        }
    }
}

执行结果:
public int Reflect.MethodTest$Student.getScore(java.lang.String)
private int Reflect.MethodTest$Student.getPhone(int)
public java.lang.String Reflect.MethodTest$Person.getName()

获取到Method对象,就可以获取该方法的所有信息,java提供了以下方法对方法进行操作:

  • getName(): 返回方法名称
  • getReturnType(): 返回方法返回值类型,是一个Class实例
  • getParameterTypes(): 返回方法的参数类型,是一个Class数据
  • getModifiers():返回方法的修饰符,是一个int类型,不同数字代表不同含义
//获取方法的详细信息
Method method = clazz.getMethod("getScore", String.class);
System.out.println(method.getName());//方法名
System.out.println(method.getReturnType());//返回类型
System.out.println(method.getParameterTypes());//方法参数类型
System.out.println(method.getModifiers());//方法的修饰符
        
执行结果:
getScore
int
[Ljava.lang.Class;@6ff3c5b5
1

2.1 调用方法

获取到一个Method方法时,不仅可以获取该方法对象的所有信息,还可以对方法进行操作。调用方法。
利用反射调用String的length()方法,使用Method的invoke方法就相当于调用该方法,invoke的第一个参数是对象实例,后面的可变参数与方法参数一致。

 String str = "Hello World";
 Method m1 = String.class.getMethod("length");
 int length = (int) m1.invoke(str);
 System.out.println(length);

调用非public方法,使用Method.setAccessible(true)方法

//调用private方法
User user = new User();
Method m2  = user.getClass().getDeclaredMethod("setName", String.class);
m2.setAccessible(true);
String band = (String) m2.invoke(user,"Oasis");
System.out.println(band);

static class User{
        String name;
        private String setName(String name){
            return name;
        }
    }

执行结果:
Oasis

处理多态:子类覆写了父类的方法,从父类获取到的方法,作用于子类时,调用的是子类的方法。
结论:使用反射调用方法时,仍然遵守多态规则。

//处理多态
Method m3 = Animals.class.getMethod("run");
m3.invoke(new Cat());
class Animals{
    public void run(){
         System.out.println("Animals:I can run");
    }
}

class Cat extends Animals{
     public void run(){
         System.out.println("Cat:I can run");
     }
}

执行结果:
CatI can run

2.2 调用构造方法

使用Class调用newInstance()方法来创建新的实例,但通过此种方法只能调用该类的public无参数构造方法。
要解决上面的问题,Java的反射API提供了Constructor对象,包含一个构造方法的所有信息,可以创建一个实例,调用结果总是返回实例。
Constructor类提供了一下方法:

  • getConstructor(Class…): 获取某个public的Constructor
  • getDeclaredconstructor(Class…): 获取某个Constructor
  • getConstructors(): 获取所有public的Constructor
  • getDeclaredConstructors(): 获取所有Constructor
 //获取构造方法Integer(int)
 Constructor cons = Integer.class.getConstructor(int.class);
 Integer n = (Integer) cons.newInstance(132);
 System.out.println(n);

 //获取构造方法String(String)
 Constructor cons1  = String.class.getConstructor(String.class);
 String str = (String) cons1.newInstance("hello world");
 System.out.println(str);

2.3 获取继承关系

2.3.1 获取普通类的Class

获取Class对象的三种方法:

使用.class获取某个Class对象

Class cls = String.class;

使用getClass()方法获取

String str = "";
Class cls = str.getClass();

使用Class.forName(“”)方法获取,需要传入类的完整名称

Class cls = Class.forName("java.lang.String");

2.3.2 获取父类的Class

使用getSuperclass()方法

  	@Test
    public void test(){
        Class clazz = Integer.class;
        Class supCls = clazz.getSuperclass();
        System.out.println(supCls);

        Class sup2Cls = supCls.getSuperclass();
        System.out.println(sup2Cls);
        System.out.println(sup2Cls.getSuperclass());
    }

执行结果:
class java.lang.Number
class java.lang.Object
null

2.3.3 获取interface

通过getInterfaces()方法,返回一个数组。

 /**
     * 获取接口
     * */
    @Test
    public void test1(){
       Class cls = Integer.class;
       Class[] clazz = cls.getInterfaces();
       for (Class inface : clazz){
           System.out.println(inface);
       }
    }

执行结果:
interface java.lang.Comparable

2.3.4 继承关系

判断一个实例是否是某个类型时,使用instanceof操作符。

	@Test
    public void instanceofTest(){
        Object obj = Integer.valueOf(123);
        System.out.println(obj instanceof Double);//false
        System.out.println(obj instanceof String);//false
        System.out.println(obj instanceof Integer);//true
        System.out.println(obj instanceof Number);//true
    }

判断一个实例向上转型是否成立,使用isAssignableFrom()方法

	@Test
    public void assignableFrom(){
        //Number<--------可以转为-----Integer
        System.out.println(Integer.class.isAssignableFrom(Integer.class));//true
        System.out.println(Integer.class.isAssignableFrom(String.class));//false
        System.out.println(Integer.class.isAssignableFrom(Number.class));//false
        System.out.println(Number.class.isAssignableFrom(Integer.class));//true
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值