黑马程序员 Java高新技术2

本文详细介绍了JavaBean的概念及其PropertyDescriptor类的使用方法,包括属性的读取和设置。同时,深入探讨了Java泛型的基本概念、应用场景及其实现细节,例如通配符、自定义泛型方法和泛型类的定义。

 ------- android培训java培训、期待与您交流! ----------

 

内省--JavaBean

关于PropertyDescriptor类:PropertyDescriptor类表示JavaBean类通过存储器导出一个属性。

其中的方法

1.getPropertyType( )获得属性的Class对象。

2.getReadMethod( )获得用于读取属性值的方法。

3.getWriteMethod( )获得用于写入属性值的方法。

4.setReadMethod( )设置用于读取属性值的方法。

5.setWriteMethod( )设置用于写入属性值的方法。

部分代码:

PropertyDescriptor pd = new PropertyDescriptor(propertyName, 对象.getClass());

Method methodGet = pd.getReadMethod();

Object retValX = methodGet.invoke(对象);

System.out.println(retValX);

采用遍历BeanInfo的所有属性方式来查找和设置某个RefectPoint对象的x属性。在程序中把一个类当作JavaBean来看,就是调用IntroSpect.getBeanInfo方法,得到的BeanInfo对象封装了吧这个类当作JavaBean看的结果信息。

部分代码如下:

      BeanInfo beanInfo = Introspector. getBeanInfo(e.getClass());
      PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
      Object retVal =  null;
      for(PropertyDescriptor p : pds){
            if(p.getName().equals(propertyName)){
                  Method methodGet = p.getReadMethod();
                  retVal = methodGet.invoke(e);                   
            }                 
      }
      return retVal;

BeanUtils工具包与logging包:

获得属性的值,BeanUtils.getProperty(pt1,"x"),返回的是字符串类型。

设置属性的值,BeanUtils.setProperty(pt1,"y",9).

注意:对象不能为null。如,private Date birthday=new Date()。

在Java1.7中有一些新特性:如,Map和JavaBean之间可以进行相互转换,map可以简化书写,Map map = (name:"zxx",age:18)。

这里要说明的是,在使用PropertyUtils类的setProperty(bean,name,value)方法没有类型转换,使用属性的原有类型或者包装类。

Java中的注解(annotation):

1.@SuppressWarnings("Deprecation"),取消过时警告。

2.@Deprecated,注明过时。

3.@Override,重写方法注解,当重写错误时会报错。

注解相当于一种标记,在程序中加上注解就相当于为程序打上了某种标记,没加,则等于没有某种标记,以后,Javac编译器,开发工具和其他可以用反射来了解你的类及各种元素上有无各种标记,看你有什么标记,就去干相干的事,标记可以加在包、类、字段、方法、方法的参数以及局部变量上。

自定义注解:

1.定义一个简单注解格式:punlic @interface MyAnnotation{}.

2.把它加在某个类上:

@MyAnnotation

public class AnnotationTest{

}

3.RetentionPolicy规定的三个作用范围:

一,只在源代码中起作用,SOURCE。二,只在编译之后的class中起作用,Class。三,在运行时其作用,RUNTIME。

@Override、@SuppressWarnings是默认保留到SOURCE阶段;@Deprecated是保留到RUNTIME阶段。

@Target注释中,存在ElementType类型的变量,表示注解类应该在什么位置,对那一块的数据有效。

在方法上有效:@Target(ElementType.METHOD),在类或接口上有效:@Target(ElementType.Type),在构造方法(CONSTRUCTOR),在包上(PACKAGE)等。

例:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)

public @interface MyAnnotation {

}

注解增加基本属性:

注解类似于借口,属性类似于借口的方法。引用注解时,所有的属性必须全部出现,除非属性有缺省值。

如果只有value属性,没有其他属性,可以不写“=”。

程序的部分代码,判断是否为指定的Annotation,并通过反射建立对象:

