Java高新技术-反射


说明:反射就是把Java类中的各种成分映射成该成分对应的Java类。


一,Class类

Class类对象为内存中类的字节码,例如:String.class

1.获取类的Class对象

方法一:

Class.forName("java.lang.String"):

1)若该类已加载,则直接返回该类字节码。

2)若该类不在Java虚拟机内,则会先通过类加载器加载该类,然后返回该类字节码。

方法二:

类名.class

方法三:

对象.getClass()

public class Test {	
	public static void main(String[] args) throws Exception{
		//获取方法Class对象的三种方法
		Class cls1=Class.forName("java.lang.String");
		Class cls2=String.class;
		Class cls3=new String().getClass();
	
	
	}
}

2.一个类被类加载器加载到内存中,占用一片存储空间,空间内存放内容就是类的字节码,不同类的字节码不同,所以它们在内存中的内容页不同,这些字节码就是Class类的一个个对象。

注意:基本数据类型的Class对象和数据包装类不是同一类。

例如int.class和Integer.class不是同一个对象。

Integer.TYPE和int.class是同一个字节码文件。

public class Test {	
	public static void main(String[] args) throws Exception{
		System.out.println(Integer.class==int.class);
		System.out.println(Integer.TYPE==int.class);
	
	}
}

运行结果:

false
true


3.判断Class对象的类型

-----isPrinitive():判断Class对象是否为基本类型

----isArray():判断Class对象是否为数组类

public class Test {	
	public static void main(String[] args) throws Exception{
		//判断Integer类是否为基本类型
		System.out.println(Integer.class.isPrimitive());
		//判断int.class是否为基本类型
		System.out.println(int.class.isPrimitive());
		int[] a=new int[3];
		//判断一个Class是否为数组类型
		System.out.println(a.getClass().isArray());
	}
}

运行结果;

false
true
true


二。构造方法的反射:Constructor类

常用方法:

Class类中

----getConstructors():获取Class对象所表示类的所有公有构造方法;

----getComstructor(Class<?>...parameterTypes):获取Class对象的指定公有构造函数

----getDeclaredConstructors():获取Class对象所表示类的所有公有构造方法;

----getDeclaredComstructor(Class<?>...parameterTypes):获取Class对象的指定公有构造函数

Constructor类中

----newInstance(Object...initargs):使用Constructor对象所表示的构造函数创建对象,

import java.lang.reflect.*;

public class Test {	
	public static void main(String[] args) throws Exception{
		//获取String中的指定构造函数,构造函数的参数为字符串类型
		Constructor con=String.class.getConstructor(String.class);
		//通过Constructor对象创建String类对象
		String str=(String) con.newInstance("构造函数的反射");
		System.out.println(str);
	}
}


注:也可以通过Class类的newInstance方法直接为本类创建一个无参数的构造函数。

三,成员变量的反射:Field类

常见方法:

Class类中

----getFields():获取一个类的公有的所有成员变量;

----getField(String name):获取类中指定的公有成员变量;变量名为name;

import java.lang.reflect.*;

public class Test {	
	public static void main(String[] args) throws Exception{
		//获取指定成员变量
		Field field=Student.class.getField("a");
		
		System.out.println(field);
		
	}
}
class Student{
	public int a=3;
	int b;
	public Student(){
	}
}

运行结果:

public int Test.Student.a

注意:上面语句获取的成员变量都是属于类的,而不是属于某个对象。如果要获取给类某个指定对象的成员变量值,可以通过Field 类中方法

Field常用方法:

----get(Object obj):获取指定对象的该成员变量值。

----set(Object obj,Object Value):将指定对象中该变量的值设为value。

import java.lang.reflect.*;

public class Test {	
	public static void main(String[] args) throws Exception{
		//获取指定成员变量
		Field field=Student.class.getField("age");
		
		Student s=new Student(27);
		//获取指定对象的成员变量值
		System.out.println(field.get(s));
		
	}
}
class Student{
	public int age;
	public String name;
	public Student(int age){
		this.age=age;
	}
}


运行结果:‘

27


示例:反射类中的私有成员变量

import java.lang.reflect.*;

public class Test {	
	public static void main(String[] args) throws Exception{
		//获取指定成员变量
		Field field=Student.class.getDeclaredField("name");
		
		Student s=new Student(27,"LiSi");
		//暴力反射,使私有变量变为可以操作
		field.setAccessible(true);
		//获取指定对象的成员变量
		String name=(String) field.get(s);
		System.out.println(name);
	}
}
class Student{
	private int age;
	private String name;
	public Student(int age,String name){
		this.age=age;
		this.name=name;
	}
}

运行结果:

LiSi


四,成员方法的反射:Method类

常见方法:

Class类中:

----getMethods():获取类中所有公有方法
----getMethod(String name,Class<?>...parameterTypes):根据方法名和参数类型获取类中指定方法。

Method类中:

----invoke(Object obj,Object ...args):调用指定类的该方法。

如果要调用静态方法则可以写为:

----invoke(null,Object...arg)

import java.lang.reflect.*;

public class Test {	
	public static void main(String[] args) throws Exception{
		//获取方法
		Method method=String.class.getMethod("charAt", int.class);
		String str="Method.class";
		//由指定对象调用该方法
		char ch=(char) method.invoke(str, 3);
		System.out.println(ch);
	}
}


运行结果:

h

注意:如果一个要调用的函数需要的参数是数组类型的参数时,直接将数组给invoke如:

method.invoke(null,new String[]{"abc","def","gh"});

此时会产生错误,因为编译器会自动将new String[]{"abc","def","gh"}拆包成三个元素,而需要传递的数组是一个元素,所以会发生越界异常。

处理方式:

1.将数组作为Object数组的一个元素传递

method.invoke(null,new Object[]{new String[]{"abc","def","gh"}});
2.将数组向上转型为一个Object对象。此时编译器会认为这是一个Object类的对象而不是一个数组,所以不会进行拆包。

method.invoke(null,(Object)new String[]{"abc","def","gh"});

五,数组的反射:Array类

具有相同数据类型和维数的数组共享一个.class文件。

数组的父类是Object类,所以数组可以向上转型为Object类,

基本数据类型不能向上转型为Object类,但是基本数据的数组可以作为整体向上转型为Object类,

import java.lang.reflect.*;

public class Test {	
	public static void main(String[] args) throws Exception{
		int[] arr1=new int[3];
		//基本类型的数组整体作为一个对象向上转型为Object类
		Object obj1=arr1;
		/*Object[] obj2=arr1;
		 * 上面语句报错,因为单个基本数据类型不能向上转型为Object
		 */
		int[][] arr2=new int[3][4];
		 //将二维数组转型为Object数组,也就是讲二维数组中的每个一维数组向上转型为Object类
		Object[] obj3=arr2;
		
		String[] str1=new String[]{"dfv","wef","efwf"};
		//引用数据类型数组作为整体向上转型为Object类
		Object obj4=str1;
		//数组黄总每个元素单独向上转型为Object类
		Object[] obj5=str1;
	}
}


数组反射操作常见方法:

Array类中:

----get(Object array,int index):返回数组中指定位置的值

----set(Object array,int index,Object value):为数组指定位子设置值。

import java.lang.reflect.*;

public class Test {	
	public static void main(String[] args) throws Exception{
		
		String[] str=new String[]{"dfv","wef","efwf"};
		Class cls=str.getClass();
		if(cls.isArray()){
			//为数组中元素重新赋值
			Array.set(str, 0, "abcd");
			//获取数组指定位置的元素
			String s=(String) Array.get(str, 0);
			System.out.println(s);
		}
	}
}

运行结果:

abcd



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值