泛型
什么是泛型?
使用泛型有什么好处?
没有使用泛型时,只要是对象,不关是什么类型的对象,都可以存储进同一个集合中。使用泛型集合,可以将一个集合中的元素限定为一个特定的类型,
集合中只能存储同一个类型的对象,这样更安全;并且当从集合获取一个对象时,编译器也可以知道这个对象的类型,不需要对对象进行强制类型转换
这样就更方便
泛型的通配符
通配符的使用:?
可以指向任意类型,
总结,使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用于参数化无关的方法,不能调用与参数化有关的方法
通配符的扩展:
限定通配符的上边界:
?extends Number
限定通配符的下边界:
?super Integer
限定通配符总是包括自己
如何自定义泛型?
定义泛型的方法
1,只有引用类型才可以作为泛型的方法的实际参数
2,用&来指定多个边界<V extends Serializable&cloneable> void mehtod(){}
练习题:采用自定义泛型方法的方式打印出任意参数化类型的集合中的所有内容
在这种情况下,前面的通配符方案比泛型方法更有效,
当一个类型变量用来表示两个参数之间或者参数和返回值之间关系时,
即同一个类型变量在方法前面的两处被使用,
或者类型变量在方法体代码中也被使用而不是仅在签名的时候使用,
才需要使用泛型方法。
public static void printCollection(Collection<?> collection){
//?可以指向任意类型,但是传入后不能调用一个与参数有关系的方法
//这个是错误的,collection.add(1);
System.out.println(collection.size());
for(Object o :collection){
System.out.println(o);
}
// collection.add(new Object());要使用这类型参数的时候,就要用T来定义泛型,否则可以用?
}
public static <T>void copyArray(Collection <T> collection,T[] t){
int i = 0;
//这个方法就必要定义T,因为传入了两个参数用来做运算。
for(T t1:collection){
t[i] = t1;
i++;
}
}
<演示代码何时用T或者?>
3,类型推断T:
GeneriesTest2.copyArray(new Collection<String> , s2);//为什么集合可以指明T?因为泛型里面有规定了<String>
copyArrtoArr(new Date[10],new String[10]);//取共有父类,数组没有统一规定就取共有的
Number i1 = add(3.5,3);
Object o = add(3,"abc");
类型向上转型,取最大公约数
private static <T> T add(T x,T y){
return null;
}
编辑器判断泛型的方法的实际类型参数的过程成为类型推断,类型推断是相对于知觉推断的。
根据调用泛型方法时实际传递的参数类型或者返回值的类型来判断
1,类型变量在一处应用,根据调用方法时该处的实际类型来确定
2,多处应用,对应同一种类型,根据传入类型确定
3,多处应用,对应不同类型,根据类型最大交集类型
4,多处应用包括返回值,优先考虑返回值类型
定义泛型的类
public class GeneriesDao<T>
对所有成员进行统一约束
泛型的注意事项:
1,参数化类型与原始类型的兼容性
Collection<String> c = new Vector();
Collection c = new Vector<String>();
以上代码不安全,只会提警告,但是可以运行
2,参数化类型不考虑类型参数的继承关系:
Vector<String> v = new Vector<Object>();
Vector<Object> v = new Vector<String>()
两者都是错误的
3,在创建数组实例时,数组的元素不能使用参数化类型
例如:
Vector<Integer> vectorlist[] = new Vector<Integer>[10];错误
4,在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型
5,当一个变量被声明为泛型时,只能被实例变量和方法调用,而不能被静态变量和静态方法调用。
因为静态成员是被所有参数化的类共享的,
所以静态成员不应该有(类级别)的类型参数
public static void update2(T t){
}
------------------------------------------------------------------------------------------------------------------------------------------
什么是类加载器?
就是加载类的工具,但是类加载器也是java类,但是有一个加载器不是java类,它是加载了必要的类的加载器叫BootStrap
加载器的究竟是怎样的一个顺序?如何加载?
什么是代理?
其实按照教程来讲可能会有点不是很容易理解,其实java中的代理是对存在相同接口的目标类进行额外的功能扩展,而实现这个功能的类叫做代理类
代理类用处?
很多时候我们需要临时扩展指定接口的目标类的功能,换个说法,我们要测试或者检查这些目标类的功能,所以要在这些功能上加上自己的测试代码
那么如何增加呢?
这个问题就产生了代理
代理的实现:

AOP
在java中如何创建自己的代理类呢?
这就是涉及到动态代理技术
package cn.itcast.day3;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
public class ProxyTest {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
Class classProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
//获取实现参数接口的代理类
System.out.println(classProxy1.getName());
Constructor [] constructors = classProxy1.getConstructors();
/*$Proxy0()
$Proxy0(InvocationHandler,int)*/
System.out.println("----------begin Conustructor list---------------");
for(Constructor constructor : constructors){
String s = constructor.getName();
StringBuilder sBuilder = new StringBuilder(s);
sBuilder.append("(");
Class [] classParams = constructor.getParameterTypes();
for(Class clazzParams :classParams){
sBuilder.append(clazzParams.getName()).append(",");
}
if(classParams != null&&classParams.length != 0)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(")");
System.out.println(sBuilder.toString());
}
Method [] Methods = classProxy1.getMethods();
/*$Proxy0()
$Proxy0(InvocationHandler,int)*/
System.out.println("----------begin Method list---------------");
for(Method metod : Methods){
String s = metod.getName();
StringBuilder methodString = new StringBuilder(s);
methodString.append("(");
Class [] classParams = metod.getParameterTypes();
for(Class clazzParams :classParams){
methodString.append(clazzParams.getName()).append(",");
}
if(classParams != null&&classParams.length != 0)
methodString.deleteCharAt(methodString.length()-1);
methodString.append(")");
System.out.println(methodString.toString());
}
System.out.println("----------begin create instance Object list---------------");
//创建实现了Collection接口的动态类和查看其名称,分析Proxy.getProxyClass方法的各个参数。
/*创建动态类的实例对象
1,用反射获得构造方法
2,编写一个最简单的InvocationHandler类
3,调用构造方法创建动态类的实例对象,并将编写的InvocationHandler类的实例对象传进去
打印创建的对象和调用对象的没有返回值的方法和getClass方法,演示调用其他有返回值的方法报告了异常。
4,将创建动态类的实例对象的代理改成匿名内部类的形式编写,锻炼大家习惯匿名内部类。*/
Constructor constructor = classProxy1.getConstructor(InvocationHandler.class);
class MyInvocationHandler1 implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHandler1());
proxy1.clear();
//proxy1.size();空指针异常
Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
});
;
Collection proxy3 =
//返回的是动态代理类,里面的方法全是已经修改过的,所以表面形式是一样,但是内里的方法是不同的
//利用了反射原理对方法进行重做,传入对象,方法和变量,利用method.invoke就可以实现代理
//代理里面持有InvocationHandler对象,调用方法的时候就是调用InvocationHandler类里面的invoke方法
//但是传入的Collection对象不是实现对象,要在InvocationHandler中创建需要操作的对象例如下列的ArrayList
(Collection)Proxy.newProxyInstance(Collection.class.getClassLoader(),
new Class[]{Collection.class},
new InvocationHandler(){
//直接创建实现参数接口的代理类对象
//方法自动重写。
ArrayList target = new ArrayList();//实际操作对象,proxy只是代理集合类,不是集合类
@Override
public Object invoke(Object proxy, Method method, Object[] args)
//涉及三要素:objProxy对象、add方法、“abc”参数
throws Throwable {
long startTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+"runtime....."+(endTime-startTime));
return retVal;
//return method.invoke(proxy,args) 死循环
}
});
proxy3.add("123");
//每掉用一次add就去找invacationHandler的子类传入生成动态类对象的invoke方法
//涉及三要素:proxy3对象、add方法、“123”参数
proxy3.add("dfg");
//add方法运行原理:
/*boolean add(Object obj){
handler.invoke(this,this.getClass().getMethod("add"),obj);
}*/
proxy3.add("ffg");
System.out.println(proxy3.size());
/*
* 以上方法有两个不足,第一ArrayList要自身编译,第二功能代码要写固定
* 所以利用面向切面的编程,利用两个对象封装了,方法和操作对象给InvacationHandler
* */
System.out.println("----------begin create instance autoObject2 list---------------");
/*实现操作对象和封装了方法的对象传入*/
final ArrayList target = new ArrayList();
Collection proxy4 = (Collection)getProxy(target,new MyAdvice());
proxy4.add("aaa");
proxy4.add("bbb");
proxy4.add("ccc");
System.out.println(proxy4.size());
}
private static Object getProxy(final Object target,final Advice advice) {
//target是实际操作的对象,Advice是自身现实了功能的对象,
//作为InvocationHandler子类对象invoke方法的调用
//Advice是一个接口,这个接口就自定义了invoke主方法前和后的抽象方法,
//我们只要实现其子类和复写方法即可,这样就不用把功能写死了
Object proxy4 =
Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
});
return proxy4;
}
}
package cn.itcast.day3.aopframework;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import cn.itcast.day3.Advice;
public class BeanFactory {
//通过配置文件来选择创建代理或者是对象。Bean工厂..
Properties props = new Properties();
public BeanFactory(InputStream ips){
try {
props.load(ips);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Object getBean(String name){
String className = props.getProperty(name);
Class clazz = null;
Object bean = null;
try {
clazz = Class.forName(className);
bean = clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
//对javabean来说,必须有一个不带参数的构造方法
if(bean instanceof ProxyFactoryBean){
ProxyFactoryBean pfb = (ProxyFactoryBean)bean;
try {
Advice advice = (Advice)Class.forName(props.getProperty(name + ".advice")).newInstance();
Object target = Class.forName(props.getProperty(name + ".target")).newInstance();
pfb.setAdvice(advice);
pfb.setTarget(target);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Object proxy = pfb.getProxy();
return proxy;
}
return bean;
}
}
<以下是图示>