@ItcastAnnotation(color="black")
...
...
	if(AnnotationDemo.class.isAnnotationPresent(ItcastAnnotation.class)){
 		ItcastAnnotation annotation =(ItcastAnnotation)AnnotationDemo.class.getAnnotation(ItcastAnnotation.class);
 		System.out.println(annotation.color());
 	}
 

泛型:

使集合定向的存入某种类型的数据<T>。

例:

	ArrayList<String> collection1 = new ArrayList<String>();    
	collection1.add(1);    
	collection1.add(1L);    
	collection1.add("String");    
	String i = collection1.get(0);
	//反射中的应用    
	String str = new String(new StringBuffer("abc"));         
	Constructor<String> constructor1 = String.class.getConstructor(StringBuffer.class);           
	String str1 = constructor1.newInstance(new StringBuffer("abc"));    
	System.out.println(str1.charAt(2));    

关于反射绕过泛型的限制实例

部分代码:

	ArrayList<Integer> collection3 = new ArrayList<Integer>();    
	System.out.println(collection3.getClass()==collection2.getClass());    
	
	collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");    
	System.out.println(collection3.get(0));  


结果为:true abc。

ArrayList<E>类定义和ArrayList<Integer>类引用中涉及的术语:

1.ArrayList<E>:这个整体称为“泛型类型”,其中的“E”称为 类型变量 或 类型参数 。

2.ArrayList<Integer>:整体称为“参数化的类型”,“Integer”称为“类型参数的实例”或“实际类型参数”,"<>"读为typeof,ArrayList称为“原始类型”。

3.参数化类型与原始类型的兼容性:可以互相引用,但编译器会报告警告。

4.参数化类型不考虑类型参数的继承关系 。

5.编译器不允许创建类型变量的数组。在创建数组实例时,数组的元素不能使用参数化的类型。

关于泛型中的通配符:

1.限定通配符的上边界:
Vector<? extends Number>  x = new Vector<Integer>();正确。
Vector<? extends Number>  x = new Vector<String>():错误。
2.限定通配符的下边界:
Vector<? super Integer>  x = new Vector<Number>();正确。
Vector<? super Integer>  x = new Vector<Byte>();错误。

使用<?>通配符可以引用其他各种参数化的类型,<?>通配符定义的变量主要用作引用,可以调用与参数无关的方法,不能调用与参数化有关的方法。

泛型综合应用代码:

	HashMap<String,Integer> maps = new HashMap<String,Integer>();    
	hm.put("zhangsan", 20);    
	hm.put("lisi", 30);    
	hm.put("wangwu", 23);    

	Set<Map.Entry<String,Integer>> entrySet = maps.entrySet();    
	for(Map.Entry<String, Integer> entry:entrySet){    
		System.out.println(entry.getKey() + ":" + entry.getValue());    
	}    

自定义泛型例:

	add(1,2);    
	Number x1 = add(3.1.4);   //注意x1类型
	Object x2 = add(3,"abc");   //注意x2类型
      
	private static<T> T add(T x,T y){   //自定义泛型方法
		return null;    
	}  

数组中交换两个元素的位置(类型不确定)。

	swap(new String[]{"abc","xxx","it"},0,1);    
	

	private static<T> void swap(T[] t ,int x,int y){    
		T temp = t[x];    
		t[x] = t[y];    
		t[y] = temp;    
	}   

泛型类的定义:

格式:

public class GenericDao<T>{

public void save(T obj){}

public T getById(int id){}

}

注意:

1.在对泛型类型进行初始化时,类型参数的实例引用必须是引用类型,不能是基本类型。

2.当一个变量声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用。因为静态成员是被所有参数化的类所共享,所以静态成员不应该有类级别的类型参数。

类中只有一个方法需要使用泛型时使用类级别的泛型。
类加载器:

java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个负责特定位置的类,BootStrap xitClassLoader AppClassLoader。

类加载器也是java类,因为其他是java类的类加载器也要被类加载器加载,显然必须有第一个类加载器不是java类, 这正是:BootStrap。

