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类常用方法

怎样获取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对象对应的类型:

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构造器

10-06 18:29