7.泛型
泛型是给javac编译器使用的,可以限定集合 中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会除掉“类型”信息,是程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型不一样。
由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往泛型集合中计入其他类型的数据。
例如:用反射得到集合,在调用其add方法即可。
//通过反射给泛型添加元素
//泛型是给编译器使用的。
ArrayList<Integer> al2=new ArrayList<Integer>();
al2.getClass().getMethod("add", Object.class).invoke(al2, "abc");
System.out.println(al2.get(0));
术语:
整个称为ArrayList<E>泛型类型
ArrayList<E>中的E称为类型变量或类型参数
整个ArrayList<Integer>称为参数化的类型
ArrayList<Integer>中的Integer称为参数类型的实例或实际类型参数
ArrayList<Integer>中的<>念为typeof
ArrayList称为原始类型
参数化类型与原始类型的兼容性:
参数化类型可以引用一个原始类型的对象, 编译报告警告,例如:
Collection<String> c=new Vector();
原始类型可以引用一个参数化类型交给你的对象,编译报告警告,例如:
Collection c=new Vector<String>();
参数化类型不考虑类型参数的继承关系:
Vector<String> v=new Vector<Object>();//错误
Vector<Object> v=new Vector<String>();//错误
在创建数组实例时,数组的元素不能使用参数化类型的类型,例如
Vector<Integer> vectorList[]=new Vector<Integer>[10];//错误
?通配符:
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以提哦啊用与参数化无关的方法,不能调用与参数化有关的方法
例子:
private static void printCollection(Collection<?> collection)
{
System.out.println(collection.size());
for (Object object : collection)
{
System.out.println(object);
}
}
扩展:
限定上边界:
正确:Vector<? extends Number> x=new Vector<Integer>();
错误:Vector<? extends Number> x=new Vector<String>();
限定下边界:
正确:Vector<? super Integer> x=new Vector<Number>();
错误:Vector<? super Integer> x=new Vector<Byte>();
提示:
限定通配符总是包括自己。
类型参数的类型判断:
根据调用泛型方法是实际传递的参数类型或返回值的类型来推断,规则如下:
1.当某个类型变量只在整个参数列表中的所有参数和返回值中的一处被应用了,那么根据调用方法是该处的实际应用类型来确定。
即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型。
swap(new String[3],3,4) --> static <T> void swap(T[]a ,int i,int j);
2.当某个类型变量在整个参数列表中的所有参数和返回值的多处被应用了,如果调用方法时着多处的实际应用类型都对应同一种类型来确定。
add(3,5) --> static <T> T add(T a,T b)
3.当某个类型变量在整个参数列表中的所有参数和返回值的多处被应用了,如果调用方法时这多处的实际应用对应了不同的类型,且没有使用返回值,这时候取多个参数中的最大交集类型。
例如:下面语句实际对应的类型就是Number,编译没问题,只是运行时出问题。
fill(new Integer[3],3.5f) --> static <T> void fill(T[] a,T v)
4.当某个类型变量在整个参数列表中的所有参数和返回值的多处被应用了,如果调用方法时这多处的实际应用对应了不同的类型,并且使用返回值,这时候优先考虑返回值的类型。
例如:下面语句实际对应的类型就是Integer了,编译将报告错误,将变量x的类型改为float,对比eclipse报告的错误提示,接着在将变量x的类型改为Number就可以了
int x=(3,3.5f) --> static <T> T add(T a,T b);
5.参数类型的类型推断具有传递性,下面第一种情况推断实际参数类型为Object,编译没有问题,而第二种情况则根据参数化的Vector类实例将类型变量直接确定为String类型,编译将出现问题。
copy(new Integer[5],new String[5]) --> static <T> void copy(T[] a,T[] b);
copy(new Vector<String>(),new Integer[5]) --> static <T> void copy(Collection<T> a,T[] b);
定义泛型类型:
如果类的实例对象中的多处都要用到同一个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型时,这时候要采用泛型类型的方式进行定义,也就是类级别的泛型。
格式:
public class GenericDao<T>{
private T file1;
public void save(T t){}
public T getById(int id){}
}
类级别的泛型时根据引用该类名时指定的类型信息李艾参数化类型变量的。
例如:
GenericDao<String> dao=null;
new GenericDao<String>();
注意:
在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。
当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不是被静态变量和静态方法调用。因为静态成员是被所有参数实例化的类所共享的,所以静态成员不应该有类级别的类型参数。
MyEclipse
调试
想要查看某个遍历的值?
选中变量,右键watch,在debug下就可以查看变量的值
透视图
透视图perspective包含视图view
编译
高版本的java能运行低版本的javac编译的程序
低版本的java不能运行高版本的javac编译的程序
导入外部程序
把外部的工程拷贝到指定目录下。java页面下Import导入File System
overload与override的区别
Overload是重载的意思,Override是覆盖的意思,也就是重写。
重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。
overload对我们来说可能比较熟悉,可以翻译为重载,它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,VM就会根据不同的参数样式,来选择合适的方法执行。
在使用重载要注意以下的几点:
1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int,float),但是不能为fun(int,int);
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响;
4、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。
重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。
子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。
子类方法的访问权限只能比父类的更大,不能更小。如果父类的方法是private类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。
override可以翻译为覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。
对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。
除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。
在覆盖要注意以下的几点:
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;
3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
|
|