反射的基础部分知识

反射的基础——Class

Java当中的类用来表示具有相同属性和方法的对象的集合,是抽象的概念。对象是类创建的,同一个类的不同对象具有不同的属性值。

Java当中定义的所有类都属于同一类事物,可以Class来表示。

类型

访问方法

返回值类型

说明

包路径

getPackage()

Package 对象

获取该类的存放路径

类名称

getName()

String 对象

获取该类的名称

继承类

getSuperclass()

Class 对象

获取该类继承的类

实现接口

getlnterfaces()

Class 型数组

获取该类实现的所有接口

构造方法

getConstructors()

Constructor 型数组

获取所有权限为 public 的构造方法

getDeclaredContruectors()

Constructor 对象

获取当前对象的所有构造方法

方法

getMethods()

Methods 型数组

获取所有权限为 public 的方法

getDeclaredMethods()

Methods 对象

获取当前对象的所有方法

成员变量

getFields()

Field 型数组

获取所有权限为 public 的成员变量

getDeclareFileds()

Field 对象

获取当前对象的所有成员变量

对比理解:

不同的人可以用Person类来表示。

人->Person

Java当中定义的不同类可以用Class来表示。

Java当中的类->Class

Class类的对象-字节码:不同类编译生成的字节码。

Person p1 = new Person();

Class class = new Class()       (×)

三种方式:

  1. 对象名.getClass()

Person p1 = new Person(); p1.getClass();

  1. 类名.class

Date.class

  1. Class.forName()方法(此方式用的较多)

Class.forName(“java.lang.String”);

package com.apesource.demo;
//class对象的三种创建方式
public class Demo01 {
	public static void main(String[] args) throws ClassNotFoundException {
		//方法1:通过类名访问class 
		Class stringCls = String.class;
		//方法2: 通过实例访问getclass();
		String s = "";
		Class stringCls2 = s.getClass();
		//方法3:通过class类的静态方法forName(类名)
		Class stringCls3 = Class.forName("java.lang.String");
		
		
		System.out.println(stringCls.getName());
		System.out.println(stringCls2.getName());
		System.out.println(stringCls3.getName());

	}

}

Java当中的基本数据类型有:

Boolean int short byte char long float 和 double 他们也有各自的Class对象。

例如:int.class

Void 也有自己对应的Class对象 void.class

基本数据类型对应的封装类有属性TYPE,这个属性代表了封装所封装的基本数据类型的Class对象。

反射就是把Java类中的各个组成部分映射成相应的Java类。

一个类的组成部分包括:属性,方法,构造方法,包等。这些组成部分都会被映射成相应的类。

Class类定义了一系列方法来获取java类的属性,方法,构造方法,包等信息,这些信息都有相应的类来表示,分别是Field,Method,Constryctor,Package等。

注意:表示java类组成部分的各种类位于java.lang.reflect包中

Constructor类

Constructor类用来描述类中所定义的构造方法。

(1)得到类所有的构造方法

Constructor constructors[]=

Class.forName(java.lang.String).getConstructors();

  1. 得到类中某个具体的构造方法,在getConstructors中传入参数类型所对应的字节码

Constructor constructor=

Class.forName(java.lang.String).getConstructor(String.class)

使用Constructor类的目的是用来创建响应类的对象

正常情况:

String str = new String(“hello”);

反射情况:

Constructor con = String.class.getConstructor(String.class)

//拿到string类型的构造方法

String str = (String)con.newlnstance(“hello”)

通过反射方式创建对象的过程

Class---->Constructor---->某个类的对象

只有当要用某个无参构造方法创建该类对象时,可以省略创建Constructor类对象的这个过程。

Date d = (Date)Class.forName(“java.util.Date”).newlnstance();

注意:java运行环境的缓存中保存了类的无参构造方法所对应的Constructor对象。

Field类

Field类用来表示类中的属性(字段)。

(1) Class.getPields0:得到Class对象的所有字段,返回的是riela数组。

(2) Class. getField (String: name)返回个 Field 对象,它反映此 Class对象所表示的类或接口的指定公有成员字段。

