天天看点

java基础----反射机制天使总在想象中,魔鬼总在细节处反射是框架设计的灵魂一、反射机制的概述

java基础--反射机制

  • 天使总在想象中,魔鬼总在细节处
  • 反射是框架设计的灵魂
  • 一、反射机制的概述
    • 二、类的加载过程
    • 三、反射的优缺点
    • 四、实现反射的方法
      • 4.1、动态加载类的三种方法
      • 4.2、 获得类的构造方法并调用
      • 4.3 获得类的成员方法并调用
      • 4.4获取类的成员变量并调用
    • 五、实际运用
      • 5.1 利用反射创建数组
      • 5.2 利用反射使之越过泛型检查

天使总在想象中,魔鬼总在细节处

java基础----反射机制天使总在想象中,魔鬼总在细节处反射是框架设计的灵魂一、反射机制的概述

反射是框架设计的灵魂

一、反射机制的概述

  java反射机制是在运行状态中,对任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象的方法的功能称为Java语言的反射机制。

  反射就是把Java类中的各种成分映射成一个个的java对象。例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。

二、类的加载过程

  Class对象的由来是程序将class文件读入内存中,并为之创建一个class对象

java基础----反射机制天使总在想象中,魔鬼总在细节处反射是框架设计的灵魂一、反射机制的概述

三、反射的优缺点

优点 提高了程序的灵活性和扩展性,更加容易实现面向对象开发
缺点 反射会消耗一定的系统资源;反射操作会模糊程序的内部逻辑,比如反射可以忽略权限检查机制,破坏其封装,造成安全问题 ,且增加维护的难度

四、实现反射的方法

4.1、动态加载类的三种方法

  • 直接通过类名获得这个实例对象(任何数据类型包括基本数据类型,都有一个“静态的”Class属性)

    Class s1 = Student.class

  • 通过类的对象获得该类的实例对象

    Student student = new Student();

    Class s2 = student.getClass();

  • 使用forName(“全类名”)

    Class s3 = Class.forName(“student”)

类的加载只会发生一次,所以存在于JVM中的类对象是唯一的,所以在程序运行中,使用反射多次获得的类对象是同一个。

4.2、 获得类的构造方法并调用

批量:

Public Constructor[] getConstructors();

获得所有的“公有的”构造方法

Public Constructor getConstructor(Class…parameter Types);

获得所有的构造方法(包括私有、受保护、默认、公有)

单个:

Public Constructor getConstructor(Class…parameterType);

获得单个的“公有的”构造方法

Public Constructor getDeclaredConstructor(Class…parameterTypes);

获得“单个构造方法”可以是私有的,或受保护的、默认、公有

调用构造方法:

Public Object newInstance(Object…initargs);

参数说明:

initargs:实参

newInstance是Constructor类的方法(管理构造函数的类)

具体调用方法

public class Student{
	//--构造方法--
	//(默认的构造方法)
	Student(String str){
		System.out.println("(默认的)构造方法 s = "+str);
	}
	//(无参构造方法)
	public Student(){
		System.out.println("调用了公有、无参构造方法执行了。。。");
	}
	//(有一个参数的构造方法)
	public Student(char name){
		System.out.println("姓名:"+name);
	}
	//(有多个参数的构造方法)
	public Student(String name,int age){
		System.out.println("姓名:"+name+"年龄:"+age);
	}
	//(受保护的构造方法)
	protected Student(Boolean n){
		System.out.println("受保护的构造方法 n="+n);
	}
	//(私有构造方法)
	private Student(int age){
		System.out.println(“私有的构造方法 年龄:”+age);
	}
}


//获得Class对象
Class stuClass = Class.forName("fanshe.method.Student");

//获得私有构造方法,并调用
Constructor con = stClass.getDeclaredConstructor(char.class);

//忽略掉访问修饰符 暴力访问;(访问私有资源的核心方法)
con.setAccessible(true);

//调用构造方法
Object obj = con.newInstance('男');

//也可以直接调用Class对象的newInstance()方法来创建Class对象对应类的实例
Class<?> c = String.class;
Object str = c.newInstance();

           

4.3 获得类的成员方法并调用

批量:

public Method[] getMethods();

获得类的所有public的方法,包括继承父类的

public Method[] getDeclaredMethods()

获得类的所有自己声明的方法

单个:

public Method getMethod(String name,Class<?>…parameterTypes);

获得类的某一个public的方法,包括继承父类的

public Method getDeclaredMethod(String name,Class<?> parameterTypes);

获得类的某一个自己声明的方法

