黑马程序员-反射(高新技术)

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

 

1:什么是反射:反射的概念主要指类可以访问、检测和修改它本身状态或行为的一种能力,它能让java类自身进行检查,并能直接操作类的内部属性。

反射总结:就是把Java类中的所有成分反射成不同的java

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

 

反射的基石àClass类

1.所有的类文件都有共同属性,所以可以向上抽取,把这些共性内容封装成一个类,这个类就叫Class(描述字节码文件的对象)。

        Class类中就包含属性有field(字段)、method(方法)、construction(构造函数)。

       field中有修饰符、类型、变量名等复杂的描述内容,因此也可以将字段封装称为一个对象。用来获取类中field的内容,这个对象的描述叫Field。同理方法和构造函数也被封装成对象MethodConstructor。要想对一个类进行内容的获取,必须要先获取该字节码文件的对象。该对象是Class类型。

       Class类描述的信息:类的名字,类的访问属性,类所属于的包名,字段名称的列表,方法名称的列表等。每一个字节码就是class的实例对象。如:classcls=Data.class;

什么是字节码:

       当源程序中用到类时,首先要从硬盘把这个类的那些二进制代码,一个类编译成class放在硬盘上以后,就是一些二进制代码,要把这些二进制代码加载到内存中里面来,再用这些字节码去复制出一个一个对象来。

2Classclass的区别

       1classJava中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。

       2Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是ClassClassJava程序中各个Java类的总称;它是反射的基石,通过Class类来使用反射。

反射的作用(重点):

可以通过反射机制取得对象的类型

取得对象的方法、属性、构造器

可以创建对象并访问任意对象方法和属性

反射两个缺点:

性能问题。用于字段和方法介入时反射要远慢与直接的代码

使用反射会模糊程序内部实际要发生的事情,使程序对程序逻辑的可读性变差

 

得到字节码对象的方式有三种

1)在源程序里直接写上类的名字.class         例:Person.class

2)在通过对象调用getClass(),返回字节码             例:per.getClass()

3)用Class类的静态方法去查询或加载字节码             

例:Class.forName(“类名”) 

PS:一般开发都用第三种,传入字符串即可得到类的字节码

问:以下得到的三个字节码是不是同一份?

                String str1 = "abc";
		Class cls1 = str1.getClass();
		Class cls2 = String.class;
		Class cls3 = Class.forName("java.lang.String");
		System.out.println(cls1 == cls2);//输出true
		System.out.println(cls1 == cls3); //输出true

面试提问:Class.forName(“类名”)的作用是什么?

回答:

有两个作用

1:如果该类的字节码曾经被加载过,那么直接返回该类的字节码:

2:如果该类还没有被加载进内存,那么此时就进行加载该类的字节码,缓存在内存中,并返回字节码对象

 

回答:得到的都是同一份字节码

 

isprimitive():判断一个类是不是一个基本类型的方法

isArray():判断一个类是不是数组类型的方法

代码:

                String str1 = "abc";
		Class cls1 = str1.getClass();
		System.out.println(cls1.isPrimitive());//结果为false, 说明String不是基本类型
		System.out.println(int.class.isPrimitive());//结果为true
		System.out.println(int.class == Integer.class); //结果为true
		System.out.println(int.class == Integer.TYPE); //结果为true
		System.out.println(int[].class.isPrimitive());//结果为false
		System.out.println(int[].class.isArray());	  //结果为true
                System.out.println(int.Class.isprimitive());//结果为true

总之,在源程序中出现的数据类型,都有各自对应的Class实例对象

九个预定义Class实例对象,即八个基本数据类型(booleanbytecharshortintlongfloat double)和一个void类型的字节码对象。也就是说他们都有自己的Class对象,void的是void.class

 

反射就是把Java类中的各个成分映射成相应的java类。而Class类提供了一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息。这些信息就是用相应的类的实例对象来表示的,他们是Field(变量或字段)Method(方法)Contructor(构造器)Package()等等

获取类中的方法

getDeclaredMethods():取得类中定义了的所有的方法列表

(包括privatepublicprotectedpacked),但是不包括从父类中继承来的方法

使用:字节码对象.getDeclaredMethods(),返回值类型是Methods类型

 

getMethod(name,参数字节码):获取类的所有公有方法,包括从父类中继承来的方法,返回Method类型(这点是与getDeclaredMethods()的区别)

