黑马程序员-正则表达式

---------------------- android培训java培训、期待与您交流! ----------------------

 

反射

反射就是将java类中的各种成分反射成相应的java类。

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



得到一个类字节码的两种情况

1.这个类的字节码已经加载到内存中,直接返回已存在的那份字节码

2.如果内存中还没有这个类的字节码,用类加载器将字节码加载进内存并缓存起来,返回加载进来的字节码。



获取类字节码的三种方式

1.类名.class,比如Person类的字节码Person.class

2.对象.getClass(),如new Person().getClass().

3.Class.forName(className),如Class.forName(“java.lang.String”);



Constructor类获取某个类的构造方法

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

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

例子:Constructor[] constructors = Class.forName(“java.lang.String”).getConstructors();

得到某一个构造方法

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

创建实例对象

通常方式:String str = new String(new StringBuffer(“abc”));

反射方式:String str = (String)constructor.newInstance(new StringBuffer(“abc”));




Field类,获取某个类的字段

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

Java代码
  1. package cn.itcast.reflect;
  2. import java.lang.reflect.*;
  3. class Student
  4. {
  5. public String name;
  6. private int age;
  7. Student(){}
  8. Student(String name,int age)
  9. {
  10. this.name =name;
  11. this.age = age;
  12. }
  13. }
  14. public class ReflectTest
  15. {
  16. public static void main(String[] args)throws Exception
  17. {
  18. Student stu = new Student(“何竹冬”,25);
  19. //访问公有属性name
  20. Field fieldName = stu.getClass().getField(“name”);
  21. //暴力反射,访问私有属性
  22. Field fieldAge = stu.getClass().getDeclaredField(“age”);
  23. fieldAge.setAccessible(true);//将age属性设置为可访问
  24. System.out.println(fieldName.get(stu)+”...”+fieldAge.get(stu));
  25. }
  26. }
package cn.itcast.reflect; 
import java.lang.reflect.*; 
class Student 
{ 
public String name; 
private int age; 
Student(){} 
Student(String name,int age) 
{ 
this.name =name; 
this.age = age; 
} 
} 

public class ReflectTest 
{ 
public static void main(String[] args)throws Exception 
{ 
Student stu = new Student(“何竹冬”,25); 
//访问公有属性name 
Field fieldName = stu.getClass().getField(“name”); 

//暴力反射,访问私有属性 
Field fieldAge = stu.getClass().getDeclaredField(“age”); 
fieldAge.setAccessible(true);//将age属性设置为可访问 
System.out.println(fieldName.get(stu)+”...”+fieldAge.get(stu)); 
} 
} 





Method类,获取某个类的方法

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


得到类中的某一个方法

例如 Method charAt = Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);

通过反射调用方法

String str = “abc”;

charAt.invoke(str,1);


用反射执行某个类中的main方法
问题:

启动java程序main方法参数是一个字符串数组,即public static void main(String[] args),通过反射方式调用main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法整个数组是一个参数,而按jdk1.4的语法,数组中每一个元素对于一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac到底会按照那种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按照jdk1.4的语法进行处理,即把数组打散成若干个单独的参数。所以,在给main方法传参数时,不能使用代码mainMethod.invoke(null,new String[]{“xxxx”});java只把它作为jdk1.4语法进行理解,而不把它作为jdk1.5语法解释,因此会出现参数类型不对的问题。

解决办法:

Java代码
  1. mainMethod.invoke(null,new Object[]{new String[]{“xxxx”}})
  2. mainMethod.invoke(null,(Object)new String[]{“xxxx”});
mainMethod.invoke(null,new Object[]{new String[]{“xxxx”}}) 
mainMethod.invoke(null,(Object)new String[]{“xxxx”}); 


