(重要)Java反射机制(容易理解)

Java反射指的是在运行状态时,能够获取类的属性和方法或者修改类运行时行为的过程。

java.lang.Class类提供了很多方法用于获取元数据、检查和改变类运行时的行为。

Java的反射主要涉及java.lang和java.lang.reflect包下的类。

反射应用场景举例

  1. IDE, 如Eclipse、MyEclipse、NetBeans等;
  2. 调试器;
  3. 测试工具等;
  4. 各大框架、spring、hibernate等;

java.lang.Class类

java.lang.Class主要提供了以下两个功能:

  1. 提供方法用于访问运行期间类的元数据;
  2. 提供方法用于检查和修改类的运行时行为;

java.lang.Class类常用方法

Method

Description

1) public String getName()

返回类名

2) public static Class forName(String className)throws ClassNotFoundException

加载类并返回Class对象

3) public Object newInstance()throws InstantiationException,IllegalAccessException

创建实例对象

4) public boolean isInterface()

判断是否是接口

5) public boolean isArray()

判断是否是数组

6) public boolean isPrimitive()

判断是否是原始数据类型

7) public Class getSuperclass()

返回父类Class引用

8) public Field[] getDeclaredFields()throws SecurityException

返回类的成员属性字段数组

9) public Method[] getDeclaredMethods()throws SecurityException

返回类的方法数组

10) public Constructor[] getDeclaredConstructors()throws SecurityException

返回类的构造方法数组

11) public Method getDeclaredMethod(String name,Class[] parameterTypes)throws NoSuchMethodException,SecurityException

返回类中指定参数类型的方法

怎样获取Class对象

有三种方式,如下:

  1. Class类的forName()方法,动态加载,运行时,开始装入类, 并做类的静态初始化
  2. 对象的getClass()方法,静态加载(编译时已加载)
  3. .class语法, 静态加载(编译时已加载)

forName()方法示例

class Examp {

}

public class 反射 {

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

        Class<?> c = Class.forName("Examp"); //用forName动态获取类

        System.out.println(c.getName()); //包括package的全名

        System.out.println(c.getSimpleName()); //类的名称

        /*输出结果

        Examp

        Examp

         */

    }

}

Java中泛型Class<T>、T与Class<?>

一.区别

单独的T 代表一个类型 ,而 Class<T>代表这个类型所对应的类, Class<?>表示类型不确定的类

 E - Element (在集合中使用,因为集合中存放的是元素)

 T - Type(Java 类)

 K - Key(键)

 V - Value(值)

 N - Number(数值类型)

 ? -  表示不确定的java类型

举例说明:

Set<T> 表示 集合里 是   T类的实例

List<E> 表示  集合里 是  E类的实例

List<?> 表示 集合里的对象类型不确定,未指定

List 同 List<?> 是一样的。

泛型的作用:

1、用泛型:

Java代码  收藏代码

List<T> list=new ArrayList<T>(); 

T t=list.get(0); 

2、不用泛型:

Java代码  收藏代码

List  list=new ArrayList(); 

T t=(T)list.get(0);

二、如何创建一个Class<T>类型的实例?

      就像使用非泛型代码一样,有两种方式:调用方法 Class.forName() 或者使用类常量X.class。      Class.forName() 被定义为返 回 Class<?>。另一方面,类常量 X.class 被定义为具有类型 Class<X>,所 以 String.class 是Class<String> 类型的。

三、方法中为什么需要<T> T修饰呢

泛型的声明,必须在方法的修饰符(public,static,final,abstract等)之后,返回值声明之前。

public static <T> T request2Bean(HttpServletRequest request,Class<T> clazz){}

其中第一个<T>是与传入的参数Class<T>相对应的,相当于返回值的一个泛型,后面的T是返回值类型,代表方法必须返回T类型的(由传入的Class<T>决定)

getClass()方法示例

class Examp {

}



public class 反射 {

    void printName (Object obj) {

    }

    public static void main (String[] args) {

        Examp e = new Examp();

        Class<? extends Object> c = e.getClass();

        System.out.println(c.getName());

        System.out.println(c.getSimpleName());

        /*

        输出:

        Examp

        Examp

         */

    }

}

