黑马程序员——反射
来源:互联网 发布:青海干部网络教育平台 编辑:程序博客网 时间:2024/05/22 02:06
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
反射的基础:Class
Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class
Class和class的区别
class:描述一类事物的共性抽取
Class:类文件共性内容的抽取
获取字节码文件的三种方式:
方式一:Object类中的getClass()方法的,格式:对象.getClass()
想要用这种方式,必须要明确具体的类,并创建对象。
方式二:任何数据类型都具备一个静态的属性.class来获取其对应的Class对象
格式:类名.Class
方式三:只要通过给定的类的字符串名称就可以获取该类,更为扩展
可是用Class类中的方法完成,只要有名称即可,更为方便,扩展性更强
格式: Class.forName(“类名”)
如:Class clazz=Class.forName("包名.Student");//Student是一个类名
如:Class clazz=Class.forName("包名.Student");//Student是一个类名
String str1=”abc”;Class cls1=str.getClass();C lass cls2=String.class;Class cls3=Class.forName(“java.lang.String”);System.out.println(cls1==cls2);//trueSystem.out.println(cls1==cls3);//true
九种预定义的Class
包括八种基本类型(byte、short、int、long、float、double、char、boolean)的字节码对象和一种返回值为void类型的void.class
如:Class cls1=void.class;
isPrimitive():是否是基本类型字节码
String str1="sdfssg";
注意:String不是基本数据类型
System.out.println(str1.getClass().isPrimitive());//false
System.out.println(int.class.isPrimitive());//true
System.out.println(int.class==Integer.class);//false
System.out.println(int.class==Integer.TYPE);//true
Integer.TYPE是Integer类的一个常量,它代表此包装类型包装的基本类型的字节码,所以和int.class是相等的,本数据类型的字节码都可以用与之对应的包装类中TYPE常量表示
数组类型的Class实例对象:int[].class.isArray()
总之,只要是在源程序中出现的类型,都有各自的Class实例对象
Constructor类反射:就是把Java类中的各种成分映射成为相应的java类
反射机制:JAVA反射机制是在运行状态中,对于任意一个类 (class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
得到一个类的所有构造方法:
Constructor[] cons = Class.forName(“cn.itheima.Person”).getConstructors();
得到一个构造方法:
Constructor con=Person.class.getConstructor(String.class,int.class);
Constructor constructor=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
创建实例对象:
通常方式:String str=new String(new StringBuffer(“abc”)):
反射方式:String str=(String)constructor.newlstance(newStringBuffer(“abc”)):
成员变量的反射调用获得的方法时要用到上面相同类型的实例对象
Field类:Field类代表某个类中一个成员变量
常用方法
Field getField(String s);只能获取公有和父类中公有
Field getDeclaredField(String s);获取该类中已声明的成员变量,包括私有
setAccessible(ture);是私有字段,要先将该私有字段进行取消权限检查的能力,称暴力访问
set(Object obj, Object value);将指定对象变量上此Field对象表示的字段设置为指定的新值
Object get(Object obj);返回指定对象上Field表示的字段的值
public class ReflectPoint { private int x; public int y; public ReflectPoint(int x,int y) { super(); this.x = x; this.y = y; } }ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y");
// fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值
System.out.println(fieldY.get(pt1));//获取pt1对象上面y的值
FieldfieldX = pt1.getClass().getDeclaredField("x");//获取私有成员变量
fieldX.setAccessible(true);//暴力反射,强制使私有变量可以被访问
System.out.println(fieldX.get(pt1));
需求:将一个对象某个值改变。如将ball,basketball,package三个值里面的b换成a
public class StringPoint { Stringstr1="ball"; Stringstr2="basketball"; Stringstr3="package"; @Override //确定toString方法是否写对,写对了则不报错 public String toString(){ returnstr1 + "::" +str2 + "::" +str3; }}
import java.lang.reflect.Field;public class ChangeStringValueTest { public static void main(String[] args)throws Exception { // TODO Auto-generated method stub StringPointsp1=new StringPoint(); System.out.println("字符串改变之前:"+sp1); changeStringValue(sp1,'b','a'); System.out.println("字符串改变之后:"+sp1); } private static void changeStringValue(Objectobj,char oldChar,char newChar)throws Exception { // TODO Auto-generated method stub Field[]fields=obj.getClass().getFields(); for(Field field : fields){ //if(field.getType()equals(String.class)) //用==比equals更好,因为每个字节码文件是唯一的 if(field.getType()==String.class){ StringoldValue=(String)field.get(obj); StringnewValue=oldValue.replace(oldChar, newChar); field.set(obj,newValue); } } }}
Method类
代表某个类中的一个成员方法
Method getMethod(String name, Class<?>...parameterTypes) ; 返回一个 Method 对象,它反映此Class对象所表示的类或接口的指定公共成员方法
Method[] getMethods();返回一个包含某些Method 对象的数组,这些对象反映此Class 对象所表示的类或接口的公共member 方法。
Object invoke(Object obj, Object... args); 对带有指定参数的指定对象调用由此Method 对象表示的底层方法,如果传递给Method对象的invoke()方法的第一个参数为null,说明Method对象对应的是一个静态方法
Method getDeclaredMethod(String name, Class<?>...parameterTypes);返回一个Method 对象,反映此Class 对象所表示的类或接口的指定已声明方法。
String str2="asfsdgdfhgf";
Method methodCharAt=String.class.getMethod("charAt",int.class);
System.out.println(methodCharAt.invoke(str2, 2));
需求:写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法.
分析:在给main方法传递参数时,不能使用代码 mainMethod.invoke(null,newString[](“xxx“),javac只把它当做1.4的语法进行理解,而不把它当做jdk1.5的语法理解,因此会出现参数类型不对的问题。
编译器会做特殊处理,编译时不把参数当做数组看待,也就不会把数组打散成若干参数了。
数组的反射import java.lang.reflect.Method;public class ReflectTest1 { public static void main(String[] args)throws Exception{ //TestArguments.main(newString[]{"1","2","3"});一般方法 StringstartingClassName=args[0]; MethodmainMethod=Class.forName(startingClassName).getMethod("main",String[].class); //mainMethod.invoke(null, newString[]{"1","2","3"}); /*mainMethod方法在调用invoke接收一个字符串数组,由于jdk1.5在兼容jdk1.4时,当给一个字符串数组时,会通过自动拆箱功能将数组拆开,每一个元素作为一个一个参数,为了解决这个问题,在打一个包。有两种方式*/ mainMethod.invoke(null,new Object[]{new String[]{"1","2","3"}}); mainMethod.invoke(null, (Object)new String[]{"1","2","3"}); }} class TestArguments{ public static void main(String[] args){ for(String arg:args){ System.out.println(arg); } }}
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class
基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用;
非基本类型的一维数组,既可以当做Object类型使用,又可以当作Object[]类型使用
int[] a1=new int[3];int[] a2=new int[3];int[][] a3=new int[3][2];String[]a4=new String[3];System.out.println(a1.getClass() == a2.getClass());//trueSystem.out.println(a1.getClass()== a3.getClass());//falseSystem.out.println(a1.getClass()== a4.getClass());//falseSystem.out.println(a1.getClass().getName());//[I表示整数类型的数组System.out.println(a3.getClass().getName());//[[ISystem.out.println(a1.getClass().getSuperclass().getName());//java.lang.ObjectSystem.out.println(a3.getClass().getSuperclass().getName());//java.lang.ObjectObject obj1=a1;Object obj2=a3;Object[] obj3=a1;//基本类型不是Object,因此不能装换成Object数组Object[]object4=a3;Object obj5=a4;Object[] obj6=a4;
需求:打印数组内容
int[] b=new int[]{1,2,3};String[]str=new String[]{"asf","ada","aa"};System.out.println(b);//[I@75e4fc打印数组哈希值System.out.println(str);//[Ljava.lang.String;@c62c8System.out.println(Arrays.asList(b));//[[I@75e4fc]/*对于整数(基本类型)jdk1.4处理Object类型数组,因此不能不识别整数类型,jdk1.5处理则等效于一个Object,一个参数*/System.out.println(Arrays.asList(str));//[asf,ada,aa]
需求:用数组反射打印数组
反射的作用--------->实现框架功能private static void printObject(Object obj) { Class clazz=obj.getClass(); if(clazz.isArray()){ int len=Array.getLength(obj); for(int x=0;x<len;x++){ System.out.println(Array.get(obj, x)); } } else System.out.println(obj);}
1、框架与框架要解决的核心问题
我做房子卖给用户住,由用户自己安装门和空调,我做的房子就是框架,用户要使用我的框架,把门窗插入进我提供的框架中。框架与工具类具有区别,工具类被用户的类调用,而框架则是调用用户提供的类
2、框架要解决的核心问题
在写程序时无法知道被调用的类名,所以,在程序中无法直接new某个类的示例对象了,而要用反射方式来做
需求:采用配置文件加反射的方式创建ArrayList和HashSet的实例对象,比较观察运行结果的差异。
注意:当一个对象被存储进hashSet集合中,就不能修改这个对象中的那些参与计算哈希值的字段了。如果修改了,则在remove此对象时,不能删除掉。因为修改那些字段时,对象的哈希值改变了,不是原来的值,容易导致内存泄露。
反射即不要出现具体类的名字,而是从配置文件中读取,通过Class.forName(“”)’
import java.io.FileInputStream;import java.io.InputStream;import java.util.Collection;import java.util.HashSet;import java.util.Properties;public class ReflectTest2 { public static void main(String[] args)throws Exception { //加载Properties文件,面向父类或接口编程 InputStreaminp=new FileInputStream("config.properties"); //定义Properties对象 Propertiespro=new Properties(); pro.load(inp); inp.close(); StringclassName=pro.getProperty("className"); Collectioncollection=(Collection)Class.forName(className).newInstance(); //Collection collections=new HashSet(); ReflectPointpt1=new ReflectPoint(3, 4); ReflectPointpt2=new ReflectPoint(4, 4); ReflectPointpt3=new ReflectPoint(3, 4); collection.add(pt1); collection.add(pt2); collection.add(pt3); collection.add(pt1); System.out.println(collection.size()); }}
当配置文件中的配置为:className = java.util.HashSet 时结果为: 3
当配置文件中的配置为: className = java.util.ArrayList 时结果为: 4
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
- 黑马程序员—反射
- 黑马程序员—反射
- 黑马程序员—反射
- 黑马程序员—反射
- 黑马程序员—反射
- 黑马程序员—反射
- 黑马程序员—反射
- 黑马程序员—反射
- 黑马程序员——反射
- 黑马程序员——反射
- 黑马程序员——反射
- 黑马程序员——反射
- 黑马程序员——反射
- 黑马程序员——反射
- 黑马程序员——反射
- 黑马程序员——反射
- 黑马程序员——反射
- 黑马程序员——反射
- 在Ubuntu 14.04 64bit上安装百度云Linux客户端BCloud
- HDOJ 2080 夹角有多大II
- 破解android手机屏幕九宫格锁屏
- unique_ptr
- 如果希望使用中文,必须进行两次encodeURI()编码
- 黑马程序员——反射
- 智者无敌观后感
- 对话框嵌入到对话框 或者:窗口嵌入到窗口,一个窗口嵌入到另一个窗口
- linux下mysql日常用法
- JSP结合JXL.jar包实现网页Table显示读取到的Excel表格
- android 自定义VIew 动态在页面中改变页面的布局
- hdu2673 sort水题,一遍过
- 微软2014年在线笔试题前两题
- android EditText控件修改默认选中事件