(3) Field的对象所代表的某-一个类的属性,而不是那个类的某一个对象的属性。要得到某个对象对应的属性值,需要通过get (0b ject obj)方法与某个对象具体关联

(4)对于非公有属性只能通过Class的getDec laredField (String fieldName)方法得到。

(5)对于私有属性要得到它所关联到的对象的值,需通过Field的setAccessible (boolean boolean)方法设置。

(6) Field类的getType Q方法用来得到字段所属的类型

动态加载机制

public class Main {
    static {
		System.out.println("Main被加载");
	}
	public static void main(String[] args) {
		int rand = new Random().nextInt(10);
        if (rand > 5) {
            create(rand);
        }
    }

    static void create(int no) {
    	Person p = new Person(no);
    }
}

class Person{
	
	static {
		System.out.println("Person类被加载");
	}
	
	public Person(int no) {
		System.out.println("Person类的有参构造方法");
	}
}

当执行Main.java时,由于用到了Main,因此,JVM首先会把Main.class加载到内存。然而,并不会加载Person.class,除非程序执行到create()方法,JVM发现需要加载Person类时,才会首次加载Person.class。如果没有执行create()方法,那么Person.class根本就不会被加载。

Method类

Method用来表示类中的方法。通过Class对象的如下方法得到Method对象:

  1. Method getMethod(String name,Class<?>…parameterTypes)按名称得到某个特定的public方法(包括从父类或者接口继承的方法);
  2.  Method[] getMethods():得到public方法(包括从父类或者接口继承的方法);
  3. Method[] getDeclaredMethods():得到所有的方法(不包括继承的方法);
  4. Method getDeclaredMethod(String name,Class<?>…parame-

terTypes):按名称得到某个特定的方法(不包括继承)。

得到某个方法对应的Method对象后,需要调用如下方法来在某个对象上执行该方法:

  1. invoke(Object obj,Object…obj)方法用来调用Method所表示的方法。其中,第一个参数表示此方法作用于哪一个对象。
  2. 如果调用的时静态方法,那么invoke()方法中的第一个参数用null表示。
//获得共有方法
Method method[] = class1.getMethods();
for (Method mm : method){
    System.out.println("共有方法的名称是"+mm.getName());
}

 当参数为数组时

Method method4 = class1.getDeclaredMethod("showMessages", String[].class);
        System.out.println("得到的这个方法是:"+method4.getName());
        String[] strs = {"你好","咸阳师范学院","计算机学院"};
//        1,调用数组的参数方法,把整个实际的数组最为一个Object数组的唯一元素进行调用
        method4.invoke(person1,new Object[] {strs});

//        2,吧实际数组转换为Object对象
        method4.invoke(person1,(Object)strs);

 

  1. 得到Method对象的最终目的还是为了去调用这个方法;
  2. 如果要执行应该私有访问权限的方法,调用该方法执行要执行setAccessible方法,设置为true;
  3. 调用数组的参数方法,把整个实际的数组最为一个Object数组的唯一元素进行调用;
  4. 最后将把实际数组转换为Object对象;
  5. 数组也是符合数据类型。
  6. Method类-关于方法参数的操作

  7. int getParameters():获取该Method对象所表示方法的参数数量;
  8. Parameter[] getParameters():返回一个Parameter对象的数组,表示该Method对象所表示方法返回的所有参数;
  9. Class<?>[] getParameterTypes():获取该Method对象所表示方法的所有参数类型的数组;
  10. Type[] getGenericParameterTypes():获取该Method对象所表示方法的所有参数类型的数组,一般情况下,同getParameterTypes()方法的返回值一样,如果存在泛型,则该方法会返回泛型的类型。
