一.泛型是jdk1.5提出来的,它的好处:1.是避免频繁的类型转换,2.把运行时异常提前到编译时,换句话说可以在编译时期进行类型检查。
public class Demo1<T> {
private T t;
public T add(T t){
return t;
}
public void save(List<T> p){
}
public <V> T save1(List<V> v){
return t;
}
}
1.在成员变量声明了个一个泛型T,必须在类上Demo1声明Deom1<T>。
2.在方法上声明了泛型<T>有两种:1.在方法返回类型前面声明。2.在类上声明。
二.泛型的擦除
1.泛型只在编译时有效,编译后的字节码文件不存在有泛型信息。
比如:public T save(List<T> p){
this.t=t;
return t;
}
public <V> void save(List<V> v){
}
这两个方法不是重载关系,在编译时会报错,通过反编译查看字节码文件泛型信息已经不存在了:
public class Demo1
{
public Demo1() //构造方法
{
}
public Object add(Object t)
{
return t;
}
public Object save(List p)
{
t = t;
return t;
}
public void save1(List list)
{
}
private Object t;//成员变量
}
三.泛型的写法:两种
// 1.声明泛型集合,集合两端类型必须一致
List<Object> list = new ArrayList<Object>();
List<String> list1 = new ArrayList<String>();
//2.集合一边写泛型,另外一边不写
List list2 = new ArrayList<String>();
List<Integer> list3 = new ArrayList();
// 错误写法:
//1.两边类型不一致
//List<Object> list4 = new ArrayList<String>();
// 2.泛型类型必须是引用类型,不能为基本类型
List<int> list5 =new ArrayList<int>();
四.泛型方法/泛型类/泛型接口
public class Demo1<T> {
private T t;
public <T> T add(T t){
return null;
}
public <T> T save(List<T> p){
this.t=t;
return (T) t;
}
public <V> void save1(List<V> v){
}
}
1.泛型方法是在使用的时候确定类型的。
@Test
public void test(){
add( "s");
}
2.泛型类是在创建泛型类对象的时候确定类型的。
@Test
public void test1(){
Demo1<String> d=new Demo1<String>();
}
3.泛型接口:1.如果实现泛型接口的类是抽象类时,那么类型是在具体的实现中确定或创建泛型类的时候确定。
2.如果实现泛型接口的类不是抽象类时,那么类型应该在实现该接口时指定,如果没有指定,应该在创建该类对象时指定。
五.泛型关键字:
? 指定只是接受值。
extends 元素的类型必须继承自指定的类。
super 元素的类型必须是指定的类的父类。
//一.带?的泛型特征
1. public void print(List<?> list) {
list.get(0);//已经作废,因为不能确定它的类型
list.set();//彻底作废
}
//二.带? extends 的泛型特征(泛型的上限)
public void save(List<?extends Number> list) {
//list的集合只能处理Number或者Number的子类
}
//三.带?super的泛型特征(泛型的下限)
public void save(List<?super String> list) {
//list只能处理String的父类或者String本身.
}
六.泛型的反射:
一.回忆反射:
1.反射:当一个字节码文件加载到内存的时候,jvm会对该字节码进行解剖,然后会创建一个对象的Class对象,把字节码文件的信息全部都存储到该Class对象中,我们只要获取到Class对象,我们就可以使用字节码对象设置对象的属性或者调用对象方法的操作.
注意:在反射中一个类的任何成员都有对应的类进行描叙。比如:成员变量(Field) 方法----->Method类
2.获取Class对象的方式:
1.class.forName("包名加类名");
2.类名.class;
3.对象.getClass();
3.Class对象获取构造方法:
Class clazz=Class.forName("");//得到Class对象
1. Constructor[] constructors = clazz.getConstructors(); // getConstructors()获取一个类的所有公共的构造方法
2.Constructor[] constructors = clazz.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内
3.Constructor constructor = clazz.getConstructor(int.class,String.class); // getConstructor 获取单个指定的构造方法。
Person p = (Person) constructor.newInstance(999,"小城"); // newInstance()创建一个对象
4.//获取私有的构造函数
Constructor constructor = clazz.getDeclaredConstructor(null);
constructor.setAccessible(true);//开启能够访问私有的方法,扩展:Java的安全由:类加载器、类校验器、安全管理器
* 如果我们设置了安全管理器,即指定安全策略,不允许访问对象的私有成员,那么setAccessible()方法就会抛出异常。
Person p =(Person) constructor.newInstance(null);
4.Class对象获取对应的方法(Method)
Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法。
Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法,但是不包含父类的方法。
Method m = clazz.getMethod("eat", int.class);
m.invoke(p, 3); //invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。
//执行私有的方法
Method m =clazz.getDeclaredMethod("sleep",int.class);
//设置访问权限允许访问
m.setAccessible(true);
m.invoke(null, 6);*/
Method m = clazz.getMethod("sum", int[].class);
m.invoke(p,new int[]{12,5,9});
5.Class对象获取对象的成员变量(Field)
//获取到对应的Class对象Class clazz = Class.forName("cn.itcast.reflect.Person");
//获取 到所有的成员变量
/*Field[] fields = clazz.getDeclaredFields();
Person p = new Person();
Field field = clazz.getDeclaredField("id");
//设置访问权限可以访问
field.setAccessible(true);
field.set(p, 110); //第一个参数: 设置该数据 的成员变量, 第二个参数:属性值。
二:获取泛型参数:
// 在这里获取子类传递泛型值
// Type gType = this.getClass().getGenericSuperclass();//获取泛型参数类型
// ParameterizedType pType = (ParameterizedType)gType;//我们需要把它强转成参数类型
// Type[] types = pType.getActualTypeArguments();//获取真实的参数,返回的是一个数组,其中每个type就是一个Class,它对应真实的泛型参数
// c = (Class)types[0];
c = (Class)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];//等价于上面