黑马程序员——Java中的反射技术
来源:互联网 发布:steam上巫师三mac 编辑:程序博客网 时间:2024/04/28 17:40
------- android培训、java培训、期待与您交流! ----------
反射的基石——Class类
Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class
Class描述了哪些方面的信息呢?
类的名字 类的访问属性 类所属于的包名 字段名称的列表 方法名称的列表等,
使用Class类 那么怎么给Class类赋值呢?
其中的什么是字节码呢?
将一个类编译成class文件后放在硬盘上,就会生成一些二进制代码,要把这些二进制文件加载到内存中来,然后才可以创建一个一个的对象,首先要把字节码加载到类成员中来,在用字节码赋值出一个一个对象来
每一个字节码就是一个Class类的实例对象
Person p1=new Person();
Class cls1=Person.class; //字节码1;其中Person.class就表示Person类在内存中的那个字节码
Class cls2=字节码2;
Class.forName()的作用?就是返回字节码
返回的方式有两种:
1,这份字节码曾经被加载过,已经待在java虚拟机中了,就可以直接返回了
2,java虚拟机中还没有这份字节码,则用类加载器去加载,把加载进来的字节码,缓存到虚拟机中,以后要得到这个字节码就不用在加载了
得到字节码的方式有三种:
1,类名.class 例如:System.class
2,对象.getClass() 例如:new Date().getClass(); //有一个对象,这个对象一定是字节码创建出来的
3,Class.forName(“类名”) 例如:Class.forName(“java.util.Date”) //使用静态方法去加载
在反射中主要用到的是第三种
isPrimitive() 判断是否是原始类型
数组类型的Class实例对象
Class.isArray() 判断是否是数组
总之,只要是源程序中出现的类型,都有各自的Class实例对象,例如,int[] void
什么是反射?
反射就是把Java类中的各种成分映射成相应的java类。例如:一个java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个java类来表示,
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。
使用反射技术,应该导入的包是java.reflect.*;
反射会导致程序的性能严重下降
Constructor类:
Constructor类代表某个类中的构造方法
得到某个类所有的构造方法:
例子:Constructor constructors[]=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
得到某一个构造方法:
例子:Constructor constructor=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
也可写成
Constructor constructor=String.class.getConstructor(StringBuffer.class);
StringBuffer.class //获得方法时要用到的类型
创建实例对象:
通常方式:String str=new String(new StringBuffer(“abc”));
反射方式:String str=(String)constructor.newInstance(new StringBuffer(“abc”));
new StringBuffer(“abc”)//调用获得的方法时,要用到上面相同类型的实例对象
Class.newInstance()方法:
例子:String obj=(String)Class.forName(“java.lang.String”).newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象
该方法内部用到了缓存机制来保存默认构造方法的实例对象
使用反射的构造方法的简单示例:
import java.lang.reflect.*;
publicclass reflect {
publicstaticvoid main(String[] args)throws Exception
{
Constructor constructor=String.class.getConstructor(StringBuffer.class);
String str=(String)constructor.newInstance(new StringBuffer("abc"));
System.out.println(str.charAt(1));
}
}
Field类
Field类代表某个类中的一个成员变量
生成构造方法:
Alt+Shift+s ——Generate Constructor using Fileds….
定义一个类
publicclass reflectClass {
private intx;
public inty;
public reflectClass(int x,int y) {
super();
this.x = x;
this.y = y;
}
}
总结:
Field类代表一个字节码里面的一个变量,不代表某个对象身上的变量
Field fieldY=pt1.getClass().getField("y"); 因为y变量在类中是public类型的,所以在获取变量的时候可以用getField("y")
Field fieldX=pt1.getClass().getDeclaredField("x");
因为x变量在类中的是private类型的,所以在获取变量的时候必须要用getDeclaredField("x")
fieldX.setAccessible(true);//这个就是所谓的暴力反射,让变量的值强制可以去访问
例子:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改成“a”
自定义的类:
package itheima;
publicclass reflectClass {
private intx;
public int y;
public Stringstr1="ball";
public Stringstr2="basketball";
public Stringstr3="itcast";
public reflectClass(int x,int y) {
super();
this.x = x;
this.y = y;
}
publicString toString()
{
returnstr1+"::"+str2+"::"+str3;
}
}
主函数类:
import java.lang.reflect.*;
publicclass reflect {
publicstaticvoid main(String[] args)throws Exception
{
reflectClasspt1=newreflectClass(3, 5);
changeStringValue(pt1);
System.out.println(pt1);
}
private staticvoid changeStringValue(Object obj)throws Exception {
Field[] fields=obj.getClass().getFields();
for(Field field:fields)
if(field.getType()==String.class) //这里应该用==,因为是同一个字节码
{
String oldValue=(String)field.get(obj);
String newValue=oldValue.replace('b','a');
field.set(obj, newValue);
}
}
}
总结:
(1)Field[] fields=obj.getClass().getFields();这句话是要获取类中所有的成员变量
(2)使用增加for循环遍历所有的成员变量for(Field field:fields)
(3)if(field.getType()==String.class)这是应该使用==,因为是同一个字节码,这句话是用来判断变量的类型是否是String类型,如果是String类型的变量,就将其中的‘b’替换成‘a’。
(4)String oldValue=(String)field.get(obj);获取field对象中的值
(5)String newValue=oldValue.replace('b','a');将b替换成a
(6)field.set(obj, newValue);将对象身上的值更改,obj---pt1 对obj对象身上的field进行更改值,将其值设置为newValue
Method类:
Method类代表某个类中的一个成员方法
得到类中的某个方法:
例子: Method charAt=Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
调用的方法:
通常方式:System.out.println(str.charAt()1);
反射方式:System.out.println(chatAt.invoke(str,1));
如果传递给Method对象的invoke()方法的一个参数为null,这有着什么样的意义呢? 说明该Method对象对应的是一个静态方法!!
用反射的方式得到字节码中的方法,在拿这个方法去作用到某个对象 invoke是调用前面的方法 invoke表示方法对象上的方法
用反射方式执行某个类中的main方法
String start=args[0];
Method method=Class.forName(start).getMethod("main",String.class);
method.invoke(null,(Object)new String[]{"111","222","333"});
class TestArguments
{
publicstaticvoid main(String[] args)
{
for(String arg:args)
System.out.println(arg);
}
}
数组的反射:
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用,非基本类型的一维数组,即可以当作Object类型使用,又可以当作Object[]类型使用
Arrays.asList()方法处理int[]和String[]时的差异
Array工具类用于完成对数组的反射操作
总结:
如果使用数组的反射,那么每个数组都属于同一个字节码,但是必须具有相同的数据类型,以及具有相同的维度
如果对象想要得到字节码,必须使用方法getClass();
想要获取对象的字节码的名字,必须使用方法getName(); 因为是数组,所以在显示名字的时候,如果是int类型,则显示“[I”
这有个图:
在定义数组的时候,如果后面指定了值,前面就不能指定数组的个数
例如:
Int[] a1=new int[3]{1,2,3}; 这种方式是错的
Int[] a1=new int[]{1,2,3}; 这种方式是正确的
所有的类都有父类,除了Object类
Int[][] a3=new int[2][3];
Int[] a1=new int[3];
String[] a4=new String[3];
Object[] aObj3=a1; 这种方式不能用,因为基本类型的一维数组,不能转换成Object[] 数组的,因为这个数组中装的是int,不是Object
Object[] aObj4=a3; a3是二维数组,就相当于里面装入了int类型的一维数组,因为这个数组中装的是一维数组,一维数组是Object
Object[] aObj5=a4; 这个数组中装的是String类型 String也是Object类型
Arrays.asList()方法处理int[]和String[]时的差异:
String不属于基本数据类型
Int[] a1=new int[3]; 这个可以理解为,有一个数组,这个数组中装的是int类型,int是基本数据类型,不是Object
Arrays.asList(Object[] obj);
System.out.println(Arrays.asList(a1)); asList方法接收的是Object类型的数组,因为a1是int[]类型的数组,在向方法中传值的时候,Object[]这个数组认为和这个对象对不上,因为传入的值是int,基本数据类型,不能处理,jdk1.5版本可以处理
String[] a4=new String[3];这个可以理解为,有一个数组这个数组中装的是String类型,String类型是Object
System.out.println(Arrays.asList(a4)); 因为a4是String类型的数组,所以可以将数组中的值打印出来
思考题:怎么得到数组中元素的类型呢?
不能获取整个数组的类型,只能获取整个数组中某个元素的类型
Int[] a=new int[]{1,2,3};
Object a1=new Object[]{“a”,1,2}; //可以使用a[0].getClass().getName()来获取某个元素的类型
ArrayList—HashSet的比较及HashCode的分析
ArrayList和HashSet的区别:
ArrayList是一个有顺序的集合,有顺序的集合就相当于一个数组,在将对象放入集合中的时候,是将对象的引用放入进去,是按照依次的顺序先后放进去,如果一个对象有多个引用的时候,也是依次放入集合中的,可以明确的说取出第几个
(这里的顺序指的是位置的顺序)
HashSet是在向里面存入对象的引用的时候,先查看集合中有没有这个对象是否相等,如如果有这个对象,则不向里面存入
面试题:
HashCode方法的作用:
哈希算法来提高从集合中查找元素的效率,这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希吗分组,每组分对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储在哪个区域了。
当有一个对象的时候,先算出它属于哪一个区域,假如属于第五个区域,那么就不依次去找,只在第五区域找是否有与它相等的对象即可,这样就提高了程序的效率
要想hashCode的方法有价值,前提是对象必须存储在哈希集合中才有价值
ReflectPoint pt1=new ReflectPoint(3,3);
ReflectPoint p2=new ReflectPoint(4,4);
ReflectPoint pt3=new ReflectPoint(3,3);
如果没有实现hashCode方法为什么长度就等于3呢?虽然pt1和pt3这两个对象用equals比较是相等的,但是算出来的hashCode值pt1和pt3都是按照自己的内存地址去算的,这两个本来相同的对象,分别存在了不同的区域中,所以被放入到了集合中
为了让相等的对象放在相同的区域中,那么就应该是如果两个对象的equals方法相等,那么两个对象的hashCode方法也应该相等
如果集合不存在HashSet中,那么就没有必要使用hashCode方法了
提示:当一个对象被存储进HashSet集合中以后,就不能拿修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也讲返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露
所谓的内存泄露是我这个对象不要用了,但还一直占用内存的空间,没有被释放,这就叫内存泄露
反射的作用——>实现框架功能
框架与框架要解决的核心问题
:
例子:我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类
框架要解决的核心问题:
我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序呢?我写的框架程序怎样调用到你以后写的类(门窗)呢?
因为在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类得实例对象了,而要用反射方式来做。
框架和工具类的区别:
这两个类都是别人写的,一个是你调用人家,一个是人家调用你
框架是框架在调用用户的类
工具类是用户在调用工具类
例子:
config.properties类中:
className=java.util.HashSet
reflectSet类中:
package itheima;
import java.util.*;
import java.io.*;
importjava.lang.reflect.*;
publicclass reflectSet {
publicstaticvoid main(String[] args)throws Exception{
InputStream in=new FileInputStream("config.properties");
Properties prop=new Properties();
prop.load(in);
in.close();
//getProperty()这个方法是获取config.properties文件中的属性
String className=prop.getProperty("className");
Collection a1=(Collection)Class.forName(className).newInstance();
reflectClass pt1=new reflectClass(3, 3);
reflectClass pt2=new reflectClass(5, 5);
reflectClass pt3=new reflectClass(3, 3);
a1.add(pt1);
a1.add(pt2);
a1.add(pt3);
a1.add(pt1);
System.out.println(a1.size());
}
}
------- android培训、java培训、期待与您交流! ----------
- 黑马程序员——java中的反射技术再探
- 黑马程序员——Java中的反射技术
- 黑马程序员——Java中的反射技术
- 黑马程序员——java反射技术
- 黑马程序员——Java 反射技术
- 黑马程序员 java中的反射技术理解
- 黑马程序员——Java中的反射
- 黑马程序员——java中的反射
- 黑马程序员——java中的反射
- 黑马程序员——java中的反射
- 黑马程序员—Java中的反射机制
- 黑马程序员—java技术blog—第八篇:反射
- 黑马程序员——Java新技术反射技术1
- 黑马程序员——Java新技术反射技术2
- 黑马程序员——Java学习之反射技术
- 黑马程序员--Java反射技术
- 黑马程序员-java反射技术
- 黑马程序员—Java 反射
- storyboard之 prepareForSegue:sender:
- 计算机视觉、机器学习相关领域论文和源代码
- zookeeper学习之二(高级特性)
- 今天开始学习HTML5+CSS3!
- myeclipse中servers抛NullPinterException错误
- 黑马程序员——Java中的反射技术
- 一步步走进Android MaterialDesign 之 ToolBar动画效果(2)
- YT04-贪心课后练习-1002—Repair the Wall-(6.14日-烟台大学ACM预备队解题报告)
- Angrew. NG, Machine Learning, Class Note
- iOS评分功能、APP中打开其他应用程序
- 牛客网( C/C++工程师能力评估)
- poj1185 炮兵阵地
- http和socket通信的区别
- 筛法构建素数表