Java反射定义
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。反射就是把java类中的各种成分映射成一个个的Java对象。例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
反射能做什么
反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括包括其modifiers(修饰符),fields(属性),methods(方法)等,并可于运行时改变fields内容或调用methods。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;但是需要注意的是反射使用不当会造成很高的资源消耗!
Class类
万事万物皆是对象!类是对象,类是java.lang.Class的实例对象。
注意:在运行期间,一个类,只有一个Class对象产生
Java有个Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class 对象。
Class 类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types以及关键词void。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。如果您想借由“修改Java标准库源码”来观察Class 对象的实际生成时机(例如在Class的constructor内添加一个println()),这样是行不通的!因为Class并没有public constructor。
Class是Reflection故事起源。针对任何您想探勘的类,唯有先为它产生一个Class 对象,接下来才能经由后者唤起为数十多个的Reflection APIs。
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。
获取Class对象的三种方式:
1、 Object ——> getClass();例如:Class c1 = Hern.class; //任何一个类都有一个隐含的静态成员变量
2、 任何数据类型(包括基本数据类型)都有一个“静态”的class属性,例如:Class c2 = hern.getClass(); //已经知道该类的对象通过getClass()方法调用
3、 通过Class类的静态方法:forName(String className)(常用)(注意有包名的时候要写出包名,没有包名则直接写类名)
package com.test.class_test;
public class HelloWorld {
//私有属性
private String name = "Tom";
//公有属性
public int age = 18;
//构造方法
public HelloWorld(){
}
//私有方法
private void say(){
System.out.println("private say()...");
}
//公有方法
public void work(){
System.out.println("public work()...");
}
}
package com.test.class_test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.Class;
public class Main {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException, ClassNotFoundException {
//1、通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object
// 类型的对象,而我不知道你具体是什么类,用这种方法
HelloWorld helloWorld = new HelloWorld();
Class c1 = helloWorld.getClass();
//2、直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高
// 这说明任何一个类都有一个隐含的静态成员变量 class
Class c2 = HelloWorld.class;
//3、通过 Class 对象的 forName() 静态方法来获取,用的最多,
// 但可能抛出 ClassNotFoundException 异常
Class c3 = Class.forName("HelloWorld");
}
}
例如:包名是com.imooc.reflect,类名是Foo,则class3 = Class.forName("com.imooc.reflect.Foo");
import java.util.*;
import java.math.*;
public class t9 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Hern hern = new Hern();
hern.say(); //输出:这是Hern类的say方法
//方法一
Class h1 = Hern.class;
System.out.println(h1); //输出:class Hern
//方法二
Class h2 = hern.getClass();
System.out.println(h2); //输出:class Hern
System.out.println(h1 == h2); //输出:true
//方法三
Class h3 = null;
try {
h3 = Class.forName("Hern");
System.out.println(h3); //输出:class Hern
System.out.println(h3 == h2); //输出:true
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//可以通过类的类类型创建该类的对象实例--》通过h1 or h2 or h3(注意通过哪个类类型就是使用该类类型)
try {
Hern h4 = (Hern)h1.newInstance();//进行强制转换(前提是需要有无参数的构造方法)
h4.say(); //输出:这是Hern类的say方法
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Hern{
public void say() {
System.out.println("这是Hern类的say方法");
}
}
通过 Class 类获取成员变量、成员方法、接口、超类、构造方法等
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
package com.test.class_test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.Class;
public class Main {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
Class c1 = HelloWorld.class;
String className = c1.getName();
System.out.println(className);
/*
Field[] fields = c1.getFields();
for (Field field:fields){
System.out.println(field);
}
Field[] fields1 = c1.getDeclaredFields();
for (Field field:fields1){
System.out.println(field);
}
Method[] methods = c1.getDeclaredMethods();
for (Method method: methods){
System.out.println(method);
}
*/
Field field = c1.getDeclaredField("name");
System.out.println(field);
field.setAccessible(true);
System.out.println(field);
Object object = c1.newInstance();
field.set(object,"AAA");
System.out.println(field.get(object));
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor: constructors){
System.out.println(constructor);
}
}
}
通过反射了解集合泛型的本质
反射的操作都是编译之后的操作, c==c2结果返回true说明编译之后集合的泛型是去泛型化的,Java中集合的泛型,是防止错误输入的,只在编译阶段有效,绕过编译就无效了,可以通过方法的反射来操作,绕过编译
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class All implements Hern {
public static void main(String[] args){
// TODO Auto-generated method stub
ArrayList list = new ArrayList();
ArrayList<String> list2 = new ArrayList<>();
list2.add("hello");
Class c = list.getClass();
Class c2 = list2.getClass();
System.out.println(c == c2);
/*
* 反射的操作都是编译之后的操作
* c==c2结果返回true说明编译之后集合的泛型是去泛型化的
* Java中集合的泛型,是防止错误输入的,只在编译阶段有效,绕过编译就无效了
* 可以通过方法的反射来操作,绕过编译
* */
try {
Method m = c2.getMethod("add", Object.class);
m.invoke(list2, "world");
m.invoke(list2, 100);
System.out.println(list2);
//for循环遍历
for(Object obj: list2) {
System.out.println(obj);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}