代码体现:
Java代码
  1. import java.lang.reflect.*;
  2. public class Test
  3. {
  4. public static void main(String[] args) throws Exception
  5. {
  6. String startingClassName = args[0];
  7. Method mainMethod= Class.forName(startingClassName).getMethod(“main”,String[].class);
  8. //将字符串数组作为Object数组的一个元素
  9. mainMethod.invoke(null,new Object[]{new String[]{“111”,”222”,”333”}});
  10. }
  11. }
  12. class TestArguments
  13. {
  14. public static void main(String[] args)
  15. {
  16. for(String arg : args)
  17. System.out.println(arg);
  18. }
  19. }
import java.lang.reflect.*; 
public class Test 
{ 
public static void main(String[] args) throws Exception 
{ 
String startingClassName = args[0]; 
Method mainMethod=  Class.forName(startingClassName).getMethod(“main”,String[].class); 
//将字符串数组作为Object数组的一个元素 
mainMethod.invoke(null,new Object[]{new String[]{“111”,”222”,”333”}}); 
} 
} 

class TestArguments 
{ 
public static void main(String[] args) 
{ 
for(String arg : args) 
System.out.println(arg); 
} 
} 




数组的反射
特点:
1.具有相同维数和元素类型的数组属于同一类型,即具有相同的Class实例对象。
2.代表数组的Class实例对象的getSupperClass()方法返回的父类为Object类对应的Class。
3.基本类型的一维数组可以当做Object类型来使用,不能当做Object[]来使用;
非基本类型的一维数组既可以当做Object类型来使用,也可以当做Object[]来使用。


Java代码
  1. int[] a1 = new int[3];
  2. int[] a2 = new int[4];
  3. int[][] a3 =new int[2][3];
  4. String[] a4 = new String[3];
  5. System.out.println(a1.getClass()==a2.getClass());//元素数据类型和数组维度相同是同一份字节码
  6. System.out.println(a1.getClass()==a3.getClass());//元素数据类型相同,数组维度不同不是同一份字节码
  7. System.out.println(a1.getClass()==a4.getClass());//元素数据类型不同,数组维度也不同不是同一份字节码
int[] a1 = new int[3]; 
int[] a2 = new int[4]; 
int[][] a3 =new int[2][3]; 
String[] a4 = new String[3]; 
System.out.println(a1.getClass()==a2.getClass());//元素数据类型和数组维度相同是同一份字节码 
System.out.println(a1.getClass()==a3.getClass());//元素数据类型相同,数组维度不同不是同一份字节码 
System.out.println(a1.getClass()==a4.getClass());//元素数据类型不同,数组维度也不同不是同一份字节码 




反射的综合案例
ArrayList和HashSet以及hashCode分析
1. ArrayList可以存储相同元素
2. HashSet不可以存储相同元素,和其他哈希结构的集合判断元素唯一的依据是hashCode和equals方法。
3. hashCode的由来
我们要判断集合中是否存在某一个元素要遍历这个集合进行查找,这样效率很低,有人发明了一种方法,将集合分成几个区域,每个对象可以算出一个哈希码,将这些哈希码分组,不同的哈希码对于不同的存储区域,要判断集合中是否有某个元素,根据它的哈希码去指定的区域查找即可,这样大大提高了效率。
4. 当一个对象被存储进HashSet集合中以后,就不要在修改这个对象中那些参与计算哈希值的字段,否则,对象修改后的哈希值与最初存储进HashSet集合时的哈希值就不同了。在这种情况下,即使在contains方法是用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet中单独删除当前对象,从而造成内存泄露。
代码示例:演示反射获取ArrayList和HashSet的元素个数,以及复写hashCode和equals方法
要往集合中添加的对象所属的类ReflectPoint
Java代码
  1. package cn.itheima.reflect;
  2. /**
  3. * 要往集合中添加的对象所属的类ReflectPoint
  4. * @author zhanggeng
  5. *
  6. */
  7. public class ReflectPoint {
  8. private int x;
  9. @Override
  10. public int hashCode() {
  11. final int prime = 31;
  12. int result = 1;
  13. result = prime * result + x;
  14. result = prime * result + y;
  15. return result;
  16. }
  17. @Override
  18. public boolean equals(Object obj) {
  19. if (this == obj)
  20. return true;
  21. if (obj == null)
  22. return false;
  23. if (getClass() != obj.getClass())
  24. return false;
  25. ReflectPoint other = (ReflectPoint) obj;
  26. if (x != other.x)
  27. return false;
  28. if (y != other.y)
  29. return false;
  30. return true;
  31. }
  32. public int y;
  33. ReflectPoint(int x,int y) {
  34. this.x = x;
  35. this.y = y;
  36. }
  37. }