name为想取得的方法的名字,后面的参数的自己码为方法可能有多个重载形式,这里通过参数的字节码来识别

例:调用String类型的charAt()

String str = “abc”;

Method methodCharAt = str.getClass.getMethod(“charAt”,int.class);

System.out.println(methodCharAt.invoke(str,1));//传入要截取的字符串对象和要操作的下标

//输出是“b       ps: invoke()表示调用

如果invoke()中传入的对象是null,说明该方法对应的方法是静态方法,静态方法调用不需要对象

代码示例:

		Method methodCharAt = String.class.getMethod("charAt", int.class);
		System.out.println(methodCharAt.invoke(str1, 1));
		System.out.println(methodCharAt.invoke(str1, new Object[]{2}));
		
		//TestArguments.main(new String[]{"111","222","333"});
		String startingClassName = args[0];
		Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
		//mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
		mainMethod.invoke(null, (Object)new String[]{"111","222","333"});


 

获取类中的构造方法

getConstructor(A.class):取得类的构造方法(不能获取私有构造方法)

用法(字节码.getConstructor(A.class)),如果有多个构造方法,传入构造方法的所接收的类字节码,返回值类型是Constructor类型

getDeclaredConstructors():取得类中的所有构造方法(无论是私有还是公有)

用法(字节码.getDeclaredConstructors(),返回值类型是Constructor数组

PS通过getDeclaredConstructors()获取私有的构造方法,可以突破单例模式不能创建对象的限制,由外部创建对象

代码示例:

		Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
		String str2 = (String)constructor1.newInstance(/*"abc"*/new StringBuffer("abc"));
		System.out.println(str2.charAt(2));


 

例:得到String的构造方法    String.class.getConstructor()

String有不止一个构造方法,要得到哪一个构造方法,如何指定?

getConstructor()中传入参数,传入的参数同样为字节码,想得到的构造方法有几个对象就传几个字节码文件

如:String.class.getConstructor(StringBuffer.class)//这个就是得到参数为类型为StringBuffer.的构造方法

获取方法的参数类型

Type[] getGenericParameterTypes():按照声明顺序返回Type对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型的。如果底层方法不带参数,则返回长度为 0的数组。

用法:Type[] types = method. getGenericParameterTypes();

 

Field:类中的成员变量

取得某个类的某个成员变量:getFields(“name”),传入的name是成员的名字,但这种只能得到公有的成员,私有的不行(得到的只是变量,但是并不是得到变量的值,要得到变量的值要得到该变量后,再通过get(指定对象)包括父类中的定义的成员

要修改值用set(指定对象)

获取类中的成员变量

per.class.getFields(“age”),这样就得到了Person这个类的成员变量age,并不是得到age的值

getDeclaredField():也是得到成员变量,与getFields(“name”)的区别在于:无论公有私有都可以得到,不受权限的控制

代码:

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

public class ReflectTest {

	public static void main(String[] args) throws Exception {
		ReflectPoint pt1 = new ReflectPoint(3,5);
		Field fieldY = pt1.getClass().getField("y");
		//fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值
		System.out.println(fieldY.get(pt1));
		Field fieldX = pt1.getClass().getDeclaredField("x");
		fieldX.setAccessible(true);
		System.out.println(fieldX.get(pt1));	
		
		changeStringValue(pt1);
		System.out.println(pt1);
}
public class ReflectPoint {
	private Date birthday = new Date();
	
	private int x;
	public int y;
	public String str1 = "ball";
	public String str2 = "basketball";
	public String str3 = "itcast";
	
	public ReflectPoint(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final ReflectPoint other = (ReflectPoint) obj;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}
	@Override
	public String toString(){
		return str1 + ":" + str2 + ":" + str3;
	}
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	
}


 

练习(重点):得到一个类中的String类型的成员变量,并把成员变量的值中的ae来替换

private static void changeValue(Object obj)
{//注释为思路与步骤
	Field[] field = objgetClass.getFields();//得到所有的成员变量的数组
	For(Field field: Field)//遍历该数组,取出成员变量
        {
	        if(field.getType()==String.class)//判断取出的成员变量是否是String类型的
                {
	                String oldValue = field.get(obj);//取出obj该对象的String成员变量的值
	                String newValue = oldValue.replace(“a”,”e”);//替换字母后返回一个新的字符串
	                field.set(obj,newValue);//设置obj对象的String成员变量的新值
                }
        }
}




 

 

 

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值