黑马程序员 反射学习笔记,黑马程序员学习笔记
黑马程序员 反射学习笔记,黑马程序员学习笔记
----------android培训、java培训、java学习型技术博客、期待与您交流!----------
反射:
“反射就是把Java类中的各种成分映射成相应的java类”,而在此之前,首先是必须获得类的Class对象,再调用Class的相关方法,获取实例类中的各种成分,如构造方法Constructor、域Field及包等信息。
具体过程:反射就是把Java类中的各种成分映射成相应的java类。具体就是先得到一个Field(字段,通常都是变量)们映射的Class的实例对象--一份字节码。然后在通过它们操作具体的类对象。
比如:
Constructor:得到一个Constructor[] constructors= Class.forName(“java.lang.String”).getConstructors();,通过调用它的newInstance得到这个constructors所在的类的新对象。String str =(String)constructor.newInstance(new StringBuffer(“abc”))。
Field:得到一个类中的Field,再通过Field操作这个类中的Field对应的具体成员变量。如果这个变量是私有的,还可以通过暴力反射对这个变量进行操作。
Method:得到一个类中的Method()包括main方法,在通过得到的method对这个类对应的一个具体对象进行操作(通过invoke方法)。
那么,常见的获取Class实例的方法有哪些呢,通过学习,一般的,有如下三种方法:
(1)对于类,格式为:类名.class,例如,System.class ,Person.class
(2)对于具体的对象,需使用getClass()方法,格式为:对象.getClass(),例如,new Date().getClass(),new Person().getClass()。
(3当然,若给定类名,则可使用Class类的静态方法forName(),格式为:Class.forName("类名"),例如,Class.forName("java.util.Date");
1.获取构造方法(Constructor):
通过反射可以获取到java类中的构造方法,通过构造方法可以在运行时动态的创建java对象,而不用通过new来创建。对于Class类,有四个方法可以获取构造方法,getConstructors返回的是类中所有public权限的构造方法数组,getConstructor根据参数的列表返回打个public权限的构造方法。此外,getDeclaredConstructors和getDeclaredConstructor与之前的两个类似,但是,这两个获取的是类中真正声明的除private权限的构造方法,且忽略从父类中继承下来的构造方法。构造方法获取后,便可以调用构造方法了。
import java.lang.reflect.Constructor;
public class ReflectGetConst {
public static void main(String[] args) throws Exception{
//反射获取构造方法
Constructor<MathMethods> constructor = MathMethods.class.getDeclaredConstructor(String.class,String.class);
//利用构造方法创建实例对象
MathMethods mathMethods = constructor.newInstance("myAdd","add");
System.out.println("name:"+mathMethods.getName()+"\nforWhat:"+mathMethods.getForWhat());
}
}
class MathMethods{
private static String id = "001";//私有静态域
public String name = "shinian";
private String forWhat = "No";//私有域
MathMethods(){}
MathMethods(String name,String forWhat){
this.name = name;
this.forWhat = forWhat;
}
public int add(int a,int b){
return a+b;
}
public double add(double ...b){
double sum = 0.0;
for(int i=0;i<b.length;i++){
sum+=b[i];
}
return sum;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getForWhat() {
return forWhat;
}
public void setForWhat(String forWhat) {
this.forWhat = forWhat;
}
}
}
2、 获取域(Field)
反射不仅能够获取上述的构造方法,也能获取类中public修饰的域,若是private,则需通过getDeclaredField(),再经setAccessible(true)之后进行暴力似获取。而对于getField()方法,暴力获取是无效的,其只能访问public修饰的域。请看下表
|
private |
缺省 |
protected |
public |
getField() |
× |
× |
× |
√ |
getField(),再经setAccessible(true)之后 |
× |
× |
× |
√ |
getDeclaredField() |
× |
√ |
√ |
√ |
getDeclaredField(),再经setAccessible(true)之后 |
√ |
√ |
√ |
√ |
这里需要留意的是对静态域的反射操作,静态域与非静态域的区别在于静态域使用时不需要提供具体的实例,涉及到需要实例参数时,使用null即可,
public static void main(String[] args) throws Exception{
Field staticField =MathMethods.class.getDeclaredField("id");
staticField.setAccessible(true);
//通过反射改变id域的值
System.out.println(staticField.get(new MathMethods()));
//通过反射改变id域的值,无需创建具体对象
staticField.set(null, "007");
System.out.println(staticField.get(new MathMethods()));
System.out.println("---分割线---");
Field nameField =MathMethods.class.getDeclaredField("name");
MathMethods mathMethods = new MathMethods();
//通过反射改变id域的值,需要具体的对象
nameField.set(mathMethods, "张三");
System.out.println(nameField.get(mathMethods));
}
运行结果:
001
007
---分割线---
张三
3、 获取方法(Method)
这里需要注意两点,其一是,利用getMethod(String name,Class<?>... parameterTypes),获取某个方法的对象时,对于参数是数组或者是可变参数的,需要的是同类型的数组的Class对象。其二是对某个方法对象调用
方法Objectinvoke(Object obj,Object... args)时,务必注意该方法的返回值是Object类型,参数也均为Object类型,必要的时候是需要对参数进行类型强制转换成Object类型的。
/*获取MathMethods类中的public double add(double ...b){}方法并调用*/
public class ReflectGetConst {
public static void main(String[] args) throws Exception{
//反射获取类的成员方法
Method method = MathMethods.class.getMethod("add", double[].class);
double result = (Double) method.invoke(new MathMethods("myAdd","add"), (Object)new double[]{1.1,2.1,3.5});//第二个参数强转成Object类类型,返回值Object型强转成Double类型
System.out.println(result);//打印结果:6.7
}
4、 操作数组
使用反射对数组进行操作是经过专门的java.lang.reflect.Array这个工具类来实现的,import java.lang.reflect.Array;
public class ReflectArray {
public static void main(String[] args) {
ArrayDemo();
}
public static void ArrayDemo(){
//一维数组
String[] strArr = (String[])Array.newInstance(String.class, 2);
Array.set(strArr, 0, "张三");//反射赋值
strArr[1] = "李四";//普通赋值
print(strArr);
print("---1---");
//二维数组
int[][] intArr = (int[][])Array.newInstance(int.class, 1,1);
intArr[0][0] = 1;
print(intArr[0][0]);
print("---2---");
//类似int[][][] intArr2 = new int[1][1][1]方式
int[][][] intArr2 = (int[][][])Array.newInstance(int.class, 2,2,2);
intArr2[0][0][0] = 11;
intArr2[0][0][1] = 22;
print(intArr2[0][0][1]);
print("---3---");
int[] notObject = new int[]{13,23,33};
Object[] objcetes1 = strArr;
//Object[] objcetes2 = notObject;//该句报错,原因是int等基本数据类型不是直接继承自Object
/*那么下面这句为什么又不报错呢,因为intArr是二维数组,可以视为二维数组里面存储的元素是一维数组,
* 是一个对象,它默认继承Object*
*/
Object[] objectes3 = intArr;
print(objectes3.length);//从打印结果为1也可以看出,intArr里实际存放的元素是一维数组
}
public static void print(Object[] obj){
for(int i = 0;i<obj.length;i++){
System.out.println(obj[i]);
}
}
public static void print(Object obj){
System.out.println(obj);
}
}
总结:反射还是比较难的,要好好练习才能好好掌握。
----------android培训、java培训、java学习型技术博客、期待与您交流!----------
相关文章
- 暂无相关文章
用户点评