import java.util.Date;
public class ClassLoderTest {

    public static void main(String[] args) throws Exception {
        System.out.println(ClassLoderTest.class.getClassLoader().getClass().getName());
        System.out.println(System.class.getClassLoader());
        
        ClassLoader loader = ClassLoader.class.getClassLoader();
        while(loader!=null){
            System.out.println(loader.getClass().getName());
            loader = loader.getParent();
        }
        System.out.println(loader);    
        System.out.println(new ClassLoaderAttachment().toString());
    }
}

当Java虚拟机要加载一个类时,派出哪个类加载器加载:

1.首先当前线程的类加载器去加载线程中的第一个类。

2.如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器来加载类B。

3.还可以直接调用ClassLoader.LoadClass方法来指定某个某个类加载器去加载某个类。

每个类加载器加载类时,又首先委托给其上级类加载器。

当所有类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFindException,不是再去找发起者类加载器的子类,因为没有getChild方法。

自定义类加载器

1.自定义的类加载器必须继承ClassLoader。

2.loadClass方法与findClass方法:只需重新findClass方法,就会跳出委托机制。

3.defineClass方法。

编程步骤:

1.编写一个队文件内容进行监督加密的程序。

2.编写了一个自己的类加载器,可实现对加密的类进行撞在和解码。

3.编写一个程序调用类加载器加载类,在源程序中不能用该类定义引用变量,因为编程器无法识别这个类。程序中可以除了使用ClassLoader.load方法外,还可以使用使用设置线程的上下文加载器或者系统加载器,然后再使用Class.forName。

 实例:

package study.day2;
import java.util.Date;
public class ClassLoaderAttachment extends Date {	
	@Override
	public String toString() {
		return "hello,itcast";
	}	
}
package study.day2;
import java.util.Date;
public class ClassLoderTest {
    public static void main(String[] args) throws Exception {
        Class clazz = new MyClassLoader("itcastlib").loadClass("study.day2.ClassLoaderAttachment");
        Date dd = (Date) clazz.newInstance();
        System.out.println(dd);
    }
}
package study.day2;
import java.io.*;
import com.sun.beans.finder.ClassFinder;
public class MyClassLoader extends ClassLoader{
    public static void main(String[] args) throws Exception {
        String srcPath = args[0];
        String destDir = args[1];
        FileInputStream fis = new FileInputStream(srcPath);
        String destFileName = srcPath.substring(srcPath.lastIndexOf('\\'));
        String destPath = destDir+destFileName;
        FileOutputStream fos = new FileOutputStream(destPath);
        cypher(fis,fos);
        fis.close();
        fos.close();
    }
        public static void cypher(InputStream fis, OutputStream fos) throws Exception {
        int b = -1;
        while((b=fis.read())!=-1){
            fos.write(b ^ 0xff);
        }
    }
    private String classDir;
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String classFileName = classDir+"\\"+name.substring(name.lastIndexOf('.')+1)+".class";
        try {
            System.out.println("It's MyClassLoader.");
            FileInputStream fis = new FileInputStream(classFileName);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            cypher(fis,bos);
            byte[] bys = bos.toByteArray();
            return defineClass(null, bys, 0,bys.length);            
        } 
        catch (Exception e) {
            e.printStackTrace();
        }
        return super.findClass(name);
    }
    public MyClassLoader(String classDir){
        this.classDir = classDir;
    }
}

代理

举例:

     class A     
     {    
       void sayHello()    
       {    
         System.out.println("hello itcast");    
       }    
     }    
         
        
    AProxy    
     {    
       void sayHello()    
       {    
         starttime;    
         A.sayHello();    
         endTime;    
       }     
     }   

AOP面向方面编程

1.系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方法。

2.交叉业务的房产问题即为面向方面的编程(AOP,Aspect oriented program),AOP的目标就是要使交叉业务模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编程切面代码的运行效果是一样的。

动态代理技术

1.要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情。(引出动态代理)

2.JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作 代理类 ,即动态代理类。

