黑马程序员—Java反射

原创 2015年07月08日 16:30:55

14. 反射

 

 

14.1   Class类

 

Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。

 

Class.forName(String) 该方法返回字节码。如果字节码曾经被加载过,存在于jvm中,则直接返回。如果jvm中还没有此字节码,则用类加载器去加载,将其缓冲在jvm中

此方法会抛出ClassNotFoundException异常,因为输入的String有可能不是一个对象。

 

如何得到各个字节码对应的对象(即Class对象,但并不是有具体参数的实例对象):

1)  类名.class 如 Person.class

2)  对象.getClass() 如 new Date().getClass()

3)  Class.forName(“类名”) 如Class.forName(“java.util.Date”)

class ReflectTest 
{
	public static void main(String[] args) throws Exception
	{
		String str1 = "abc";
		Class cls1 = str1.getClass();
		Class cls2 = String.class;
		Class cls3 = Class.forName("java.lang.String");
		/*三者得到的都是同一份字节码,对应的都是String类,
		  而String类可以创造多个不同的实例化对象*/
		System.out.println(cls1==cls2);    //true
		System.out.println(cls1==cls3);    //true
		System.out.println(cls2==cls3);    //true

		/*String类不是基本类型,Integer也不是,而Integer封装的TYPE是。
		  即:boolean、byte、char、short、int、long、float 和 double*/
		System.out.println(cls1.isPrimitive());    //false
		System.out.println(Integer.class.isPrimitive());  //false
		System.out.println(Integer.TYPE==int.class);  //true
		System.out.println(Void.TYPE.isPrimitive()); //true。Void是一个占位符类
	}
}

Class.newInstance():该方法内部先得到默认的空参数的构造方法,然后用该构造方法创建实例对象。该方法内部用了缓存机制来保存默认构造方法的实例对象。

如:Stringobj = (String)Class.forName(“java.lang.String”).newInstance () //得到空字符序列


14.2   反射

 

1)  反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等

2)  一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象。

 

 

14.3  Constructor类

 

Constructor类代表某个类中的一个构造方法

 

得到某个类所有的构造方法:

Constructor[] constructors = Class.forName("java.lang.String").getConstructors();

 

得到某一个构造方法:

Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);

getConstructor()方法中传入的参数是想要获取的构造方法能够传入的参数,如果该构造方法能传入多个参数,getConstructor()中可以传入一个包含这些参数的数组,也可以利用1.5新特性,直接将各个参数写入,用“ , ”分割

 

使用Constructor中的newInstance()方法,可以将得到的构造方法实例化(即使用此方法),注意使用时需要进行强转,因为jvm并不知道得到的Constructor对象是哪个类中的构造方法。newInstance()中传入的参数就是对应构造方法传入的参数。

import java.util.*;
import java.lang.reflect.*;
class ConstructorDemo 
{
	public static void main(String[] args) throws Exception
	{
		Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
		System.out.println(Arrays.toString(constructors));
		//获得的构造方法是以StringBuffer对象为参数的。
		Constructor constructor = 
			Class.forName("java.lang.String").getConstructor(StringBuffer.class);
		String str = (String)constructor.newInstance(new StringBuffer("abc"));
		System.out.println(str);
	}
}


14.4  Field类

 

Field类代表某个类中的一个成员变量

import java.lang.reflect.*;
class FieldDemo 
{
	public static void main(String[] args) throws Exception
	{
		ReflectPoint pt1 = new ReflectPoint(3,5);

		//获取类中的成员变量
		/*Field只代表获取到的类中的某个变量,不代表该变量在某个实例对象中的值
		  如果该成员变量用private修饰,则此方法会报出NoSuchFieldException异常
		*/
		Field fieldY = pt1.getClass().getField("y");

		//获取类中的成员变量,private修饰的同样可以获取
		Field fieldX = pt1.getClass().getDeclaredField("x");

		//获取成员变量在某个实例对象中的值
		System.out.println(fieldY.get(pt1));
		
		//通过setAccessible(true)方法才能够得到private修饰的成员变量值
		fieldX.setAccessible(true);
		System.out.println(fieldX.get(pt1));
	}
}
class ReflectPoint 
{
	private int x;
	public int y;
	ReflectPoint(int x,int y)
	{
		this.x = x;
		this.y = y;
	}
}

映射Field类应用:

//将某个对象实例中所有String类型的成员变量中的字符b替换成字符a:
import java.lang.reflect.*;
class FieldTest 
{
	public static void main(String[] args) throws Exception
	{
		ReFlectPoint2 pt2 = new ReFlectPoint2("hbhb","bob");
		//获取包含所有成员变量的数组
		Field[] fields = pt2.getClass().getFields();
		for(Field field : fields)
		{
			//判断成员变量类是否是String 类型的类字节码用==比较,因为同一个类的字节码在虚拟机中是唯一的
			if(field.getType() == String.class)
			{
				//获取该变量在pt2中的值
				String oldValue = (String)field.get(pt2);
				//将该值中的b字符替换成a字符
				String newValue = oldValue.replace('b','a');
				//将该变量在pt2中的值设置成新的值。
				field.set(pt2,newValue);
			}
		}
		System.out.println(pt2);
	}
}
class ReFlectPoint2
{
	public String str1;
	public String str2;
	public String str3 = "itcast";
	ReFlectPoint2(String str1,String str2)
	{
		this.str1 = str1;
		this.str2 = str2;
	}
	public String toString()
	{
		return str1 + ":" + str2 + ":" + str3;
	}
}


14.5  Method类

 

