1、反射的概念
反射的引入:
Object obj = new Student();
若程序运行时接收到外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象运行类型的方法:
1.若编译和运行类型都知道,使用instanceof 判断后,强转。
2.编译时根本无法预知该对象属于什么类,程序只能依靠运行时信息来发现对象的
真实信息,这时就必须使用反射了。
3.要是想得到对象真正的类型,就得使用反射。
反射的引入:
Object obj = new Student();
若程序运行时接收到外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象运行类型的方法:
1.若编译和运行类型都知道,使用instanceof 判断后,强转。
2.编译时根本无法预知该对象属于什么类,程序只能依靠运行时信息来发现对象的
真实信息,这时就必须使用反射了。
3.要是想得到对象真正的类型,就得使用反射。
2,什么是反射?
反射:反射就是将java类中的各种成份映射成相应的java类!!(冯伟立)
eg:一个java类用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的java类来表示,就像汽车是一个类,汽车中的发动机,变速箱,等等零部件也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field,Method,Constructor,Package等等。
3,反射的基石:Class类。(java类用来描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的具体值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。Java程序中的各个Java类,它们是否属于同一类事物,是不是可以由一个类来描述这类事物呢?这个类的名字就是Class,要注意与小写class的区别。Class类描述了哪些方面的信息呢?类的名字,类的访问属性,类所属的包名,字段名称的列表,方法名称的列表,等等。学习反射,首先就要明白Class这个类。)
class:.class只是Class类中的一个具体实例。Class类的一个用来定义具体实例前面修饰词。
Class:Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。
4,对比提问:
a,众多的人用一个什么类表示?众多的java类用一个什么类表示?
人--->Person
java类--->Class
b,Person类代表人,它的实例对象就是张三、李四这样一个个具体的人。
Class类代表java类,它的各个实例对象又分别对应什么呢?
1,对应各个类在内存中的字节码,例如:Person类的字节码,ArrayList类的字节码等等。
2,一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?答案就是:Class类。
用类来描述对象,类:描述数据的结构
用元数据来描述Class,MetaData(元数据):描述数据结构的结构;
反射就是得到元数据的行为;
用元数据来描述Class,MetaData(元数据):描述数据结构的结构;
反射就是得到元数据的行为;
备注:一个类在虚拟机中只有一份字节码;
5,反射机制的优点与缺点:
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java 的灵活性,体现了多态的应用,有以降低类之间的藕合性。
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java 的灵活性,体现了多态的应用,有以降低类之间的藕合性。
一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE 的开发。
它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
6,获得Class 对象
如何得到各个字节码对应的实例对象?
每个类被加载后,系统会为该类生成对应的Class 对象,通过Class 对象可以访问到JVM 中的这个类,
3 种方式:
1、调用某个类的class 属性获取Class 对象,如Date.class 会返回Date 类对应的Class
对象(其实就是得到一个类的一份字节码文件);
2、使用Class 类的forName(String className)静态方法,className 表示全限定名;如
String 的全限定名:java.lang.String;
3、调用某个对象的getClass()方法。该方法属于Object 类;
Class<?> clz = new Date().getClass();
如何得到各个字节码对应的实例对象?
每个类被加载后,系统会为该类生成对应的Class 对象,通过Class 对象可以访问到JVM 中的这个类,
3 种方式:
1、调用某个类的class 属性获取Class 对象,如Date.class 会返回Date 类对应的Class
对象(其实就是得到一个类的一份字节码文件);
2、使用Class 类的forName(String className)静态方法,className 表示全限定名;如
String 的全限定名:java.lang.String;
3、调用某个对象的getClass()方法。该方法属于Object 类;
Class<?> clz = new Date().getClass();
-------------------------------------
/*
* 需求:列举获取Class对象的三种方法。
* */
public class ClassDemo {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//第一种方法:调用属性!
Class c1 = String.class;//String.class就表示JVM中一份表示String类的字节码
Class c2 = String.class;
System.out.println("c1:" + c1);//c1:class java.lang.String
System.out.println(c1 == c2);//true都是String类的字节码一个类在虚拟机中只有一份字节码;
//第二种方法:使用Class类中静态方法forName();
Class c3 = Class.forName("java.lang.String");//必须用上全限定名,否则报错!
System.out.println("c3:" + c3);
System.out.println(c1 == c3);
//利用对象调用Object的getClass方法。
Class c4 = new String().getClass();
System.out.println("c4:" + c4);
System.out.println(c1 == c4);
}
//总结:获取Class 对象最常用的是利用属性的方法!
}
-------------------------------------
7,九个预定义Class 对象
基本的Java 类型(boolean、byte、char、short、int、long、float 和double)和关键字void通过class 属性也表示为Class 对象;
Class 类中boolean isPrimitive() :判定指定的Class 对象是否表示一个基本类型。
包装类和Void 类的静态TYPE 字段;
Integer.TYPE == int.class ;
Integer.class != int.class;
数组类型的Class 实例对象:
Class<String[]> clz = String[].class;
数组的Class 对象如何比较是否相等? 数组的维数和数组的类型;
Class 类中boolean isArray() :判定此Class 对象是否表示一个数组类型。
基本的Java 类型(boolean、byte、char、short、int、long、float 和double)和关键字void通过class 属性也表示为Class 对象;
Class 类中boolean isPrimitive() :判定指定的Class 对象是否表示一个基本类型。
包装类和Void 类的静态TYPE 字段;
Integer.TYPE == int.class ;
Integer.class != int.class;
数组类型的Class 实例对象:
Class<String[]> clz = String[].class;
数组的Class 对象如何比较是否相等? 数组的维数和数组的类型;
Class 类中boolean isArray() :判定此Class 对象是否表示一个数组类型。
-------------------------------------
public class PredefineClassDemo {
/**
* @param args
*/
public static void main(String[] args) {
Class c1 = int.class;
Class c2 = Integer.class;
Class c3 = Integer.TYPE;//包装类都有一个常量TYPE,用来表示其基本数据类型的字节码
System.out.println(c1);//int
System.out.println(c2);//class java.lang.Integer
System.out.println(c3);//int
System.out.println(c1 == c2);//false
System.out.println(c1 == c3);//true
Class c4 = String[].class;
Class c5 = int[].class;
System.out.println(c4 == c5);
}
//这两个自定义的方法是可以的,一个int,一个Integer
//基本数据类型与其包装类在内存中的字节码是不一样的。
public void show(int i){}
public void show(Integer i){}
}
</pre></div><div><span style="font-size:12px;">-------------------------------------</span></div><div><span style="font-size:12px;"><span>总之:只要是在源程序中出现的类型,都有各自的Class实例对象,例如:void,int,int[]等等。</span></span></div><div><span style="font-size:12px;"></span></div><div><span style="font-size:12px;">8,利用Class 获取类的属性信息</span></div><div><span style="font-size:12px;">-----------------------------------------</span></div><span style="font-size:12px;"></span><pre class="java" name="code">import java.lang.reflect.Modifier;
class A {
}
interface B {
}
interface C {
}
public class ClassPropertyInfo extends A implements B,C {
public class D {}
public interface E {}
public static void main(String[] args) {
//类可以,接口也可以。
Class c0 = ClassPropertyInfo.class;
System.out.println(c0);//class base.day12.ClassPropertyInfo
//得到包名
System.out.println(c0.getPackage());//package base.day12
//得到全限定名
System.out.println(c0.getName());//base.day12.ClassPropertyInfo
//得到类的简称
System.out.println(c0.getSimpleName());//ClassPropertyInfo
//得到父类
/**
* Class<? super T> getSuperclass() 此处super表示下限
返回表示此Class 所表示的实体(类、接口、基本类型或void)的超
类的Class。
*/
System.out.println(c0.getSuperclass().getSimpleName());//A,先获得父类,再获得父类的简称。
//得到接口
System.out.println(c0.getInterfaces());//[Ljava.lang.Class;@1bab50a,显然是一个地址。
Class[] c1 = c0.getInterfaces();
for(Class c : c1) {
System.out.println(c);//interface base.day12.B;interface base.day12.C
}
//获得public修饰的类
/**
* Class<?>[] getClasses()
返回一个包含某些Class 对象的数组,这些对象表示属于此
Class 对象所表示的类的成员的所有公共类和接口。(如果内部类前面没有加上public
的话那么得不到!)
*/
Class[] c2 = c0.getClasses();
for(Class c : c2) {
//class base.day12.ClassPropertyInfo$D
//interface base.day12.ClassPropertyInfo$E
System.out.println(c);
}
//获得修饰符
int i = c0.getModifiers();
System.out.println(i);//常量值1表示public
System.out.println(Modifier.toString(i));//直接打印public
}
}
-----------------------------------------
9,Class 中得到构造方法Constructor、方法Method、字段Field
常用方法:
Constructor 类用于描述类中的构造方法:
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回该Class 对象表示类的指定的public 构造方法;
Constructor<?>[] getConstructors()
返回该Class 对象表示类的所有public 构造方法;
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回该Class 对象表示类的指定的构造方法,和访问权限无关;
Constructor<?>[] getDeclaredConstructors()
返回该Class 对象表示类的所有构造方法,和访问权限无关;
Constructor 类用于描述类中的构造方法:
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回该Class 对象表示类的指定的public 构造方法;
Constructor<?>[] getConstructors()
返回该Class 对象表示类的所有public 构造方法;
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回该Class 对象表示类的指定的构造方法,和访问权限无关;
Constructor<?>[] getDeclaredConstructors()
返回该Class 对象表示类的所有构造方法,和访问权限无关;
---------------------------------------
import java.lang.reflect.Constructor;
class Emp {
private String name;
private int age;
private Emp() {
}
Emp(String name) {
}
public Emp(String name, int age) {
}
}
public class ClassConstructorInfo {
/**
* @param args
* @throws Exception
* @throws SecurityException
*/
public static void main(String[] args) throws SecurityException, Exception {
//得到所有的构造器,先得到类。
Class c0 = Emp.class;
/**
* Constructor<?>[] getConstructors()
返回一个包含某些Constructor 对象的数组, 这些对象反映此
Class 对象所表示的类的所有公共构造方法。
*/
//前面的修饰符必须是public,这个方法才能获取到此构造方法
Constructor[] cons = c0.getConstructors();
for(Constructor c : cons) {
//public base.day12.Emp(java.lang.String,int)
System.out.println(c);
}
//得到指定构造器,也必须是被public修饰的。
Constructor con = c0.getConstructor(String.class, int.class);
System.out.println(con);//public base.day12.Emp(java.lang.String,int)
System.out.println("=================================");
//现在想获得不受public影响的,getDeclaredConstructors(),暴力反射。
Constructor[] cons1 = c0.getDeclaredConstructors();
for(Constructor c1 : cons1) {
/*private base.day12.Emp()
base.day12.Emp(java.lang.String)
public base.day12.Emp(java.lang.String,int)
* */
System.out.println(c1);
}
}
}
---------------------------------------
Method 类用于描述类中的方法:
Method getMethod(String name, Class<?> ... parameterTypes)
返回该Class 对象表示类和其父类的指定的public 方法;
Method[] getMethods():
返回该Class 对象表示类和其父类的所有public 方法;
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回该Class 对象表示类的指定的方法。和访问权限无关,但不包括继承的方法;
Method[] getDeclaredMethods(): 获得类所有的方法,包括公共、保护、默认(包)访问和私
有方法,但不包括继承的方法;
Method getMethod(String name, Class<?> ... parameterTypes)
返回该Class 对象表示类和其父类的指定的public 方法;
Method[] getMethods():
返回该Class 对象表示类和其父类的所有public 方法;
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回该Class 对象表示类的指定的方法。和访问权限无关,但不包括继承的方法;
Method[] getDeclaredMethods(): 获得类所有的方法,包括公共、保护、默认(包)访问和私
有方法,但不包括继承的方法;
------------------------------------
class AB {
protected String name;
protected int id;
}
public class ClassMethodInfo extends AB {
void show() {}
public void say() {}
private int age;
public char c;
private boolean b;
/**
* @param args
* @throws NoSuchMethodException
* @throws SecurityException
* @throws NoSuchFieldException
*/
public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException {
Class c = ClassMethodInfo.class;
//获取所有的(包含父类的方法)public修饰的方法
Method[] methods = c.getMethods();
for(Method m : methods) {
System.out.println(m);
}
System.out.println("-----------------------");
/*总结:4个方法:
* 获取全部,获取特定。
* 不受修饰符限制的全部,不受修饰符限制的特定。
* */
//获取指定的方法:
Method m1 = c.getMethod("main", String[].class);
System.out.println(m1);
System.out.println("--------------------");
/**
* Method[] getDeclaredMethods()
返回Method 对象的一个数组,这些对象反映此Class 对象表示的
类或接口声明的所有方法,
包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法,
只可以对当前类有效
*/
//访问所有不受权限限制的方法:
methods = c.getDeclaredMethods();
for(Method m : methods) {
System.out.println(m);
}
System.out.println("--------------------");
//访问不受权限控制的特定方法:
m1 = c.getDeclaredMethod("show");
System.out.println(m1);
System.out.println("--------------------");
/*Exception:java.lang.NoSuchMethodException
* c.getDeclaredMethod() 不能得到继承的方法
m1 = c.getDeclaredMethod("toString");
System.out.println(m1);
System.out.println("--------------------");
*/
Field[] fields = c.getFields();
for(Field f: fields) {
//只得到了public
System.out.println(f);
}
System.out.println("-----------------");
fields = c.getDeclaredFields();
for(Field f: fields) {
//得到不受修饰符限定的字段,但是只对当前类有
System.out.println(f);
}
System.out.println("-----------------");
Field f = c.getField("c");
System.out.println(f);
System.out.println("-----------------");
f = c.getDeclaredField("age");
System.out.println(f);
System.out.println("-----------------");
//注释 Annotation
Annotation[] ans = c.getAnnotations();
System.out.println(ans.length);
for(Annotation a: ans) {
System.out.println(a);
}
System.out.println("-----------------");
//特殊注释
Annotation d = c.getAnnotation(Deprecated.class);
System.out.println(d);
}
}
----------------------------------------
-------------
---------------------------
//获取当前对象的字段:
class Student {
public String name;
public String sex;
public int age;
public Student(String name, String sex, int age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
}
}
public class GetCurrentField {
/**
* @param args
* @throws NoSuchFieldException
* @throws SecurityException
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Student s = new Student("妞妞","女",10);
Class<Student> c1 = Student.class;
Field f = c1.getField("name");
System.out.println(f.get(s));
Class c2 = s.getClass();
f = c2.getField("name");
System.out.println(f.get(s));
f.set(s, "hnlm");
System.out.println(f.get(s));
}
/*
* 总结:对于方法,字段,构造方法之类用类获取记住四个:获取全部,获
* 取特定,暴力获取全部,暴力获取特定!
*/
}
---------------------------
10,利用反射创建对象:
创建对象:
1、使用Class 对象的newInstance()方法创建该Class 对象的实例,此时该Class 对象必
须要有无参数的构造方法。
2、使用Class 对象获取指定的Constructor 对象,再调用Constructor 的newInstance()
方法创建对象类的实例,此时可以选择使用某个构造方法。如果这个构造方法被私有化起来,
那么必须先申请访问,将可以访问设置为true。
1、使用Class 对象的newInstance()方法创建该Class 对象的实例,此时该Class 对象必
须要有无参数的构造方法。
2、使用Class 对象获取指定的Constructor 对象,再调用Constructor 的newInstance()
方法创建对象类的实例,此时可以选择使用某个构造方法。如果这个构造方法被私有化起来,
那么必须先申请访问,将可以访问设置为true。
-------------------------------
利用反射创建对象,第一种方法(简单)
class User {
/*//将默认的构造方法私有化的话就不可以再创建对象,两种方法都是这样
private User() {
}*/
public String toString() {
return "创建成功!";
}
}
public class NewInstanceDemo1 {
/**
* @param args
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
//传统方式创建对象
System.out.println(new User());
//使用反射的方式
Class<User> c = User.class;
//(直接newInstance的话必须保证默认的构造方法正常存在,也就是没有被私有化!这是前提条件)
System.out.println(c.newInstance());
}
}
</pre></div><div><span style="font-size:12px;">-------------------------------</span></div><div>复杂点的:更强大的第二种:使用指定构造方法来创建对象:获取该类的Class 对象。利用Class 对象的getConstructor()方法来获取指定的构造方法。调用Constructor 的newInstance()方法创建对象。AccessibleObject 对象的setAccessible(boolean flag)方法,当flag 为true 的时候,就会忽略访问权限(可访问私有的成员)。其子类有Field, Method, Constructor;若要访问对象private 的成员?在调用之前使用setAccessible(true),Xxx x = getDeclaredXxxx();//才能得到私有的类字段.</div><div>总结步骤:1. 获取该类的Class 对象。2. 利用Class 对象的getConstructor()方法来获取指定的构造方法。3. 申请访问(设置为可访问)4. 调用Constructor(构造方法)的newInstance()方法创建对象。</div><div>---------------------------------</div><div><pre class="java" name="code">class Person {
private String name;
private Person() {
}
private Person(String name) {
this.name = name;
}
public String toString() {
return name + "创建对象成功!";
}
}
public class NewInstanceDemo2 {
/**
* @param args
* @throws Exception
* @throws InstantiationException
*/
public static void main(String[] args) throws InstantiationException, Exception {
Class<Person> c = Person.class;
// System.out.println(c.newInstance());由于无参的构造方法被私有化,所以此方法不行。
//先获得需要被调用的构造器(private 修饰的构造方法)调用默认的,什么都不要写
Constructor<Person> con = c.getDeclaredConstructor();
System.out.println(con);
//私有的成员是受保护的,不能直接访问,若要访问私有的成员,得先申请一下
con.setAccessible(true);//允许访问
Person p = con.newInstance();//成功,通过私有的受保护的构造方法创建了对象
System.out.println(p);//null创建对象成功!
//获取指定的构造方法。
con = c.getDeclaredConstructor(String.class);
con.setAccessible(true);
p = con.newInstance("hnlm");
System.out.println(p);
//备注:对于此时的话,单例模式就不再安全了!反射可破之!!
}
}
---------------------------------
对于枚举而言,反射依然没有办法重新创建对象
对于枚举,安全!
对于枚举,安全!
------------------------------------
enum Color {
RED,BLUE,GREEN;
private Color() {
}
}
public class EnumDemo {
/**
* @param args
* @throws Exception
* @throws SecurityException
*/
public static void main(String[] args) throws SecurityException, Exception {
Class<Color> c = Color.class;
//(错误在这一行发生,就是说对枚举而言这种方法连构造器都获得不了,)编译可以通过,但是运
//行就通不过了!
// Constructor<Color> con = c.getDeclaredConstructor();
// con.setAccessible(true);
// Color color = con.newInstance();
// System.out.println(color);//失败,证明对枚举而言不行,所以枚举的单例模式更加安全
System.out.println(c.isEnum());//true是枚举
}
}
------------------------------------
11,使用反射调用方法
每个Method 的对象对应一个具体的底层方法。获得Method 对象后,程序可以使用Method
里面的invoke 方法来执行该底层方法。
里面的invoke 方法来执行该底层方法。
Object invoke(Object obj,Object ... args):obj 表示调用底层方法的对象,后面的args 表示传递
的实际参数。
如果底层方法是静态的,那么可以忽略指定的obj 参数。该参数可以为null,想想为什么?
如果底层方法所需的形参个数为0,则所提供的args 数组长度可以为0 或null。
不写,null,或new Object[]{}
若底层方法返回的是数组类型,invoke 方法返回的不是底层方法的值,而是底层方法的返回类型;
的实际参数。
如果底层方法是静态的,那么可以忽略指定的obj 参数。该参数可以为null,想想为什么?
如果底层方法所需的形参个数为0,则所提供的args 数组长度可以为0 或null。
不写,null,或new Object[]{}
若底层方法返回的是数组类型,invoke 方法返回的不是底层方法的值,而是底层方法的返回类型;
------------------------------------
class Dept {
//用反射的方法来调用正常的方法
public String show(String name) {
return name + "publicshow";
}
//用反射来实现对私有化方法的调用
private void privateShow() {
System.out.println("privateshow");
}
//用反射来实现对静态方法的调用
public static void publicShow() {
System.out.println("publicshow");
}
}
public class InvokeDemo {
/**
* @param args
* @throws Exception
* @throws SecurityException
*/
public static void main(String[] args) throws SecurityException, Exception {
//传统方式
String name = new Dept().show("hnlm");
System.out.println(name);
//想要通过反射来调用Dept中的方法
Class<Dept> c = Dept.class;
/**
* Method getMethod(String name, Class<?>... parameterTypes)
返回一个Method 对象,它反映此Class 对象所表示的类或接口的指
定公共成员方法。
name - 方法名
parameterTypes - 参数列表
*/
//利用反射对普通方法的调用。
Method m = c.getMethod("show",String.class);
//o为调用该方法的返回值。
Object o = m.invoke(c.newInstance(),"妞妞");
System.out.println(o);
//利用反射对私有化的方法调用
m = c.getDeclaredMethod("privateShow");//无参方法
m.setAccessible(true);
m.invoke(c.newInstance());
//利用反射对静态方法的调用
m = c.getMethod("publicShow");
//staticshow为静态方法,不需创建对象,所以这里会是null
m.invoke(null);
}
}
------------------------------------
12,使用反射调用可变参数方法
使用反射操作对象-调用可变参数方法
要把可变参数都当做是其对应的数组类型参数;
如show(XX... is)作为show(XX[] is)调用;
若可变参数元素类型是引用类型:
JDK 内部接收到参数之后,会自动拆包取出参数再分配给该底层方法,为此我们需要把这
个数组实参先包装成一个Object 对象或把实际参数作为一个Object 一维数组的元素再传递。
若可变参数元素类型是基本类型:
JDK 内部接收到参数之后,不会拆包,所以可以不必再封装.不过封装了也不会错.所以建
议,不管基本类型还是引用类型都使用Object[]封装一层,保证无误.
使用反射操作对象-调用可变参数方法
要把可变参数都当做是其对应的数组类型参数;
如show(XX... is)作为show(XX[] is)调用;
若可变参数元素类型是引用类型:
JDK 内部接收到参数之后,会自动拆包取出参数再分配给该底层方法,为此我们需要把这
个数组实参先包装成一个Object 对象或把实际参数作为一个Object 一维数组的元素再传递。
若可变参数元素类型是基本类型:
JDK 内部接收到参数之后,不会拆包,所以可以不必再封装.不过封装了也不会错.所以建
议,不管基本类型还是引用类型都使用Object[]封装一层,保证无误.
------------------------------------
class VariableMethod {
/*public static void show(int[] args){//这是一样的}*/
public static void show(int...is) {
System.out.println("基本类型可变参数传递过来啦!!");
}
public static void show(String...strings) {
System.out.println("引用类型可变参数传递过来啦!!");
}
}
public class VariableDemo {
/**
* @param args
* @throws Exception
* @throws SecurityException
*/
public static void main(String[] args) throws SecurityException, Exception {
Class<VariableMethod> c = VariableMethod.class;
Method m = c.getMethod("show", int[].class);
m.invoke(null, new Object[]{new int[]{1,2,3}});
m = c.getMethod("show", String[].class);
//m.invoke(null,new String[]{"A","B","C"});//ERROR
m.invoke(null, new Object[]{new String[]{"A","B","C"}});//推荐用法
m.invoke(null,(Object)new String[]{"A","B","C"});//YES, 强转为Object类型
}
}
------------------------------------
13,使用反射操作字段
Field 提供两组方法操作字段:
xxx getXxx(Object obj):获取obj 对象该Field 的字段值,此处的xxx 表示8 个基本数据类型。
若该字段的类型是引用数据类型则使用,Object get(Object obj);
void setXxx(Object obj,xxx val):将obj 对象的该Field 字段设置成val 值,此处的xxx 表示8
个基本数据类型。若该字段的类型是引用数据类型则使用,void set(Object obj, Object value);
Field 提供两组方法操作字段:
xxx getXxx(Object obj):获取obj 对象该Field 的字段值,此处的xxx 表示8 个基本数据类型。
若该字段的类型是引用数据类型则使用,Object get(Object obj);
void setXxx(Object obj,xxx val):将obj 对象的该Field 字段设置成val 值,此处的xxx 表示8
个基本数据类型。若该字段的类型是引用数据类型则使用,void set(Object obj, Object value);
//获取字符,并且赋值,然后再取出来(对应的去查看api,比如这个是Field,别的比如
Constructor,Method)
步骤:
1.获取类
2.获取字段
3.赋值(set(c.newInstance(),””));{如果为私有的话设置可接受}
Constructor,Method)
步骤:
1.获取类
2.获取字段
3.赋值(set(c.newInstance(),””));{如果为私有的话设置可接受}
------------------------------------
class Cat {
private String name;
public int age;
private String color;
}
public class FieldDemo {
/**
* @param args
* @throws Exception
* @throws SecurityException
*/
public static void main(String[] args) throws SecurityException, Exception {
Class<Cat> c = Cat.class;
Field[] fields = c.getDeclaredFields();
for(Field f: fields) {
System.out.println(f);
}
Field f = c.getDeclaredField("name");
System.out.println(f);
System.out.println(f.getName());
//核心开始
/**
* void set(Object obj, Object value)
将指定对象变量上此Field 对象表示的字段设置为指定的新值。
*/
Constructor<Cat> con = c.getDeclaredConstructor();
Cat cat = con.newInstance();
f.setAccessible(true);
f.set(cat, "妞妞");//赋值成功
Object value = f.get(cat);
System.out.println(value);
Cat cat1 = c.newInstance();
Field f1 = c.getDeclaredField("age");
f1.set(cat1, 11);
int i = f1.getInt(cat1);//左边的接受类型已经写成了int,右边的返回类型就也必须是int
System.out.println(i);//获取成功
}
}
------------------------------------
14,反射和泛型-反射来获取泛型信息
通过指定对应的Class 对象,程序可以获得该类里面所有的Field,不管该Field 使用private
方法public。获得Field 对象后都可以使用getType()来获取其类型。
Class<?> type = f.getType();//获得字段的类型
但此方法只对普通Field 有效,若该Field 有泛型修饰,则不能准确得到该Field 的泛型参数,如
Map<String,Integer>;
为了获得指定Field 的泛型类型,我们采用:
Type gType = f.getGenericType();得到泛型类型
然后将Type 对象强转为ParameterizedType,其表示增加泛型后的类型
Type getRawType()//返回被泛型限制的类型;
Type[] getActualTypeArguments()//返回泛型参数类型;
通过指定对应的Class 对象,程序可以获得该类里面所有的Field,不管该Field 使用private
方法public。获得Field 对象后都可以使用getType()来获取其类型。
Class<?> type = f.getType();//获得字段的类型
但此方法只对普通Field 有效,若该Field 有泛型修饰,则不能准确得到该Field 的泛型参数,如
Map<String,Integer>;
为了获得指定Field 的泛型类型,我们采用:
Type gType = f.getGenericType();得到泛型类型
然后将Type 对象强转为ParameterizedType,其表示增加泛型后的类型
Type getRawType()//返回被泛型限制的类型;
Type[] getActualTypeArguments()//返回泛型参数类型;
利用反射来获取泛型的类型(泛型信息)
步骤:
1.获取当前类
2.获取目标字段
3.获取包含泛型类型的类型getGenericType()
4.强转至子类ParameterizedType 因为Type 没有任何对应的方法
5.获得泛型真正的类型getActualTypeArguments()
步骤:
1.获取当前类
2.获取目标字段
3.获取包含泛型类型的类型getGenericType()
4.强转至子类ParameterizedType 因为Type 没有任何对应的方法
5.获得泛型真正的类型getActualTypeArguments()
------------------------------------
public class GetGenericDemo {
Map<Integer,String> map = new HashMap<Integer,String>();
/**
* @param args
* @throws Exception
* @throws SecurityException
*/
public static void main(String[] args) throws SecurityException, Exception {
Class<GetGenericDemo> c = GetGenericDemo.class;
Field field = c.getDeclaredField("map");
System.out.println(field);
System.out.println(field.getName());
// Class<?> getType() 返回一个Class 对象,它标识了此Field 对象所表示字段的声明类型。
Class<?> c1 = field.getType();
//获得其类型:interface java.util.Map
System.out.println(c1);
/**
* Type getGenericType() 返回一个Type 对象,它表示此Field 对象
所表示字段的声明类型。
* Type是Class的接口;
*/
Type type = field.getGenericType();//包含泛型的类型
//java.util.Map<java.lang.String, java.lang.Integer>
System.out.println(type);
/**
* Type这个类里面没有任何的方法,所以需要调用子类的方法,那么大的类型
转到小的类型,需要强转!
*/
ParameterizedType ptype = (ParameterizedType)type;
Type[] types = ptype.getActualTypeArguments();
for(Type t: types) {
System.out.println(t);
}
/**
* Type[] getActualTypeArguments()
返回表示此类型实际类型参数的Type对象的数组。
Type getOwnerType()
返回Type 对象,表示此类型是其成员之一的类型。
Type getRawType()
返回Type 对象,表示声明此类型的类或接口。
*/
Type t1 = ptype.getOwnerType();
Type t2 = ptype.getRawType();
System.out.println(t1);
System.out.println(t2);
//总结:多查找api,参考api 中方法使用的限制,比如是否静态、返回值类型等。
}
}
------------------------------------
----------------------
ASP.Net+Unity开发、
.Net培训、期待与您交流! ----------------------