package cn.itheima.reflect; 
/** 
* 要往集合中添加的对象所属的类ReflectPoint 
* @author zhanggeng
* 
*/ 
public class ReflectPoint { 
private int x; 
@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; 
ReflectPoint other = (ReflectPoint) obj; 
if (x != other.x) 
return false; 
if (y != other.y) 
return false; 
return true; 
} 

public int y; 

ReflectPoint(int x,int y) { 
this.x = x; 
this.y = y; 
} 


} 


演示:ArrayList和HashSet集合元素的存储,以及通过反射获取集合

Java代码
  1. package cn.itheima.reflect;
  2. import java.util.ArrayList;
  3. import java.util.Collection;
  4. import java.util.HashSet;
  5. /**
  6. * 演示:ArrayList和HashSet集合元素的存储,以及通过反射获取集合
  7. * @author zhanggeng
  8. *
  9. */
  10. public class ReflectTest {
  11. /**
  12. * @param args
  13. */
  14. public static void main(String[] args) {
  15. testArrayList();
  16. testHashSet();
  17. }
  18. public static void testArrayList() {
  19. Collection coll = new ArrayList();
  20. //ArrayList可以存放相同元素,所以打印size应该是3
  21. coll.add(new ReflectPoint(3,3));
  22. coll.add(new ReflectPoint(5,5));
  23. coll.add(new ReflectPoint(3,3));
  24. System.out.println("the size of ArrayList is "+coll.size());
  25. }
  26. public static void testHashSet() {
  27. Collection coll = new HashSet();
  28. //HashSet不可以存放相同元素,判断元素是否相同的依据是hashCode和equals方法,
  29. //所以打印size应该是2
  30. coll.add(new ReflectPoint(3,3));
  31. coll.add(new ReflectPoint(5,5));
  32. coll.add(new ReflectPoint(3,3));
  33. System.out.println("the size of HashSet is "+coll.size());
  34. }
  35. }
package cn.itheima.reflect; 

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.HashSet; 

/** 
* 演示:ArrayList和HashSet集合元素的存储,以及通过反射获取集合 
* @author zhanggeng
* 
*/ 
public class ReflectTest { 

/** 
* @param args 
*/ 
public static void main(String[] args) { 
testArrayList(); 
testHashSet(); 
} 

public static void testArrayList() { 
Collection coll = new ArrayList(); 
//ArrayList可以存放相同元素,所以打印size应该是3 
coll.add(new ReflectPoint(3,3)); 
coll.add(new ReflectPoint(5,5)); 
coll.add(new ReflectPoint(3,3)); 
System.out.println("the size of ArrayList is "+coll.size()); 
} 

public static void testHashSet() { 
Collection coll = new HashSet(); 
//HashSet不可以存放相同元素,判断元素是否相同的依据是hashCode和equals方法, 
//所以打印size应该是2 
coll.add(new ReflectPoint(3,3)); 
coll.add(new ReflectPoint(5,5)); 
coll.add(new ReflectPoint(3,3)); 
System.out.println("the size of HashSet is "+coll.size()); 
} 

} 






反射的作用-->实现框架功能

框架与框架要解决的核心问题

我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入我提供的框架中。框架与工具的区别是,工具类被用户的类调用,框架调用用户提供的类。


框架要解决的核心问题

我在写框架(房子时),你这个用户可能还在上小学,还不会写程序呢?我写的框架怎样调用以后你写的类(门窗)呢?

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

