黑马程序员_高薪技术一(java反射)
2013-06-19 17:01
190 查看
----------- android培训、java培训、java博客、java学习型技术博客、期待与您交流! --------------
本章主要的知识点总结:1、了解Class类、得到字节码的三种方式以及反射的概念
2、Constructor类、Field类、Method类的反射应用
3、数组的反射和Object的关系及数组反射的应用,hashcode的分析。
4、用反射技术开发框架的原理、用类加载器的方式管理资源和配置文件
一.Class类——反射的基石
(1)java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class.
(2)举例
人-->Person
Java类-->Class
(3)对比提问:Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,Class
类代表Java类,它的各个实例对象又分别对应什么呢?
----对应各个类在内存中的字节码,例如:Person类的字节码,ArrayList类的字节码,等等。
-----一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,
-----不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个空间可分别用一个个
-----的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?
(4)如何得到各个字节码对应的实例对象(Class类型)
类名.class, 例如:Math.class
对象.getClass(), 例如:new String().getClass()
Class.forName("类名"), 例如:Class.forName("java.String")//查询或加载
java里面有9个预定义的Class实例对象(8个基本数据类型和void)。
int.class
== Integer.TYPE;
int.class.isPrimitive();-----true //判断class类是否为基本数据类型。
int[].class.isArray();-----true //判断Class类是否为数组类。
总之在源程序出现的类型,都有各自的Class实例对象 如:int[ ] ,void
2.class与Class的区别:
class是指java类,java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,
至于这个属性的值是什么,则由这个类的实例对象来确定,不同的实例对象有不同的属性值。
java程序中的各个类,也属于同一类事物,Class类是用来描述java程序中的各个java类这一事物的,
Class类描 述了类的名字,类的访问属性,类所属的包名,字段名称的列表,方法名称的列表等等。
3.Class.forName("java.lang.String");中forName()的作用:
返回字节码。有两种方式:第一,字节码已加载过。第二,字节码未被加载过,在java虚拟机中还不存在,
则用类加载器去加载,然后缓存到虚拟机中,以后就不用再加载了。
二、反射概念
Java中的反射:就是把Java类中各种成分映射成相应的Java类。
例如,一个java类可用一个Class类的对象来表示,一个类中的组成部分有:成员变量,方法,构造方法,包等等 信息也可用一个个的java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个类。表示java类
的 Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field,Method,Contructor,Package等等。
一 个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法
可以得到这些实例对象。然后再使用这些对象。
三、Constructor类
代表某个类中的一个构造方法。
(1)得到某个类所有的构造方法:
例子:Constructor[] contructors = Class.forName("java.lang.String").getConstructors();
(2)得到某一个构造方法:
例子:Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
//获取方法时要用到类型
(3) 创建实例对象:
1、通常方式:String str = new String(new StringBuffer("abc"));
2、反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));
//调用获得的方法时要用到上面的相同类型的实例对象
(4)Class.newInstance()方法:
1、例子:String obj = (String)Class.forName("java.lang.String").newInstance();
2、该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
四、Field类
Field类代表某个类中的一个成员变量。
注意:得到的Field对象是对应到类上面的成员变量,不是对应到对象上的成员变量,
字段fieldX代表的是x的定义,而不是具体的x变量。
代码实例:
public class ReflectPoint
{
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
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");//x 是私有变量,是看不见的,此方法则可看见,但不能用
fieldX.setAccessible(true);//暴力反射:可强制使用已看到但不能用的私有变量。
System.out.println(fieldX.get(pt1));
}
}
五、Method类
Method类代表某个类中的一个成员方法
( 1)得到类中的某一个方法:
如:Method charAt = String.class.getMethod("charAt",int.class);
(2)调用方法:
1、通常方式:System.out.println(str.charAt(1));
2、反射方式:System.out.println(charAt.invoke(str,1));
如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法。
对接收数组参数的成员方法进行反射
问题:
启动java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),
通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,
整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,因为jdk1.5
要兼容jdk1.4的语法,所以当把一个字符数组作为参数传递给invoke方法时,javac会按jdk1.4
的语法进行处理。不能使用代码:mainMethod.invoke(null,new String[]{"xxx"});
解决办法:
(1)mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});//即封装成一个参数
(2)mainMethod.invoke(null,(Object)new String[]{"xxx"});//这样做等于告诉编译器说这是一个参数
//编译器就不分把参数当数组看待,也不会把数组打散成若干个参数了.
代码实例:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTest {
public static void main(String[] args)throws Exception
{
//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"});
}
}
class TestArguments
{
public static void main(String[] args)
{
for(String arg : args)
{
System.out.println(arg);
}
}
}
六、数组的反射与Object关系及其反射类型
1.数组反射
(1)具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
(2)代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class.
(3)基本类型的一维数组可以被告当作Object类型使用,不能当作Object[]类型使用,
非基本类型的一维数组,即可以当作Object类型使用,也能当作Object[]类型使用。
代码例子:
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"};
System.out.println(a1.getClass() == a2.getClass());
System.out.println(a1.getClass == a4.getClass());
System.out.println(a1.getClass() == a3.getClass());
System.out.println(a1.getClass().getName());
System.out.println(a1.getClass().getSuperclass().getName());
//获取Class实例对象的父类对应的Class实例对象名称为Object
System.out.println(a4.getClass().getSuperclass().getName());
Object aobj1 = a1;
Object aobj2 = a4;
//Object[] aobj3 = a1;
Object[] aobj4 = a3;
Object[] aobj5 = a4;
System.out.println(a1);
System.out.println(a4);
System.out.println(Arrays.asList(a1));//--->a1整体相当于一个Object类型,使用JDK1.5的,故打印结果为一个对象的哈希值。
System.out.println(Arrays.asList(a4));//--->a4中相当于有三个Object类型,使用JDK1.4的,故打印结果为[a,b,c]。
Java.Lang.Reflect.Array类
public final class Array extends Object
Array 类提供了动态创建和访问 Java 数组的方法。 Array 允许在执行 get 或 set 操作期间进行扩展转换,
但如果发生收缩转换,则抛出 IllegalArgumentException。
代码例子:
Object obj=null;
Class clazz=obj.getClass();
if(clazz.isArray()){
int len=Array.getLength(obj);
for(int i=0;i<len;i++)
{
System.out.println(Array.get(obj,i));
}
}
hash集合中hashcode()方法及内存泄漏
当一个对象被存储到HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值
的字段了,否则,对象修改后哈希值就变了,这种情况下,使用contains方法传入该对象当前
引用作为参数无法检索到对象,这也导致无法从HashSet集合中单独删除当前对象,从而造成
内存泄露。
七、用反射技术开发框架的原理
1.反射的作用-->实现框架功能
( 1)框架与框架要解决的核心问题
我做房子给用户住,用户自己安装门窗,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中,框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。
你做的门调用锁,锁是工具,你做的门被房子调用,房子是框架,房子和锁都是别人提供的。
(2)框架要解决的核心问题:
若干年前写的框架可以调用若干年后写的程序。
写程序时无法知被调用的类名,所以在程序中无法直接new某个类的实例对象, 而要用反射来做。
八、用类加载器的方式管理资源和配置文件
1.类 ClassLoader
public abstract class ClassLoader extends Object类加载器是负责加载类的对象。
ClassLoader 类是一个抽象类。如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据。
一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的“类文件”。
每个 Class 对象都包含一个对定义它的 ClassLoader 的引用。
InputStream getResourceAsStream(String name)
返回读取指定资源的输入流。
将文件放到源文件下,会自动将它的字节码文件搬到classPath目录下。
代码实例:
(1)InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");
//此例运行是将配置文件放在了源文件(src)目录下,意为:从根目录下开始查找,若不加cn/itcast/day1的话就找不到文件。
(2)InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties");
//此例运行是将配置文件放在了源文件的新建包cn.itcast.day1.resources下,意为:从默认的程序路径下开始查找,即从包cn.itcast.day下找。
(3)InputStream
ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
//使用绝对路径
本章主要的知识点总结:1、了解Class类、得到字节码的三种方式以及反射的概念
2、Constructor类、Field类、Method类的反射应用
3、数组的反射和Object的关系及数组反射的应用,hashcode的分析。
4、用反射技术开发框架的原理、用类加载器的方式管理资源和配置文件
一.Class类——反射的基石
(1)java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class.
(2)举例
人-->Person
Java类-->Class
(3)对比提问:Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,Class
类代表Java类,它的各个实例对象又分别对应什么呢?
----对应各个类在内存中的字节码,例如:Person类的字节码,ArrayList类的字节码,等等。
-----一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,
-----不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个空间可分别用一个个
-----的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?
(4)如何得到各个字节码对应的实例对象(Class类型)
类名.class, 例如:Math.class
对象.getClass(), 例如:new String().getClass()
Class.forName("类名"), 例如:Class.forName("java.String")//查询或加载
java里面有9个预定义的Class实例对象(8个基本数据类型和void)。
int.class
== Integer.TYPE;
int.class.isPrimitive();-----true //判断class类是否为基本数据类型。
int[].class.isArray();-----true //判断Class类是否为数组类。
总之在源程序出现的类型,都有各自的Class实例对象 如:int[ ] ,void
2.class与Class的区别:
class是指java类,java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,
至于这个属性的值是什么,则由这个类的实例对象来确定,不同的实例对象有不同的属性值。
java程序中的各个类,也属于同一类事物,Class类是用来描述java程序中的各个java类这一事物的,
Class类描 述了类的名字,类的访问属性,类所属的包名,字段名称的列表,方法名称的列表等等。
3.Class.forName("java.lang.String");中forName()的作用:
返回字节码。有两种方式:第一,字节码已加载过。第二,字节码未被加载过,在java虚拟机中还不存在,
则用类加载器去加载,然后缓存到虚拟机中,以后就不用再加载了。
二、反射概念
Java中的反射:就是把Java类中各种成分映射成相应的Java类。
例如,一个java类可用一个Class类的对象来表示,一个类中的组成部分有:成员变量,方法,构造方法,包等等 信息也可用一个个的java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个类。表示java类
的 Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field,Method,Contructor,Package等等。
一 个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法
可以得到这些实例对象。然后再使用这些对象。
三、Constructor类
代表某个类中的一个构造方法。
(1)得到某个类所有的构造方法:
例子:Constructor[] contructors = Class.forName("java.lang.String").getConstructors();
(2)得到某一个构造方法:
例子:Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
//获取方法时要用到类型
(3) 创建实例对象:
1、通常方式:String str = new String(new StringBuffer("abc"));
2、反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));
//调用获得的方法时要用到上面的相同类型的实例对象
(4)Class.newInstance()方法:
1、例子:String obj = (String)Class.forName("java.lang.String").newInstance();
2、该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
四、Field类
Field类代表某个类中的一个成员变量。
注意:得到的Field对象是对应到类上面的成员变量,不是对应到对象上的成员变量,
字段fieldX代表的是x的定义,而不是具体的x变量。
代码实例:
public class ReflectPoint
{
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
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");//x 是私有变量,是看不见的,此方法则可看见,但不能用
fieldX.setAccessible(true);//暴力反射:可强制使用已看到但不能用的私有变量。
System.out.println(fieldX.get(pt1));
}
}
五、Method类
Method类代表某个类中的一个成员方法
( 1)得到类中的某一个方法:
如:Method charAt = String.class.getMethod("charAt",int.class);
(2)调用方法:
1、通常方式:System.out.println(str.charAt(1));
2、反射方式:System.out.println(charAt.invoke(str,1));
如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法。
对接收数组参数的成员方法进行反射
问题:
启动java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),
通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,
整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,因为jdk1.5
要兼容jdk1.4的语法,所以当把一个字符数组作为参数传递给invoke方法时,javac会按jdk1.4
的语法进行处理。不能使用代码:mainMethod.invoke(null,new String[]{"xxx"});
解决办法:
(1)mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});//即封装成一个参数
(2)mainMethod.invoke(null,(Object)new String[]{"xxx"});//这样做等于告诉编译器说这是一个参数
//编译器就不分把参数当数组看待,也不会把数组打散成若干个参数了.
代码实例:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTest {
public static void main(String[] args)throws Exception
{
//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"});
}
}
class TestArguments
{
public static void main(String[] args)
{
for(String arg : args)
{
System.out.println(arg);
}
}
}
六、数组的反射与Object关系及其反射类型
1.数组反射
(1)具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
(2)代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class.
(3)基本类型的一维数组可以被告当作Object类型使用,不能当作Object[]类型使用,
非基本类型的一维数组,即可以当作Object类型使用,也能当作Object[]类型使用。
代码例子:
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"};
System.out.println(a1.getClass() == a2.getClass());
System.out.println(a1.getClass == a4.getClass());
System.out.println(a1.getClass() == a3.getClass());
System.out.println(a1.getClass().getName());
System.out.println(a1.getClass().getSuperclass().getName());
//获取Class实例对象的父类对应的Class实例对象名称为Object
System.out.println(a4.getClass().getSuperclass().getName());
Object aobj1 = a1;
Object aobj2 = a4;
//Object[] aobj3 = a1;
Object[] aobj4 = a3;
Object[] aobj5 = a4;
System.out.println(a1);
System.out.println(a4);
System.out.println(Arrays.asList(a1));//--->a1整体相当于一个Object类型,使用JDK1.5的,故打印结果为一个对象的哈希值。
System.out.println(Arrays.asList(a4));//--->a4中相当于有三个Object类型,使用JDK1.4的,故打印结果为[a,b,c]。
Java.Lang.Reflect.Array类
public final class Array extends Object
Array 类提供了动态创建和访问 Java 数组的方法。 Array 允许在执行 get 或 set 操作期间进行扩展转换,
但如果发生收缩转换,则抛出 IllegalArgumentException。
代码例子:
Object obj=null;
Class clazz=obj.getClass();
if(clazz.isArray()){
int len=Array.getLength(obj);
for(int i=0;i<len;i++)
{
System.out.println(Array.get(obj,i));
}
}
hash集合中hashcode()方法及内存泄漏
当一个对象被存储到HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值
的字段了,否则,对象修改后哈希值就变了,这种情况下,使用contains方法传入该对象当前
引用作为参数无法检索到对象,这也导致无法从HashSet集合中单独删除当前对象,从而造成
内存泄露。
七、用反射技术开发框架的原理
1.反射的作用-->实现框架功能
( 1)框架与框架要解决的核心问题
我做房子给用户住,用户自己安装门窗,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中,框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。
你做的门调用锁,锁是工具,你做的门被房子调用,房子是框架,房子和锁都是别人提供的。
(2)框架要解决的核心问题:
若干年前写的框架可以调用若干年后写的程序。
写程序时无法知被调用的类名,所以在程序中无法直接new某个类的实例对象, 而要用反射来做。
八、用类加载器的方式管理资源和配置文件
1.类 ClassLoader
public abstract class ClassLoader extends Object类加载器是负责加载类的对象。
ClassLoader 类是一个抽象类。如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据。
一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的“类文件”。
每个 Class 对象都包含一个对定义它的 ClassLoader 的引用。
InputStream getResourceAsStream(String name)
返回读取指定资源的输入流。
将文件放到源文件下,会自动将它的字节码文件搬到classPath目录下。
代码实例:
(1)InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");
//此例运行是将配置文件放在了源文件(src)目录下,意为:从根目录下开始查找,若不加cn/itcast/day1的话就找不到文件。
(2)InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties");
//此例运行是将配置文件放在了源文件的新建包cn.itcast.day1.resources下,意为:从默认的程序路径下开始查找,即从包cn.itcast.day下找。
(3)InputStream
ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
//使用绝对路径
相关文章推荐
- 黑马程序员————java高薪技术---反射单元1
- 黑马程序员_Java高薪技术之构造方法的反射应用
- java基础--高薪技术--反射
- 黑马程序员-java基础06高薪技术
- 黑马程序员---java高新技术----反射技术
- 黑马程序员_Java高薪技术之泛型
- 黑马程序员_Java反射技术(一)
- 黑马程序员—java核心技术—反射
- 黑马程序员——Java学习之反射技术
- 黑马程序员——Java中的反射技术
- 黑马程序员——java基础加强高薪技术总结
- 黑马程序员--Java反射技术
- 黑马程序员-06-离你很近的java反射技术笔记总结
- 黑马程序员——Java新技术反射技术1
- 黑马程序员——Java 反射技术
- 黑马程序员_Java反射技术学习总结
- 黑马程序员—Java学习笔记之必须掌握的反射技术
- 黑马程序员_Java反射技术
- 黑马程序员——高薪技术——反射
- 黑马程序员_java高新技术之反射技术