---------------------- ASP.Net+Android+IO开发S.Net培训、期待与您交流! ----------------------

高新技术(2)

1,Beannutils工具包:
我们在操作JavaBean的时候我们可以用Introspector的方式来操作,但是呢这样需要我们写大量的代码。
Apache小组为我们提供了很有用的工具包来操作JavaBean
也就是BeanUtils工具包,这个可以到apache.org上面下载commons-BeanUtils工具包,
同时我们也要下载Logging也就是日志工具包 。
BeanUtils类中的所有方法都是静态方法我们通过它的getProperty setProperty方法 等等方法 这里我们主要用到BeanUtils类
首先我们应该将jar包加入到Eclipse的BuildPath中 然后我们才能使用BeanUtils工具包中的各种类
下面是一个简单的JavaBean
package me.test;
import java.util.Date;
public class BeanTest
{
private intx ;
private Date birthday=newDate() ;
public BeanTest(int x)
{
this.x=x;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}

}
下面是操作
package me.test;
importjava.lang.reflect.InvocationTargetException;
import java.util.*;
importorg.apache.commons.beanutils.BeanUtils;
public class Test
{
publicstatic void main(String []args) throwsIllegalAccessException, InvocationTargetException,NoSuchMethodException
{
BeanTest t=new BeanTest(6) ;
BeanUtils.setProperty(t,"x",7);//设置x属性 ,利用BeanUtils设置值的时候值可以是任意原始类型 也可以是String类型 在web开发中我们用到的都是String类型因为网页间传递的是字串如果我们不想进行字符串转换那个就用PropertyUtils类和 BeanUtils类有着同样的作用只不过PropertyUtils 不进行类型的转换
System.out.println(BeanUtils.getProperty(t,"x")); //返回x属性
BeanUtils.setProperty(t,"birthday.year", "111") ; //这是birthday的year的属性值
System.out.println(BeanUtils.getProperty(t,"birthday.year")); //BeanUtils可以进行级联设置
Mapm=BeanUtils.describe(t); //将JavaBean的各种属性以及值以Map的形式描述


}

}
2,注解:

@SuppressWarnings:压缩警告
通过System.runFinalizersOnExit(true);的编译警告引出
@Deprecated
过时的提示
@Override
重写的注释。
注释相当于一种标记,在程序中加了注释就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,Javac编译器,开发
工具和其他程序可以用反射来了解你的类及各种元素上有无任何种标记,看你有什么标记,就去干相应的事,标记
可以加在包,类,字段,方法,方法的参数以及局部变量上。
看Java.lang包,可以看到JDK中提供的最基本的annotation.

定义一个最简单的注解:public @interface MyAnnotation{}
把它加在某一个类上:@MyAnnotation public class AnnotationTest(){}
用反射进行测试:
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
ItcastAnnotationannotation =(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation);
}
根据反射测试的问题引出@Rectetion元注解的讲解,其三种取值:RetelonPocllcy.SOURCE,
RetelonPocllcy.CLASS,
RetelonPocllcy.RUNTIME
RectetionPocllcy.RUTIME:分别对应的:java源文件-->class文件-->内存中的字节码
Override保留在 :RetelonPocllcy.SOURCE,
SuppressWarnings保留在:RetelonPocllcy.SOURCE
Deprecated保留在:RetelonPocllcy.RUTIME,

@Target元注解:
Target的默认值为任何元素,设置Target等于ElementType.METHOD,原来加在类上的注解就报错了改用数组方式设置@Target({ElementType.METHOD,ElementType.TYPE})就可以了

元注解以及枚举属性值具体查看API文档java.lang.annotation包下面的类。

注解的详细语法可以通过java语言规范了解,即看java的languagespecification。

注解增加的高级属性:
数组类型的属性
int[] arrayAttr() default{1,2,3}
@MyAnnotation(arraAttr = {2,3,4})
如果数组属性中有一个元素,这时候属性值部分可以省略大括号。
枚举类型的属性
Enum Test.TraficLamp();
@MyAnnotation(lamp = EnumTest.TraficLamp.GREEN)

