反射

1、反射的概念
反射的引入:
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(元数据):描述数据结构的结构;
反射就是得到元数据的行为;
备注:一个类在虚拟机中只有一份字节码;

5,反射机制的优点与缺点:
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。
     静态编译:在编译时确定类型,绑定对象,即通过。
     动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了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对象的三种方法。
 * */
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 对象是否表示一个数组类型。
-------------------------------------
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 对象表示类的所有构造方法,和访问权限无关;
---------------------------------------
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(): 获得类所有的方法,包括公共、保护、默认(包)访问和私
有方法,但不包括继承的方法;
------------------------------------
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。
-------------------------------
利用反射创建对象,第一种方法(简单)
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 方法来执行该底层方法。
Object invoke(Object obj,Object ... args):obj 表示调用底层方法的对象,后面的args 表示传递
的实际参数。
如果底层方法是静态的,那么可以忽略指定的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[]封装一层,保证无误.
------------------------------------
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);

//获取字符,并且赋值,然后再取出来(对应的去查看api,比如这个是Field,别的比如
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()//返回泛型参数类型;

利用反射来获取泛型的类型(泛型信息)
步骤:
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培训、期待与您交流! ----------------------



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值