Java反射指的是在运行状态时,能够获取类的属性和方法或者修改类运行时行为的过程。
java.lang.Class类提供了很多方法用于获取元数据、检查和改变类运行时的行为。
Java的反射主要涉及java.lang和java.lang.reflect包下的类。
反射应用场景举例
- IDE, 如Eclipse、MyEclipse、NetBeans等;
- 调试器;
- 测试工具等;
- 各大框架、spring、hibernate等;
java.lang.Class类
java.lang.Class主要提供了以下两个功能:
- 提供方法用于访问运行期间类的元数据;
- 提供方法用于检查和修改类的运行时行为;
java.lang.Class类常用方法
怎样获取Class对象
有三种方式,如下:
- Class类的forName()方法,动态加载,运行时,开始装入类, 并做类的静态初始化
- 对象的getClass()方法,静态加载(编译时已加载)
- .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
*/
}
}
通过反射创建实例对象
有两种方式,如下:
- 通过Class对象的newInstance()方法创建,这种方式只能调用无参构造方法;
- 通过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构造器