注释类型的属性
MetaAnnotation annotationAttr() default@MetaAnnotation("XXX")
@MyAnnotation(annotationAttr =@MetaAnnotation("YYY"))
可以认为上面这个@MyAnnotation是MyAnnotation类的一个实例对象,同样的道理,可以认为上面这个@MetaAnnotation是MetaAnnotation类的一个实例对象,调用代码如下:
MetaAnnotation =myAnnotation.annotationAttr();
System.out.println(ma.value());

3,泛型:
没有使用泛型时,只要是对象,不管是什么类型的对象,都可以存储进同一个集合中,使用泛型集合,可以将一个
集合中的元素限定为一个特定的类型,集合中只能存储同一个类型的对象,这样更安全,并且当从集合获取一个对
象的类型,不需要对 对象进行强制转换。这样更方便。


了解泛型
ArrayList<E>类定义和ArrayList<Integer>类引用涉及的术语:
整个称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>();//也错误

泛型中的类型参数严格说明集合中装载的数据类型是什么和可以加入什么类型的数据,记住
Collection<String>和Collection<Object>是两个没有转换关系的参数化的类型。

假设:Vector<String>v = newVector<Object>();可以的话,那么以后从V中取出
的对象当作String用,而而V实际指向的对象中可以加入任意类型对象。

假设:Vector<Object>v =newVector<String>();可以的话,那么以后向V中加入
任意类型的对象,而v实际指向集合中只能装String类型的对象。

在创建数组实例时,数组的元素不能使用参数化的类型,例如,下面语句有错误,
Vector<Integer>vectorList[] = newVector<Integer>[10];

小思考题:
Vector v1 = newVector<String>();参数类型可以给原始类型
Vector<Object> v = v1;原始类型也可以给参数类型。
一行一行推理就知道了。。。
这两句都不会报错。


泛型中的? 通配符
总结:使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量用作引用,可以调用
与参数化无关的方法,不能调用与参数化有关的方法。
泛型的限定:
上限:例子
正确:Vector<?extends Number> x = newVector<Integer>();
错误:Vector<?extends Number> x = newVector<>(String);
下限:
正确:Vector<?super Integer> x = newVector<Number>();
错误:Vector<?super Integer> x = new Vector<Byte>();
小注意:限定通配符总是包括自己。

泛型方法的练习题:
1,编写一个泛型方法,自动将Object类型的对象转换成其他类型:
main:{ Object obj ="abcd";
String x3 =autoConvert(obj);
System.out.println(x3);
}