(5)public class MethodReflect {
    public static void main(String[] args) {

        Class<? extends MyClass1> aClass = MyClass1.class;

        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods){
            //获取该方法的参数值
            int parameterCount = method.getParameterCount();
            //获取参数类型数组,
            Class<?>[] parameterTypes = method.getParameterTypes();
            Type[] genericParameterTypes = method.getGenericParameterTypes();
            for (int i = 0;i < parameterTypes.length; i++){
                System.out.println(method.getName()+","+parameterCount+","+parameterTypes[i].getTypeName()+","+genericParameterTypes[i].getTypeName()+"\t");
            }
            System.out.println();
        }
    }
}
class MyClass1{
    public void m1(int i){

    }

    public void m2(Boolean bool){

    }

    public void m3(String str,int i){

    }

    public void m4(List<String> list){

    }

    public void m5(Integer... nums){

    }
}

 

Method类-关于方法返回值的操作

  1. Class<?> getReturnType():返回应该Class对象,该对象表示此Method对象表示的方法的正式返回值类型;
  2. Type getGenericReturnType():返回一个Type对象,该对象表示此Method对象表示的方法的正式返回值类型。(如果返回值类型不是泛型,那么两个方法的返回值是一致的;如果是泛型,getGenericReturnType()方法会返回泛型的类型。)
(3)public class MethodReflect2 {
    public static void main(String[] args) {

        Class<? extends MyClass2> aClass = MyClass2.class;

        Method[] methods = aClass.getDeclaredMethods();
        for (Method method : methods){
            Class<?> returnType = method.getReturnType();
            Type genericReturnType = method.getGenericReturnType();
            System.out.println(returnType+","+genericReturnType);
        }

    }
}

class MyClass2{

    public int getInt(){
        return 1;
    }

    public Boolean getBoolean(){
        return Boolean.TRUE;
    }

    public String getString(){
        return "ddc";
    }

    public List<String> getList(){
        return new ArrayList<>();
    }

    public Map<String,Object> getMap(){
        return new HashMap<>();
    }
}

Method类-关于修饰符

  1. int getModifiers():得到方法前面所定义的修饰符,返回类、接口、变量、方法等以2整数编码的Java语言修饰符,访问修饰符编码列表。Modifier类应该提供了12种修饰符的编码常量;
  2. java.lang.reflect.Modifier类提供解码类和访问修饰符的静态方法和常量,系师傅集合别表示为具有表示不同的修饰符的不同位置的整数。

Method类-关于修饰符

  1. int getModifiers():得到方法前面所定义的修饰符,返回类、接口、变量、方法等以2整数编码的Java语言修饰符,访问修饰符编码列表。Modifier类应该提供了12种修饰符的编码常量;
  2. java.lang.reflect.Modifier类提供解码类和访问修饰符的静态方法和常量,系师傅集合别表示为具有表示不同的修饰符的不同位置的整数。

Method类-关于所抛出的异常

  1. Class[] method.getExceptionTypes():方法在定义的时候可以通过throws关键字声明抛出异常,应该方法可以抛出多个异常。

数组的反射操作

在Java中数组属于符合数据类型,具有相同元素类型和维数的数组属于同一个类型,即具有相同的字节码对象。

代表数组的字节码对象调用getSuperClass()得到它的父类Object的字节码对象。

基本数据类型的一维数组可以当做Object类型使用,但不能当作Object[]类型使用;基本数据类型的二维数组可以当做Object[]类型使用;复合数据类型的一维数组既可以当做Object类型使用,也可以当作Object[]类型使用。

Java.lang.Array用于完成对数组的反射操作。

Object[]来使用
//数组也是复合类型
Object obj3 = new String[4];//一维复合数据类型数组当作Object使用
Object[] obj4 = new String[4];//一维复合数据类型数组当作Object[]使用

Object[][] obj5 = new String[4][5];//二维复合数据类型数组当作Object,Object[][].或者Object[]使用

int a1[] = new int[3];
int a2[] = new int[100];
//只要维数相等,类型相等,那么我们就认为驻足的class对象相等(和元素个数无关)
System.out.println(a1.getClass() == a2.getClass());
  1. 只要维数相等,类型相等,那么我们就认为驻足的class对象相等(和元素个数无关);
  2. 二维复合数据类型数组当作Object,Object[][].或者Object[]使用;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值