.class语法示例

public class 反射

{

    public static void main(String args[])

    {

        Class<Boolean> c = boolean.class;

        System.out.println(c.getName());



        Class<反射> c2 = 反射.class;

        System.out.println(c2.getName());

    }

}

判断Class对象对应的类型

以下方法可用于判断Class对象对应的类型:

1) public boolean isInterface(): 是否对应接口

2) public boolean isArray(): 是否对应数组

3) public boolean isPrimitive(): 是否对应原始数据类型

class Examp {

}

interface Examp2 {

}

public class 反射 {

    public static void main (String[] args) {

        try {

            Class<?> c = Class.forName("Examp");

            System.out.println(c.isPrimitive());

            System.out.println(c.isInterface());

            Class<?> c2 = Class.forName("Examp2");

            System.out.println(c.isPrimitive());

            System.out.println(c2.isInterface());

        } catch (Exception e) {

            System.out.println(e);

        }

        /*

        输出:

        false

        false

        false

        true

         */

    }

}

通过反射创建实例对象

有两种方式,如下:

  1. 通过Class对象的newInstance()方法创建,这种方式只能调用无参构造方法;
  2. 通过Constructor对象的newInstance()方法创建,这种方式适用于有参构造方法,并且还可以破坏单例模式,调用私有构造方法;

所以,通常来讲,第二种方式比第一种使用范围更广。

Class对象调用newInstance()方法示例

package tmp;
class Simple
{
    void message()
    {
        System.out.println("Hello Java");
    }
}
public class Test
{
    public static void main(String args[])
    {
        try
        {
            Class<?> c = Class.forName("tmp.Simple");
            Simple s = (Simple) c.newInstance();
            s.message();
        }
        catch (Exception e)
        {
            System.out.println(e);
        }
    }
}

Hello Java

Constructor对象调用newInstance()方法示例

import java.lang.reflect.Constructor;



class Simple

{

    private String msg;

    void message()

    {

        System.out.println("Hello Java," + msg);

    }

    private Simple(String s){

        this.msg = s;

    }

}



public class 反射

{

    public static void main(String args[])

    {

        try

        {

            Class<?> c = Class.forName("Simple");

            Constructor<?> con = c.getDeclaredConstructor(String.class);

            con.setAccessible(true);

            Simple s = (Simple) con.newInstance("hahaha");

            s.message();

            /*Simple s = new Simple("hahaha");

            s.message();

            //报错:在Simple中是private访问控制

            */

        }

        catch (Exception e)

        {

            System.out.println(e);

        }



    }

} //输出:Hello Java,hahaha

通过反射调用私有方法

通过反射,我们可以调用其它类的私有方法,主要涉及java.lang.Class和java.lang.reflect.Method类;

其中主要是用到了Method类的setAccessible方法和invoke方法,前者修改访问权限,后者调用方法。

通过调用有参私有方法示例:

import java.lang.reflect.Method;



class A {

    private void cube (int n) {

        System.out.println(n * n * n);

    }

    private void haha (int b) {

        System.out.println(b * b);

    }

}

class 反射 {

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

        Class<?> c = A.class;

        Object obj = c.newInstance(); //相当于new A();

        //返回类的方法数组

        Method m = c.getDeclaredMethod("cube", new Class[] {int.class});//method修改权限

        Method m2 = c.getDeclaredMethod("haha", new Class[] {int.class});//method修改权限



        m.setAccessible(true); //设置方法cube权限为可访问

        m.invoke(obj, 4);

        m2.setAccessible(true); //设置方法haha权限为可访问

        m2.invoke(obj,4);

        /*

        invoke方法可以把方法参数化

        invoke(class, method)

        比如你Test类里有一系列名字相似的方法setValue1、setValue2等等

        可以把方法名存进数组v[],然后循环里invoke(test,v[i]),就顺序调用了全部setValue

         */

    }

}

 

Java中newInstance()方法的作用

newInstance()也是用来创建新的对象,其与new()的区别是:

newInstance():弱类型,效率低,只能调用无参构造

new():强类型,高效率,能调用任何public构造器

猜你喜欢

转载自blog.csdn.net/YiLiXiaoHuiChen/article/details/82952861