private static <T>T autoConvert(Object obj) {

return (T)obj;

2,定义一个方法,可以将任意类型的数组中的所有元素填充为相应类型的某个对象。

private static <T>void fillArray(T[] a,T obj){
for(inti=0;i<a.length;i++){
a[i]= obj;
}
}

swap(newString[]{"abc","xyz","itcast"},1,2);
swap(newint[]{1,2,3,4,5},2,4);//为什么会报错,因为,只有引用类型才能作为泛型方法的实际参数。

private static <T>void swap(T[] a,int i,int j){
T temp =a[i];
a[i]=a[j];
a[j] =temp;
}
3,采用自定义泛型的方法的方式打印出任意参数化类型的集合中的所有内容。
在这种情况下,前面的通配符方案要比泛型方法更有效,当一个类型变量用来表达两个参数之间或者参数和返回值
之间的关系时,即同一个类型变量在方法签名的两处被使用,或者类型变量在方法体代码中也被使用而不是仅在签
名的时候使用,才需要使用泛型方法。

4,定义一个方法,把任意参数类型的集合中的数据安全地复制到相应类型的数组中。
public static<T> void copy1(Collection<T> dest,T[] src){

}
5,定义一个方法,把任意参数类型的一个数组中的数据安全地复制到相应类型的另一个数组中。
public static<T> void copy2(T[] dest,T[]src){

}

类型参数的类型推断:
编译器判断泛型方法的实际类型参数的过程称为类型推断,类型推断是相对于知觉推断的,其实现方法是一种非常复杂
的过程,

根据调用泛型方法时实际传递的参数类型或返回值的类型来推断,具体规则如下:
1,当某个类型变量只在整个参数列表中的所有参数和返回值中的一处被应用了,那么根据调用方法时该处的实际应用
类型来确定,这很容易凭着感觉推断出来,即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型。
例如:
swap(newString[3],3,4)->static<E> void swap([E] a,int i,intj)

2,当某个类型变量在整个整数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型
都对应同一种类型来确定,这很容易凭着感觉推断出来,例如:
add(3,5)->static <T> T add(T a, T b)

3,当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型
类型对应到了不同的类型,且没有使用返回值,这时候取多个参数中的最大交集类型,例如:下面的语句实际对应的
类型就是Number了,编译没问题,只是运行时出问题:
fill(New Integer[3],3,5)->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> voidcopy(T[] a ,T[] b)
copy(newVector<String>(),newInteger[5])->static<T>void copy(Collection<T> a,T[] b)


自定义泛型类:

注意的地方:
在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。
当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用,因为静态成员
是被所有参数化的类所共享的,所以静态成员不应该有类级别的类型参数。

问题:类中只有一个方法需要使用泛型,是使用类级别的泛型,还是使用方法级别的泛型?
类级别的。

4,类加载器:

Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类。
BootStrap,ExtClassLoader,AppClassLoader。
类加载器也是java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是不是java类,
这个正是BootStrap

java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级
类装载器对象或者默认采用系统类装载器为其父类加载。

图形表示:
BootStrap--->JRE/lib/rt.jar
|
|
ExtClassLoader--->JRE/lib/ext
public static void main(String[] args)throwsException {

String srcPath =args[0];
String destDir = args[1];
FileInputStream fis = newFileInputStream(srcPath);
String destFileName =srcPath.substring(srcPath.lastIndexOf('\\')+1);
String destPath = destDir+"\"+destFileName;
FileOutputStream ops = newFileOutputStream(destPath);
cypher(fis,ops);
fis.close();
ops.close();
}
//将要加密的文件 进行加密
private static void cypher(InputStreamips,OutputStream ops) throws Exception{

int b =-1;

while((b=ips.read())!=-1){
ops.write(b^0xff);
}
}
private String classDir;



@Override
// 自定义类加载器:
protected Class<?>findClass(String name) throws ClassNotFoundException {
String classFileName = classDir+ "\" +name.substring(name.lastIndexOf('.')+1)+".class";
try {
FileInputStreamfis = new FileInputStream(classFileName);

ByteArrayOutputStreambos = new ByteArrayOutputStream();

cypher(fis,bos);
fis.close();
System.out.println("aaaa");
byte[] bytes= bos.toByteArray();
returndefineClass(bytes,0,bytes.length);
} catch (Exception e) {

e.printStackTrace();
}
return null;
}
public MyClassLoader(){

}
public MyClassLoader(String classDir){
this.classDir = classDir;
}

}


5,动态代理(使用的场合:调试,远程方法的调用):

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,
无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,
因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect包中的Proxy类和InvocationHandler
接口提供了生成动态代理类的能力。

Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,
cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,
但因为采用的是继承,所以不能对final修饰的类进行代理。
1,Overview

Java在java.lang.reflect包下,定义了自己的代理。利用这个包下的类,我们可以在运行时动态地创建一个代理类,
实现一个或多个接口。并将方法的调用转发到你所指定的类。因为实际代理是在运行时创建的,所以称为:动态代理。


Proxy:完全由java产生的,而且实现了完整的subject接口。

InvocationHandler:Proxy上的任何方法调用都会被传入此类,InvocationHandler控制对RealSubject的访问。

因为Java已经帮助我们创建了Proxy类,我们需要有办法告诉Proxy类你要做什么,
我们不能像以前一样把代码写入到Proxy类中,因为Proxy类不是我们实现的。
那么我们应该放在哪里?放在InvocationHandler类中,InvocationHandler类是响应代理的任何调用。
我们可以吧InvocationHandler想成是代理收到方法调用后,请求做实际工作的对象。

2. java.lang.reflect.InvocationHandler