Mthod类代表某个类中的一个成员方法

import java.lang.reflect.*;
class MethodDemo 
{
	public static void main(String[] args) throws Exception
	{
		String str = "abc";
		//获得的方法是以一个int类型的值为参数的
		Method methodcharAt = 
			Class.forName("java.lang.String").getMethod("charAt",int.class); 
		//对str调用此方法,invoke(obj,args)中第二个参数是原方法要传入的参数
		System.out.println(methodcharAt.invoke(str,1));
		//如果该方法是静态的,则通过Method的invoke方法调用时,第一个参数传null
		//Method.invoke(null,args)
	}
}

JDK1.4和JDK1.5的invoke方法的区别:

JDK1.5:public Object invoke(Objectobj,Object…args)

JDK1.4:public Object invoke(Objectobj,Object[] args)

则上述的methodcharAt.invoke(str,1)可以写成methodcharAt.invoke(str, new Object[ ]{1})


14.6  数组的反射

 

1) 具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象

2) 代表数组的Class实例对象的getSuperclass()方法返回的父类为Object类对应的Class

3) 基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当作Object类型使用,又可以当作Object[]类型使用。

4) Arrays.asList()方法处理int[]和String[]时的差异

import java.util.*;
class ArrayReflect 
{
	public static void main(String[] args) 
	{
		int[] a1 = new int[]{1,2,3};
		int[] a2 = new int[4];
		int[][] a3 = new int[2][3];
		String[] a4 = new String[]{"a","b","c"};
		//a1和a2属于同一个类型
		System.out.println(a1.getClass() == a2.getClass());
		System.out.println(a1.getClass().getSuperclass().getName());
		System.out.println(Arrays.asList(a1));                   // 输出a1的内存地址
		System.out.println(Arrays.asList(a4));                   // 输出a,b,c
		/*
		因为需要兼容JDK1.4的方法,所以传入a4时,使用的是asList(Object[] a),
		将数组中每一个String传入List中。而传入a1时,因为int不是Object子类,
		使用的是asList(T... a),所以将a1作为一个参数(数组对象)传入到List当中。
		因此a4可以输出每个字符串对象,而a1只能输出作为一个数组对象的内存地址
		*/
	}
}


14.7  反射的作用: 实现框架功能

 

1) 框架:

框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类

2) 框架要解决的核心问题:

因为在写程序是无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象了,而要同反射方式来做。


利用反射建立的小框架:

框架并不知道需要建立什么样的集合对象,通过读取文件来建立相关的集合

import java.util.*;
import java.io.*;
class  FrameworkDemo
{
	public static void main(String[] args) throws Exception
	{
		//尽量面向父类或接口编程,通过读取文件来获取className的值
		InputStream ips = 
				new FileInputStream("d:\\workspace\\java\\config.properties");
		Properties props = new Properties();
		props.load(ips);
		ips.close();
		String className = props.getProperty("className");
		//通过读取到的className建立相关类型的对象
		Collection collections = 
			(Collection)Class.forName(className).newInstance();

		ReflectPoint pt1 = new ReflectPoint(3,3);
		ReflectPoint pt2 = new ReflectPoint(5,5);
		ReflectPoint pt3 = new ReflectPoint(3,3);

		collections.add(pt1);
		collections.add(pt2);
		collections.add(pt3);
		collections.add(pt1);
		
		//根据文件中设置className为ArrayList和HashSet得到不同的结果。
		System.out.println(collections.size());
	}
}




黑马程序员——java —反射知识总结

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——- (一)反射的基础 (1)、什么是反射? 反射就是把java类中的各个成分映射成相应的java类。通过jav...

黑马程序员—JAVA高新技术之反射

反射  JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为j...
  • yxqcz
  • yxqcz
  • 2014年06月14日 19:37
  • 236

黑马程序员—Java中的反射机制

------- android培训、java培训、期待与您交流! ----------   1.什么是反射机制?           简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在...

黑马程序员————java中类的加载、反射、动态代理、枚举

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 类的加载、反射、动态代理、枚举 一.类的加载 当程序要使用某个类时,如果该...
  • lgplf
  • lgplf
  • 2015年06月19日 22:23
  • 542

黑马程序员————JAVA反射机制深度剖析

本文通过对反射技术来讲解方法反射,属性反射,数组反射,构造器反射,还有与其相关的方法句柄...
  • QSXEDC
  • QSXEDC
  • 2015年09月26日 14:37
  • 322

黑马程序员————Java基础日常笔记---反射与正则表达式

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 黑马程序员————Java基础日常笔记---反射与正则表达式 1.1反射 反射的理解和作用...

黑马程序员—JAVA反射特点

------------- android培训、java培训、期待与您交流! ------------- 反射就是把java类中的各种成分映射成相应的java类,即Class类。 获得字节码对...

黑马程序员java学习<基础加强>—反射

Class  一、概述: 1、Class是Java程序中各个Java类的总称;它是反射的基石,通过Class类来使用反射。 2、Class和class的区别 1)class:Java中的类用于...

黑马程序员—关于java反射机制

-----------android培训、java培训、java学习型技术博客、期待与您交流!------------  理解反射机制 一丶简述        JAVA反射机制是在运行状态中,对于任意...
  • Fvcfun
  • Fvcfun
  • 2016年02月19日 00:06
  • 48

黑马程序员—JAVA基础学习日记十——反射学习总结

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------          java高新技术反射部分,算是java的进阶学习,我感觉还是比较不易理解的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:黑马程序员—Java反射
举报原因:
原因补充:

(最多只允许输入30个字)