3.JVM生成的动态类必须具有一个或多个接口,所以,JVM生成的动态类(Proxy)只能用作具有相同接口的目标类的代理。

4.CGLIB库(第三方开源库)可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的 类生成动态代理类,可以使用CGLIB库。

JVM动态生成的类

创建实现了Collection借口的动态类,查看构造方法和参数名以及查看方法和参数名:

public class ProxytTest {
	public static void main(String[] args) throws Exception {
		Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
		System.out.println(clazzProxy.getName());
		
                //获取代理类的所有构造方法
		Constructor[] constructors = clazzProxy.getConstructors();
		System.out.println("---------begin constructors list--------");
		for(Constructor constructor : constructors){
			String constructorName = constructor.getName();
			System.out.print(constructorName);
			StringBuilder sb = new StringBuilder();
			sb.append("(");
			Class[] clazzParams = constructor.getParameterTypes();
			for(Class clazzParam : clazzParams){
				sb.append(clazzParam.getName()+",");
			}
			if(clazzParams != null && clazzParams.length != 0)
				sb.deleteCharAt(sb.length()-1);
			sb.append(")");
			System.out.println(sb.toString());			
		}
	        //获取代理类的所有方法
		Method[] methods = clazzProxy.getMethods();
		System.out.println("-------begin methods list-------");
		for(Method method : methods){
			String constructorName = method.getName();
			System.out.print(constructorName);
			StringBuilder sb = new StringBuilder();
			sb.append("(");
			Class[] clazzParams = method.getParameterTypes();
			for(Class clazzParam : clazzParams){
				sb.append(clazzParam.getName()+",");
			}
			if(clazzParams != null && clazzParams.length != 0)
				sb.deleteCharAt(sb.length()-1);
			sb.append(")");
			System.out.println(sb.toString());			
		}  

创建动态类的实例对象

1.用反射获得构造方法。

2.编写一个简单的InvocationHandler类。

3.调用构造方法创建动态类的实例对象,并将编写的InvocationHandler类的实例对象传进去。

4.打印创建的对象和调用对象的没有返回值的方法和getClass方法,演示调用其他返回值的方法报告了异常。

5.将创建动态类的实例对象的代理改成匿名内部类的形式编写。

例(接上例)

        	System.out.println("-------begin create instance object-------");               
        	Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class);      
 
        	class MyInvocationHandler implements InvocationHandler{  
            	@Override  
            		public Object invoke(Object proxy, Method method, Object[] args)  
                    		throws Throwable {  
               
                		return null;  
            		}             
       	 	}         
        	Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHandler());       

匿名内部类形式

		Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
			@Override
 			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				return null;
 			}});

用Proxy.newInstance方法获取

	Collection proxy3 = (Collection)Proxy.newProxyInstance(
		Collection.class.getClassLoader(),
		new Class[]{Cellection.class}, 
		new InvocationHandler(){
			ArrayList target = new ArrayList();
			public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			long before = System.currentTimeMillis();
			Object reValue = method.invoke(target, args);
			long after = System.currentTimeMillis();                        
			System.out.println(method.getName()+"---runtime---"+(after-before));
			return reValue;
			}
		});
	}

Object继承来的方法 只有toString , hashCode , equals ,  调用时委托给InvocationHandler,其他的方法Proxy自己都有实现。

通用性实例

import java.lang.reflect.Method;

public interface Advise {
	void before(Method method);
	void after(Method method);
}
import java.lang.reflect.Method;