被代理实例所实现的一个接口,内部只有一个invoke()方法,签名如下;

Java代码

public Object invoke(Object proxy, Method method, Object[]args)

当代理的方法被调用的时候,代理就会把这个调用转发给InvocationHandler,也就会调用它的invoke()方法。

3. java.lang.reflect.Proxy

提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类,我们经常使用的静态方式是:

Java代码

newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h)

 4. 示例:

情形:自己可以查看修改姓名性别,但是不能修改rate。他人可以查看姓名,性别以及修改rate,但是不能修改姓名性别。

4.1 定义一个接口:

Java代码

public interface Person {

String getName();

String getGender();

void setName(String name);

void setGender(String gender);

void setRate(int rate);

int getRate();

}

4.2 定义实现Person接口类

Java代码

public class PersonImpl implements Person {

String name;

String gender;

String interests;

int rate;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getGender() {

return gender;

}

public void setGender(String gender) {

this.gender = gender;

}

public String getInterests() {

return interests;

}

public void setInterests(String interests) {

this.interests = interests;

}

public int getRate() {

return rate;

}

public void setRate(int rate) {

this.rate = rate;

}[nextpage]

4.3 定义OwnerInvocationHandler类,表示如果为本人,则可以进行修改查看姓名性别。

Java代码

public class OwnerInvocationHandler implementsInvocationHandler{

private Person personBean;

public OwnerInvocationHandler(Person personBean){

this.personBean = personBean;

}

@Override

public Object invoke(Object proxy, Method method, Object[]args)

throws IllegalAccessException {

try {

if(method.getName().startsWith("get")){//如果方法名为get,就调用person类内的get相应方法

return method.invoke(personBean, args);

}else if(method.getName().equals("setRate")){ //如果方法是setRate,则抛出异常

throw new IllegalAccessException("access deny");

}else if(method.getName().startsWith("set")){//如果为set,就调用person类内的set相应方法

return method.invoke(personBean, args);

}else {

System.out.println("non method invoke");

}

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return null;

}

}

4.4 定义NonInvocationHandler类,表示如果不为本人,则可以进行查看姓名性别和修改rate。

Java代码

public class NonInvocationHandler implementsInvocationHandler{

private Person person;

public NonInvocationHandler(Person person){

this.person = person;

}

@Override

public Object invoke(Object proxy, Method method, Object[]args)

throws Throwable {

if(method.getName().startsWith("setRate")){

return method.invoke(person, args);

}else if (method.getName().startsWith("get")){

return method.invoke(person, args);

} else {

System.out.println("non method invoke");

return null;

}

}

}

4.5 测试类MyDynamicProxy

Java代码

public class MyDynamicProxy {

public Person getOwnerPersonBeanProxy(Person person){

return(Person)Proxy.newProxyInstance(person.getClass().getClassLoader(),

person.getClass().getInterfaces(), newOwnerInvocationHandler(person));

}

public Person getNonPersonBeanProxy(Person person){

return(Person)Proxy.newProxyInstance(person.getClass().getClassLoader(),

person.getClass().getInterfaces(), newNonInvocationHandler(person));

}

public static void main(String[] args) {

MyDynamicProxy mdp = new MyDynamicProxy();

mdp.test();

}

public void test(){

//

Person person = getPersonBeanFromDB1();

Person personProxy = getOwnerPersonBeanProxy(person);

System.out.println(personProxy.getName());

try {

personProxy.setRate(2);

} catch (Exception e) {

System.out.println("can not setRate");

}

//

Person person1 = getPersonBeanFromDB1();

Person personProxy2 = getNonPersonBeanProxy(person1);

System.out.println(personProxy2.getName());

personProxy2.setRate(2);

System.out.println(personProxy2.getRate());

}

private Person getPersonBeanFromDB1(){

Person pb = new PersonImpl();

pb.setName("remy");

pb.setGender("girl");

pb.setRate(1);

return pb; }

输出结果:

Java代码

remy can not setRate remy 2

Spring框架两大核心内容 一个是bean工厂,一个是Aop。


---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------