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();
		}
	}

}