java-反射
来源:互联网 发布:基本款手提包 知乎 编辑:程序博客网 时间:2024/06/07 10:23
一.反射
反射就是把java类中的各个成分映射成相应的java类。
各个成分所对应的对象:Field Method Contructor Package
二.class类
java程序中的各个Java类属于同一个事务,描述这类事务java类的名字叫Class
字节码:
先将编译后的字节码加载到内存到,然后才能创建一个个对象。
每一个类创建一份字节码,
Person p1=new Person();
Pair<String> pair=new Pair<>(); System.out.println(pair.getClass()); Class.forName("day07.Pair");
Class.forName的作用是返回字节码,一种是字节码已经被加载过,另一种还没有加载,使用类加载器进行加载到虚拟机中。
获取类名的字节码:
类名.class;
对象.getClass();new Date().getClass()
Class.forName(“类名”),例如,Class.forName(“java.util.Date”)//反射经常用,类加载之前
public class Reflect {public static void main(String[] args) throws ClassNotFoundException { String str1="abc"; Class class1=str1.getClass();//对象获取class的方法 Class class2=String.class;//类型获取class的方法 Class class3=Class.forName("java.lang.String"); System.out.println(class1==class2); System.out.println(class2==class3);}}
原始的基本类型:八大基本类型
public class Reflect {public static void main(String[] args) throws ClassNotFoundException { String str1="abc"; Class class1=str1.getClass();//对象获取class的方法 Class class2=String.class;//类型获取class的方法 Class class3=Class.forName("java.lang.String"); System.out.println(class1==class2); System.out.println(class2==class3); //确定指定 类对象代表一个原始类型。 System.out.println(class1.isPrimitive());//isPrimitive()确定指定 类对象代表一个原始类型(8大基本类型)。 System.out.println(int.class.isPrimitive());//是原始的基本类型 System.out.println(int.class==Integer.class);//两个不相等 System.out.println(int.class==Integer.TYPE);//TYPE类代表原始类型的实例 int。 System.out.println(int[].class.isPrimitive());//不是原始的基本类型 System.out.println(int[].class.isArray());//判断是否为数组}}
结果
truetruefalsetruefalsetruefalsetrue
三.constructor类
constructor类:代表某个类中的构造方法
getConstructors():得到所有的构造方法
getConstructor():得到一个构造方法
四.成员变量的映射(Field类)
Field类代表某个类中的一个成员变量
Reflect_Point类public class Reflect_Point {private int x;public int y;public Reflect_Point(int x, int y) { super(); this.x = x; this.y = y;}}Reflect_Test类import java.lang.reflect.Field;public class Reflect_Test { public static void main(String[] args) throws ReflectiveOperationException, Exception { Reflect_Point r1=new Reflect_Point(3, 5); Field f1=r1.getClass().getField("y");//getclass获取字节码,getFiled获取字段 //f1不是对象身上的变量,而是类上的,用它取对象上对应的值 System.out.println(f1.get(r1));/* Field f2=r1.getClass().getField("x"); System.out.println(f1.get(r1));//此处取不出来,因为x为私有的,不可以取*/ Field f3=r1.getClass().getDeclaredField("x");//能访问,但不能取出来 f3.setAccessible(true);//设置可以访问,暴力反射 System.out.println(f3.get(r1)); }}
练习:将任意一个对象中的所有String类型的成员变量所对用的字符串的字符串内容中的”b”改成”a”。
Reflect_Point实体类public class Reflect_Point { private int x; public int y; public String str1="ball"; public String str2="basketball"; public String str3="itcast"; @Override public String toString() { // TODO Auto-generated method stub return str1+":"+str2+":"+str3; }}Reflect_Point_Test类package day13;import java.lang.reflect.Field;public class Reflect_Point_Test { public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException { // TODO Auto-generated method stub Reflect_Point rp =new Reflect_Point(); changeStringValue(rp); System.out.println(rp); } private static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException { // TODO Auto-generated method stub Field[] fields=obj.getClass().getFields();//获取字段 for(Field field:fields) { //field.getType();//获取字段的类型 //field.getType().equals(String.class) //字节码的比较实用“==” if(field.getType()==String.class){ String oldValue=(String)field.get(obj);//获取String类型的值 String newValue=oldValue.replace('b', 'a'); field.set(obj, newValue);//设置新值 } } }}aall:aasketaall:itcast
五.成员方法的反射(Method类)
得到类中的某一个方法:例如:Method charAt=Class.forName("java.lang.string").getMethod("charAt",int.class);调用方法: 通常方式:system.out.println(str.charAt(1)) 反射方式:system.out.println(charAt.invoke(str,1))
案例
import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class Re_Method {public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { String str1="abc";//String类名.class //目的:str1.charAt(1) //string的数组 Method method=String.class.getMethod("charAt", int.class); System.out.println(method.invoke(str1, 1));// System.out.println(method.invoke(str1, new Object[](2)));//1.4的版本中使用,结果是c}}
练习:用反射方式执行某个类中的 main方法
1.使用静态的方式去调用
package day13;public class Reflect_learning { public static void main(String[] args) { // TODO Auto-generated method stub TestArgument.mian(new String[]{"1111","22222","333"});//静态方法调用main方法 }}class TestArgument{ public static void mian(String[] args) { for(String arg:args) { System.out.println(arg); } }}
2.使用反射的方式去调用(不知道类的名字)
目的:用反射的原因是不知道执行哪一个类问题: 启动java程序的main方法的参数是一个字符串的数组,即public static void main(String[] args),通过反射方式调用这个Main方法时, 如何为Invoke调用方法传递参数(jdk1.5以后:整个数组是一个参数)解决办法:----------mainMethod.invoke(null,new Object[]{new String[]{"xxxx"}});----------mainMethod.invoke(null,(Object)new String[]{"xxxx"});//编译器会特殊处理,编译时不把参数当做数组看待,也就不会数组打散成若干个参数了。数组下标越界测试代码
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Reflect_learning {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { // TODO Auto-generated method stub //TestArgument.main(new String[]{"1111","22222","333"});//静态方法调用main方法 String startClassName=args[0]; Method mainMethod=Class.forName(startClassName).getMethod("main", String[].class); //mainMethod.invoke(null, new String[]{"1111","22222","333"});//(test2)静态的方法不需要传递对象,所以为null //原因是:传递的参数不能对称,打包成object //mainMethod.invoke(null, new Object[]{new String[]{"1111","22222","333"}});//(test3)此处就不会出现错误 /** * 结果 * 1111 22222 333 */ mainMethod.invoke(null, (Object)new String[]{"1111","22222","333"});//(test4)强制转换}
}
class TestArgument{
public static void main(String[] args)
{
for(String arg:args)
{
System.out.println(arg);
}
}
}
对TestArgument类按键F2,复制类名;同时在该类下右击选择Run As-->Run configures-->Arguments(复制上面的类名)上面的步骤可以得出字节码,然后可以得出main方法出错: Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at day13.Reflect_learning.main(Reflect_learning.java:13)
六.数组的反射
1.定义:
具有相同的维度和元素类型的数组属于同一个类型,即具有相同的class实例对象
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class
public 类
数组与Object的关系及其反射类型:public class Re_Array_Test { public static void main(String[] args) { // TODO Auto-generated method stub int []a1=new int[3]; int []a2=new int[4]; int [][]a3=new int[2][3]; String []a4=new String[5]; System.out.println(a1.getClass().getName());//返回的是[I,查看class的getName方法 System.out.println(a1.getClass()==a2.getClass()); //具有相同的维度和元素类型的数组属于同一个类型,即具有相同的class实例对象// System.out.println(a1.getClass()==a3.getClass());//编译器直接报错// System.out.println(a1.getClass()==a4.getClass());//编译器直接报错 System.out.println(a3.getClass().getName());//[[I System.out.println(a4.getClass().getName());//[Ljava.lang.String; System.out.println(a1.getClass().getSuperclass().getName());//java.lang.Object System.out.println(a4.getClass().getSuperclass().getName());//java.lang.Object System.out.println(a3.getClass().getSuperclass().getName());//java.lang.Object Object ob1=a1; Object ob2=a4;//自动装箱// Object[] ob3=a1;//此处不可以,基本类型的数组不能转换成object Object[] ob4=a3;//object中存放int[]的一维数组可以 Object[] ob5=a4; }}
2.数组反射的应用
a.反射的方式求:数组的遍历
Arrays.asList()方法用于处理int()和String[]时的差异import java.util.Arrays;public class Re_Array_Test { public static void main(String[] args) { // TODO Auto-generated method stub int []a1=new int[]{1,2,3}; int []a2=new int[4]; int [][]a3=new int[2][3]; String []a4=new String[]{"a","b","c"}; Object ob1=a1; Object ob2=a4;//自动装箱// Object[] ob3=a1;//此处不可以,基本类型的数组不能转换成object Object[] ob4=a3;//object中存放int[]的一维数组可以 Object[] ob5=a4; System.out.println(a1);//不能直接打印数组,返回hashcode值 System.out.println(a4);//不能直接打印数组,返回hashcode值 //Arrays工具类asList方法返回由指定数组支持的一个固定大小的列表。 //(改变返回列表“写”到数组。)该方法作为基于阵列和基于集合API之间的桥梁,结合 Collection.toArray()。返回的列表是可序列化的实现 RandomAccess。 System.out.println(Arrays.asList(a1));//[[I@15db9742] //原因是int类型不可以转换成object类型,只能转换成Integer System.out.println(Arrays.asList(a4));//[a, b, c] }}
b.反射的方式求数组的值和大小
Array工具类用于完成对数组的反射操作。怎么得到数组的类型?(暂时不能完成):Object[] a=new Object[]("a",1)a[0].getClass().getName();//此处只能选取单个的反射
public class Re_Array_Test { public static void main(String[] args) { // TODO Auto-generated method stub int []a1=new int[]{1,2,3}; int []a2=new int[4]; int [][]a3=new int[2][3]; String []a4=new String[]{"a","b","c"}; printObject(a4);//数组拆开 printObject("xys");//数组为拆开 } private static void printObject(Object obj) { // TODO Auto-generated method stub Class class1=obj.getClass(); if(class1.isArray())//判断是否object为数组 { int len=Array.getLength(obj);//获取obj的长度 for(int i=0;i<len;i++) { System.out.println(Array.get(obj, i));//获取对象 } }else{ System.out.println(obj); } }}
七.反射的应用
ArrayList_HashSet的比较及Hashcode分析
八、反射的作用–框架的实现
反射的作用->实现框架功能
—–框架与框架要解决的核心问题
—–框架与工具类的区别(工具类被用户使用,而框架则是调用用户提供的类)
配置文件的配写
实现的步骤:
——加载配置文件(创建对象时尽量使用父类或者接口)
Reflect_Point类public class Reflect_Point { private int x; public int y; public String str1="ball"; public String str2="basketball"; public String str3="itcast"; public Reflect_Point() { super(); // TODO Auto-generated constructor stub } public Reflect_Point(int x, int y) { super(); this.x = x; this.y = y; } @Override public String toString() { // TODO Auto-generated method stub return str1+":"+str2+":"+str3; }}Reflect_Point_Test2类package day13;import java.io.FileInputStream;import java.io.InputStream;import java.util.Collection;import java.util.Properties;public class Reflect_Point_Test2 { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub InputStream ips =new FileInputStream("config.properties");// Properties props =new Properties();//存放的值相当于hashmap(存放的是键值对) props.load(ips); ips.close();//会有内存泄露,此处关闭的是系统内存。不是本对象(虚拟机中还在运行) String className=props.getProperty("className"); Collection collections=(Collection)Class.forName(className).newInstance(); Reflect_Point pt1=new Reflect_Point(3,3); Reflect_Point pt2=new Reflect_Point(5,5); Reflect_Point pt3=new Reflect_Point(3,3); collections.add(pt1); collections.add(pt2); collections.add(pt3); collections.add(pt1); System.out.println(collections.size()); }}config.properties//放在整个工程里面(而不是源程序的包)className=java.util.ArrayList
实际运行中修改上面的操作形式
用类加载器的方式管理资源和配置文件
getRealPath()//外部地址–内部地址
一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的。
Reflect_Point类同上,此处的config.properties存放的位置不同import java.io.FileInputStream;import java.io.InputStream;import java.util.Collection;import java.util.Properties;public class Reflect_Point_Test2 { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub //一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的 //InputStream ips =new FileInputStream("config.properties"); //此处使用类加载器 //InputStream ips=Reflect_Point_Test2.class.getClassLoader().getResourceAsStream("day13/config.properties"); //day13/config.properties:此处不能再开始处加/(此处需要加载包) // InputStream ips=Reflect_Point_Test2.class.getResourceAsStream("config.properties"); Properties props =new Properties();//存放的值相当于hashmap(存放的是键值对) props.load(ips); ips.close();//会有内存泄露,此处关闭的是系统内存。不是本对象(虚拟机中还在运行) String className=props.getProperty("className"); Collection collections=(Collection)Class.forName(className).newInstance(); Reflect_Point pt1=new Reflect_Point(3,3); Reflect_Point pt2=new Reflect_Point(5,5); Reflect_Point pt3=new Reflect_Point(3,3); collections.add(pt1); collections.add(pt2); collections.add(pt3); collections.add(pt1); System.out.println(collections.size()); }}
- 【反射】JAVA反射机制
- JAVA 反射
- java 反射
- Java反射
- java反射
- java反射
- JAVA反射
- java 反射
- Java 反射
- java 反射
- Java反射
- java反射
- JAVA 反射
- java 反射
- Java反射
- java反射
- java 反射
- java 反射
- Web 中使用Javamail 发送邮件
- JavaScript基本语法
- LeetCode--137. Single Number II && 260. Single Number III之暴力搜法
- 安卓UI相关开源项目库汇总
- redis五大类型用法
- java-反射
- 【Selenium】8模拟键盘鼠标操作
- ruby 懒加载 lazy
- 使用devstack快速安装、部署openstack
- 对于Spring Cloud Feign入门示例的一点思考
- Kanade's sum HDU
- 在有TableView的页面一行代码收起键盘
- leetcode 89. Gray Code
- iOS性能优化