参数说明:

name: 方法名;

class:形参的class类型对象

调用:

public Object invoke(Object obj,Object…args);

参数说明

obj:要调用的方法的对象;

args:调用方法时所传递的实参;

具体调用方法

public class Student{
	//****成员方法****
	public void show1(){
		System.out.println("调用了:公有的,String参数的show1():s="+s);
	}
	protected void show2(){
		System.out.println("调用了:受保护的,无参的show2()");
	}
	void show3(){
		System.out.println("调用了:默认的,无参的show3()");
	}

	private String show4(int age){
		System.out.println("调用了,私有的,并且有返回值的,int参数的show4():age="+age);
		return "abcd";
	}
}

//获得Class对象
Class stuClass = Class.forName("fanshe.method.Student");

//动态获得该对象的某一个方法(方法名,形参的class类型对象)
Method m = stuClass.getMethod("show1",String.class);

//实例化一个Student对象(方法在调用时,需要传入该实例对象)
Object obj = stuClass.getConstructor().newInstance();

//方法的具体调用
m.invoke(obj,"刘德华");

           

特殊例子

public class Student{
	public static void main(){
		System.out.println("main方法执行了。。。");
	}
}

/**
*获取Student类的main方法、不要与当前的main方法搞混了
*/
public class Main{
	public static void main(String[] args){
		try{
			//1.获取Student对象的字节码
			Class clazz = Class.forName("fanshe.main.Student");

			//2.获取main方法
			Method methodMain = clazz.getMethod("main",String[].calss);
			//第一个参数:方法名称; 第二个参数:方法形参的类型

			//3.调用main方法
			methodMain.invoke(null,(Object)new String[]{"a","b","c"});
			//第一个参数,对象类型,因为方法时static静态的,所以为null也可以,第二个参数是String数组,这里拆的时候会将 new String[]{"a","b","c"}拆成3个对象。所以需要将它强转。

			methodMain.invoke(null,new Object[]{new String[]{"a","b","c"}});//方式二

		}catch(Exception e){
			e.printStackTrace();
		}
	}
}
           

4.4获取类的成员变量并调用

批量:

Field[] getFields();

获得所有的“公有字段”

Field[] getDeclaredFields();

获取所有字段,包括:私有、受保护、默认、公有

单个:

public Field getField(String fieldName);

获取某个“公有的”字段

public Field getDeclaredFields(String fieldName);

获取某个字段(可以是私有的)

参数说明:

fieldName:获取某个“公有的”成员变量

调用设置某个字段的值

public void set(Object obj,Object value);

参数说明:

obj:要设置的字段所在的对象

value:要为字段设置的值

具体调用方法

public class Student{
	public Student(){
		
	}
	//****字段****//
	public String name;
	protected int age;
	char sex;
	private String phoneNum;

	@Override
	public String toString(){
		return "Student[name="+name+",age="+age+",sex="+sex+",phoneNum="+phoneNum+"]";
	}
}

//获得Class对象
Class stuClass = Class.forName("fanshe.method.Student");
//获得某个字段
Field f = stuClass.getDeclaredField("phoneNum");
//忽略掉访问修饰符 暴力访问
f.setAccessible(true);
//为字段设置值
f.set(obj,"1111");

           

五、实际运用

5.1 利用反射创建数组

public static void testArray() throws ClassNotFoundException{

Class<?> cls = Class.forName(“java.lang.String”);

Object array = Array.newInstance(cls,25);

//往数组里添加内容

Array.set(array,0,“hello”);

Array.set(array,1,“java”);

Array.set(array,2,“fuck”);

Array.set(array,3,“Scala”);

Array.set(array,4,“Clojure”);

//获得某一项的内容

System.out.println(Array.get(array,3));

}

5.2 利用反射使之越过泛型检查

泛型用在编译期,编译过后泛型擦除(消失掉)。所以是可以通过反射越过泛型检查的

/*
*通过反射越过泛型检查
*
*例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?
*/
public class Demo {
	public static void main(String[] args) throws Exception{
			ArrayList<String> strList = new ArrayList<>();
			strList.add("aaa");
			strList.add("bbb");
			//获取ArrayList的Class对象,反向的调用add()方法,添加数据
			Class listClass = strList.getClass();//得到strList 对象的字节码对象
			//获取add()方法
			Method m = listClass.getMethod("add",Object.class);
			//调用add()方法
			m.invoke(strList,100);
		
			//遍历集合
			for(Object obj : strList){
				System.out.println(obj);
			}
	}
}
           

继续阅读