具体实现:
用配置文件加反射的方式创建ArrayList和HashSet的实例对象。




--------------加载配置文件的三种方法----------
配置文件配置config.properties
#className=java.util.HashSet
className=java.util.ArrayList
配置文件给用户用的时候通常是和class文件放在一起的,也就是在class文件所在的包或者子包里。得到配置文件的输入流对象,用Properties对象的load方法加载。
1.通过FileInputStream加载,相对项目路径,如果配置文件在相对于项目路径下。
InputStream ips = new FileInputStream("config.properties");
实际开发中,这种方式的路径是根据getRealPath()和配置文件名拼接得到的。而不是硬编码方式。
2.通过ClassLoader的getResourceAsStream方法,在classpath(bin目录)下查找路径需要加包名路径
InputStream ips = ReflectTest.class.getClassLoader().getResourceAsStream("cn/itheima/reflect/resources/config.properties");
3.通过字节码class对象的getResourceAsStream方法,直接在class当前包下查找不用加包路径
InputStream ips = ReflectTest.class.getResourceAsStream("resources/config.properties");
最后,将输入流对象ips作为参数传入Properties的load方法,并获取className
Properties p = new Properties();
p.load(ips);

代码演示:通过三种方式加载配置文件,以及通过反射获取集合ArrayList或HashSet实例对象
Java代码
  1. package cn.itheima.reflect;
  2. import java.io.FileInputStream;
  3. import java.io.InputStream;
  4. import java.util.Collection;
  5. import java.util.Properties;
  6. /**
  7. * 演示:通过三种方式加载配置文件,以及通过反射获取集合
  8. * @author zhanggeng
  9. *
  10. */
  11. public class ReflectTest {
  12. public static void main(String[] args) throws Exception{
  13. //通过指定的方式加载配置文件并获取ArrayList或HashSet对象
  14. Collection coll = getCollectionByClass();
  15. /*向集合中添加元素*/
  16. coll.add(new ReflectPoint(3,3));
  17. coll.add(new ReflectPoint(5,5));
  18. coll.add(new ReflectPoint(3,3));
  19. //打印集合中元素个数,ArrayList时为3,HashSet时为2
  20. System.out.println(coll.size());
  21. }
  22. /**
  23. * 用FileInputStream加载配置文件并获取集合实例对象
  24. * @return 返回集合实例对象
  25. * @throws Exception 为了演示代码,没有处理异常
  26. */
  27. public static Collection getCollectionByFileInputStream() throws Exception{
  28. /*获取Properties对象并通过FileInputStream加载配置文件获取className*/
  29. Properties p = new Properties();
  30. //相对于项目路径如果配置文件放在eclipse项目相对路径下
  31. InputStream ips = new FileInputStream("config.properties");
  32. p.load(ips);
  33. ips.close();
  34. String className = p.getProperty("className");
  35. /*获取集合实例对象*/
  36. Class clazz = Class.forName(className);
  37. Collection coll = (Collection)clazz.newInstance();
  38. return coll;
  39. }
  40. /**
  41. * 用ReflectTest类的加载器去加载配置文件并获取集合实例对象
  42. * @return 返回集合的实例对象
  43. * @throws Exception 为了演示代码,没有处理异常
  44. */
  45. public static Collection getCollectionByClassLoader() throws Exception {
  46. /*获取Properties对象并通过ClassLoader加载配置文件获取className*/
  47. Properties p = new Properties();
  48. //相对于classpath路径(bin目录)路径
  49. InputStream ips = ReflectTest.class.getClassLoader().
  50. getResourceAsStream("cn/itheima/reflect/resources/config.properties");
  51. p.load(ips);
  52. ips.close();
  53. String className = p.getProperty("className");
  54. /*获取集合实例对象*/
  55. Class clazz = Class.forName(className);
  56. Collection coll = (Collection)clazz.newInstance();
  57. return coll;
  58. }
  59. /**
  60. * 通过Class字节码对象的getresourceAsStream方法加载配置文件,并获取集合实例对象
  61. * @return 返回集合的实例对象
  62. * @throws Exception 为了演示代码,没有处理异常
  63. */
  64. public static Collection getCollectionByClass() throws Exception {
  65. /*获取Properties对象,
  66. * 并通过Class字节码对象的getResourceAsStream方法加载配置文件获取className
  67. */
  68. Properties p = new Properties();
  69. //相对class文件包目录
  70. InputStream ips = ReflectTest.class.getResourceAsStream("resources/config.properties");
  71. p.load(ips);
  72. ips.close();
  73. String className = p.getProperty("className");
  74. /*获取集合实例对象*/
  75. Class clazz = Class.forName(className);
  76. Collection coll = (Collection)clazz.newInstance();
  77. return coll;
  78. }
  79. }