public class MyAdvise implements Advise {
	long before = 0;
	public void before(Method method) {
		System.out.println("hello 黑马");
		before = System.currentTimeMillis();
	}
	public void after(Method method) {
		System.out.println("love 黑马");
		long after = System.currentTimeMillis();						
		System.out.println(method.getName()+"......"+(after-before));
	}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
public class ProxytTest {
	public static void main(String[] args) throws Exception {
        ArrayList target = new ArrayList();
        Advise advise = new MyAdvise();
        //调用方法
        Collection proxy4 = (Collection) getProxy(target,advise);
        //封装的方法
        private static Object getProxy(final Object target,final Advise advise) {
		Object proxy4 = Proxy.newProxyInstance(
				target.getClass().getClassLoader(),
				target.getClass().getInterfaces(), 
				new InvocationHandler(){
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						/*long before = System.currentTimeMillis();
						Object reValue = method.invoke(target, args);
						long after = System.currentTimeMillis();						
						System.out.println(method.getName()+"---runtime---"+(after-before));
						return reValue;*/
						
						advise.before(method);
						Object reValue = method.invoke(target, args);
						advise.after(method);
						return reValue;
					}
				}
				);
		return proxy3;
	}
}

Bean工厂BeanFactory负责创建配置文件中读取出的目标类的Bean , 如果读取到的是BeanFactoryProxy则调用BeanFactoryProxy的getProxy方法 , 返回目标类的代理

代码

#xxx=java.util.ArryList

xxx=cn.itcase.ProxyFactoryBean

xxx.target=java.util.ArryList

xxx.advice=cn.itcast.MyAdvice

package com.study.day3.aopframework;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;

public class AopFranmeworkTest {

	public static void main(String[] args) throws Exception {
		
		InputStream is = AopFranmeworkTest.class.getResourceAsStream("config.properties");
		Collection bean = (Collection) new BeanFactory(is).getBean("xxx");
		System.out.println(bean.getClass().getName());
		System.out.println(bean.getClass().getMethod("add", Object.class)
				.getName());
		bean.add("123");
		System.out.println(bean.size());
	}
}
package com.study.day3.aopframework;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import com.study.day3.Advise;
//BeanFactory类,用于返回Bean,如果配置文件中是读取的是BeanFactoryProxy,则调用BeanFactoryProxy返回代理
public class BeanFactory {
	Properties props = new Properties();
	BeanFactory(InputStream is) throws Exception{
		props.load(is);
	}
	public Object getBean(String name) throws Exception{
		String className = props.getProperty(name);
		Class clazz = Class.forName(className);
		Object bean = clazz.newInstance();
		if(bean instanceof BeanFactoryProxy){
			BeanFactoryProxy beanFactoryProxy = (BeanFactoryProxy)bean;
			Advise advise = (Advise)Class.forName(props.getProperty(name+".advise")).newInstance();
			Object target = Class.forName(props.getProperty(name+".target")).newInstance();
			//System.out.println(target.getClass().getName());
			beanFactoryProxy.setAdvise(advise);
			beanFactoryProxy.setTarget(target);
			return beanFactoryProxy.getProxy();
		}
		return bean;
	}
}
package com.study.day3.aopframework;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.study.day3.Advise;
import com.study.day3.MyAdvise;
//BeanFactoryProxy类,用于返回代理
public class BeanFactoryProxy {
	private Advise advise = null;
	private Object target = null;	
	public void setAdvise(Advise advise) {
		this.advise = advise;
	}
	public void setTarget(Object target) {
		this.target = target;
	}

	public Object getProxy() {
		Object proxy = Proxy.newProxyInstance(
				target.getClass().getClassLoader(),
				target.getClass().getInterfaces(),
				new InvocationHandler() {			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				Advise advise = new MyAdvise();
				advise.before(method);
				Object reValue = method.invoke(target, args);
				advise.after(method);
				return reValue;
			}
		});
		return proxy;
	}
}
package com.study.day3;

import java.lang.reflect.Method;

public interface Advise {
	void before(Method method);
	void after(Method method);
}
package com.study.day3;

import java.lang.reflect.Method;

public class MyAdvise implements Advise {
	long before = 0;
	public void before(Method method) {
		System.out.println("hello 黑马");
		before = System.currentTimeMillis();
	}

	public void after(Method method) {
		System.out.println("love 黑马");
		long after = System.currentTimeMillis();						
		System.out.println(method.getName()+"---runtime---"+(after-before));
	}

}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值