黑马程序员--java高新技术(二)

 ------- android培训java培训、期待与您交流! ----------
1.反射
反射就是把java类中的各种成分映射成相应的java类。
Java程序中的个各类就是一类事物,描述这类事物的java类名就是Class
得到一个类的字节码有两种情况:
	1.一个类的字节码已经加载到内存中来了,直接找到那份字节码返回
	2.没有加载,用类加载器进行加载,加载完后缓存起来
得到各个字节码对应的实例对象:
	1.类名.class,例如System.class
	2.对象.getClass(),例如,new Date().getClass();
	3.Class.forName(“类的完整名称”),例如,Class.forName(“java.util.Date”);
构造方法的反射应用:
	得到某个类所有的构造方法:
		Constructor[] constructor = Class.forName(“java.lang.String”).getConstructors();
	得到某一个构造方法:
		Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
		因为String类中的各个构造方法重载,要得到某一个构造方法就是通过参数类型来区分。
Class.newInstance()方法
	例子:String obj = (String)Class.forName(“java.lang.String”).newInstance();
	该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
成员变量的反射
	public class ReflectPoint {
		private int x;
		public int y;
		public String str1 = "ball";
		public String str2 = "basketball";
		public String str3 = "itcast";
		public ReflectPoint(int x, int y) {
			super();
			this.x = x;
			this.y = y;
		}
	}
			ReflectPoint pt1 = new ReflectPoint(3,5);
			Field fieldY = pt1.getClass().getField("y");
			//fieldY是类字节码身上的变量,没有对应到对象身上,因此fieldY的值不是5
			//取出fieldY在pt1身上的值
			System.out.println(fieldY.get(pt1));	//传递的参数表示在哪个对象身上
			
			//对于不可见的私有变量x,可以用getDeclared()来取
			Field fieldX = pt1.getClass().getDeclaredField("x");
			//虽然能够取到,但是不能使用
			fieldX.setAccessible(true);	//剥离反射
			System.out.println(fieldX.get(pt1));
			changeStringValue(pt1);
			System.out.println(pt1);
成员方法的反射
Method类代表某个类中的一个成员方法
例如,得到某个类中的一个方法
	Method charAt = Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
用反射执行某个类中的main方法
写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法
	class TestArguments{
		public static void main(String[] args){
			for(String arg:args){
				System.out.println(arg);
			}
		}
	}
在main方法中调用:
		String startClassName = args[0];
		Method mainMethod = Class.forName(startClassName).getMethod("main", String[].class);
		//java会将String[]封装的每个元素都拆成一个单独的参数,为了不让java这么干,将String类型的数组再用Object[]封装
		mainMethod.invoke(null, new Object[]{new String[]{"aaa","bbb","ccc"}});	
	另一种解决方案:
		mainMethod.invoke(null, (Object)new String[]{"aaa","bbb","ccc"});	
数组的反射
对于一个数组,我们往往有想得到数组的长度、第几个元素、把第几个元素换掉、打印数组元素等需求。
private static void printObject(Object obj) {
		Class clazz = obj.getClass();
		if(clazz.isArray()){
			int len = Array.getLength(obj);
			for (int i = 0;i<len;i++){
				System.out.println(Array.get(obj, i));
			}
		}else{
			System.out.println(obj);
		}
	}