package cn.itheima.reflect; 

import java.io.FileInputStream; 
import java.io.InputStream; 
import java.util.Collection; 
import java.util.Properties; 

/** 
* 演示:通过三种方式加载配置文件,以及通过反射获取集合 
* @author zhanggeng
* 
*/ 
public class ReflectTest { 
public static void main(String[] args) throws Exception{ 
//通过指定的方式加载配置文件并获取ArrayList或HashSet对象 
Collection coll = getCollectionByClass(); 
/*向集合中添加元素*/ 
coll.add(new ReflectPoint(3,3)); 
coll.add(new ReflectPoint(5,5)); 
coll.add(new ReflectPoint(3,3)); 

//打印集合中元素个数,ArrayList时为3,HashSet时为2 
System.out.println(coll.size()); 
} 
/** 
* 用FileInputStream加载配置文件并获取集合实例对象 
* @return 返回集合实例对象 
* @throws Exception 为了演示代码,没有处理异常 
*/ 
public static Collection getCollectionByFileInputStream() throws Exception{ 
/*获取Properties对象并通过FileInputStream加载配置文件获取className*/ 
Properties p = new Properties(); 
//相对于项目路径如果配置文件放在eclipse项目相对路径下 
InputStream ips = new FileInputStream("config.properties"); 
p.load(ips); 
ips.close(); 
String className = p.getProperty("className"); 

/*获取集合实例对象*/ 
Class clazz = Class.forName(className); 
Collection coll = (Collection)clazz.newInstance(); 
return coll; 
} 
/** 
* 用ReflectTest类的加载器去加载配置文件并获取集合实例对象 
* @return 返回集合的实例对象 
* @throws Exception 为了演示代码,没有处理异常 
*/ 
public static Collection getCollectionByClassLoader() throws Exception { 
/*获取Properties对象并通过ClassLoader加载配置文件获取className*/ 
Properties p = new Properties(); 
//相对于classpath路径(bin目录)路径 
InputStream ips = ReflectTest.class.getClassLoader(). 
getResourceAsStream("cn/itheima/reflect/resources/config.properties"); 
p.load(ips); 
ips.close(); 
String className = p.getProperty("className"); 

/*获取集合实例对象*/ 
Class clazz = Class.forName(className); 
Collection coll = (Collection)clazz.newInstance(); 
return coll; 

} 
/** 
* 通过Class字节码对象的getresourceAsStream方法加载配置文件,并获取集合实例对象 
* @return 返回集合的实例对象 
* @throws Exception 为了演示代码,没有处理异常 
*/ 
public static Collection getCollectionByClass() throws Exception { 
/*获取Properties对象, 
* 并通过Class字节码对象的getResourceAsStream方法加载配置文件获取className 
*/ 
Properties p = new Properties(); 
//相对class文件包目录 
InputStream ips = ReflectTest.class.getResourceAsStream("resources/config.properties"); 
p.load(ips); 
ips.close(); 
String className = p.getProperty("className"); 

/*获取集合实例对象*/ 
Class clazz = Class.forName(className); 
Collection coll = (Collection)clazz.newInstance(); 
return coll; 

} 
} 





----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值