2.用类加载器管理资源和配置文件
	import java.util.Properties;


	public class ReflectTest2 {
		public static void main(String[] args) throws Exception {
			//一定要用完整的路径,但完整的路径不是硬编码,是计算出来的
			//InputStream ips = new FileInputStream("Config.properties");
			//InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn\\itcast\\day1\\Config.properties");
			//该方法是用类加载器的getResourceAsStream()方法来寻找配置文件,参数为配置文件相对于工程文件下bin目录所经过的目录。
			InputStream ips = ReflectTest2.class.getResourceAsStream("Config.properties");	
			//用类的字节码的getResourceAsStream(),参数为配置文件相对于该类的路径
			Properties props = new Properties();
			props.load(ips);
			ips.close();
			String className = props.getProperty("className");
			Collection collection = (Collection)Class.forName(className).newInstance();
		
JavaBean
	javaBean是一种特殊的java类,该类里面的方法的名称符合某种特定的规则。
	主要用于把一个对象的信息传递到另一个模块中去,将这些信息封装到JavaBean中 


使用BeanUtils工具包操作JavaBean
		System.out.println(BeanUtils.getProperty(pt1, "x"));
		BeanUtils.setProperty(pt1, "x", "9");
		System.out.println(pt1.getX());
		
		//BeanUtils支持属性的级联操作
		BeanUtils.setProperty(pt1, "birthday.time", "111");
		PropertyUtils.setProperty(pt1, "x", 9);	//返回的是整数,BeanUtils是以字符串的形式进行操作
		//PropertyUtils是以数据本身的类型对数据进行操作


3.注解
	@SuppressWarnings
	@Deprecated
	@Override


@Retention():说明注解的生命周期


泛型
	泛型是提供给javac编译器使用的,可以限定集合中输入的类型,让编译器挡住程序中的非法输入,
	编译器编译带类型说明的集合信息时会去掉“类型”信息是程序运行不收影响,对于参数化的泛型类型,
	getClass()的返回值和原始类型一样。由于编译生成的字节码会去掉类型信息,只要能跳过编译器,
	就可以往集合中加入其他类型的数据。例如,用反射得到集合,再调用add()方法即可。
	//往集合中存入String类型的数据
	ArrayList<Integer> al = new ArrayList<Integer>();
	//al.add("abc");显然直接存入String类型的数据是不行的,用到反射
	al.getClass().getMethod("add", Object.class).invoke(al, "abcabc");
	System.out.println(al.get(0));
参数化的类型可以引用一个原始类型的对象,编译报告警告,例如
	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];//错误


4.深入讲解:
定义一个方法,打印任意参数化类型的集合中的方法
public static void printCollection(Collection<?> collection){
		for(Object obj:collection){
			System.out.println(obj);
			//collection.add("abc");错误,因为将来不一定匹配String
			System.out.println(collection.size());//没错,与类型参数没有关系
		}
	}
5.泛型综合应用案例
HashMap<String,Integer> maps = new HashMap<String, Integer>();
		maps.put("zxx", 28);
		maps.put("lhm", 38);
		
		Set<Map.Entry<String,Integer>> entrySet = maps.entrySet();
		for(Map.Entry<String,Integer> entry: entrySet){
			System.out.println(entry.getKey()+":"+entry.getValue());
泛型练习:
	1.编写一个泛型方法,自动将Object类型的对象转换成为其他类型
	public static <T>T convert(Object obj){
		return (T)obj;
	}
	
	//2.定义一个方法,可以将任意类型的数组中的所有元素填充为相应类型的某个对象。
	public static <T> void fill(T[] t,T obj){
		for (int i = 0;i<t.length;i++){
			t[i] = obj;
		}
	}
	
	//3.采用自定义泛型方法的方式打印出任意参数化类型的集合中的所有内容
	public static<T> void printCol(Collection<T> collection){
		for(Object obj:collection){
			System.out.println(obj);
			//collection.add("abc");错误,因为将来不一定匹配String
			System.out.println(collection.size());//没错,与类型参数没有关系
		}
	}
	//4.定义一个方法,把任意参数类型的集合中的数据安全的复制到相应类型的数组中。
	public static <T> void copyToArray(Collection<T> col,T[] t){
		for(int x=0;x<t.size();x++){
			col.add(t[x]);
		}
	}
取得一个方法的参数的泛型:
		Method methodApply = GenericTest.class.getMethod("apply", Collection.class);
		//获取参数的泛型
		Type[] types = methodApply.getGenericParameterTypes();
		ParameterizedType pType =(ParameterizedType) types[0];
		System.out.println(pType.getRawType()); 	//原始类型
		System.out.println(pType.getActualTypeArguments()[0]);  	//参数化的类型
	
6.类加载器及委托机制:
	Java虚拟机可以安装多个类加载器,系统默认3个主要类加载器,
	每个类加载器负责加载特定位置的类BootStrap、ExtClassLoader、AppClassLoader,
	其本身也是一个java类,因为其他是java类的类加载器本身也要被类加载器加载,
	显然必须有一个类加载器不是java类,这正是BootStrap。
	Java虚拟机加载一个类时,主要通过三种方式:
	首先,当前线程的类加载器去加载第一个类
	如果类A使用了类B,java虚拟机将使用加载类A的类加载器加载类B
	还可以使用ClassLoader.loadClass()指定某个类加载器去加载某个类。
	每个类加载器加载类时,又先委托其上级类加载器。


7.代理:
	AOP:(Aspect oriented program )面向方面的编程
	JVM可以在运行时动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
	JVM生成的代理类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
	如果目标类没有实现接口,要想生成代理类,用CGLIB库。
public static void main(String[] args) {
System.out.println("begin constructors");
		Method[] methods = clazzProxy.getMethods();
		for(Method method:methods){
			String name = method.getName();
			StringBuilder sb = new StringBuilder(name);
			sb.append('(');
			Class[] clazzParams = method.getParameterTypes();
			for(Class clazzParam:clazzParams){
				sb.append(clazzParam.getName()).append(',');
			}
			if(clazzParams!=null && clazzParams.length!=0){
				sb.deleteCharAt(sb.length()-1);
			}
			
			sb.append(')');
			
			System.out.println(sb.toString());
		}
	}
创建动态类及其实例对象,注意三个方面:
	1.生成的类中有哪些方法,通过让其实现哪些接口的方式进行告知
	2.产生的类字节码必须有一个关联的类加载器对象
	3.生成的类中的方法的代码是怎样的,也得由我们提供。
	把我们的代码写在一个约定好了接口对象的方法中,把对象传递给它,
	它调用我们的方法,相当于插入了我们的代码。
	提供执行代码的对象就是InvocationHandler对象,
	它是在创建动态类的实例对象的构造方法时传递进去的。
	在InvocationHandler对象的invoke方法中加一点代码,就可以看到这些代码被调用运行了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值