黑马程序员_高新技术

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

 一、java1.5的新特性

1、静态导入

      import语句可以导入一个类或者某个包中的所有类,同时import static可以导入一个类中的某个静态方法或者所有静态方法。

这样做的好处是,在代码中调用静态方法时不用再加类名点了。

静态导入的格式:import static java.util.类名.*;

2、可变参数

(1)当一个方法接受的参数个数不固定,可以使用可变参数来解决

      可变参数的特点:只能出现在参数列表的最后; ...位于变量类型和变量名之间,前后有无空格都可; 调用可变参数时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数
(2)格式:public int add(int i,int j,... args)
(3)overload和override的区别:
          overload:是重载,表示一个类中可以有多个同名的方法,但是它们的参数个数或类型不同。
          重载时要注意:重载只能通过不相同的参数,而不同通过访问权限,返回值类型进行重载;
          override:是重写或是覆盖,表示子类中的方法和其父类的方法名和参数完全相同,只是方法体不同。
         覆盖是要注意:被覆盖的方法不能是private,否则其子类中只是新定义了一个方法;如果被覆盖的方法有异常抛出,那么覆盖的必须和被覆盖的异常相同,或是其异常的子类,绝对不能出现新异常。
3、枚举:枚举一般是用来表示一组相同类型的常量。
(1)枚举是一个特殊的类,其中每个元素都是该类的一个实例对象,其中可以定义构造方法,成员变量,普通方法和抽象方法。
(2)枚举元素必须位于枚举体中最开始的部分,枚举元素列表后面要有分号与其他成员分隔。把枚举中的成员方法和变量放在枚举元素的前面,编译器报告错误。
(3)带构造方法的枚举:构造方法必须定义成私有的。
(4)当枚举只有一个成员时,就可以作为一种单利的实现方式。
 
二、反射

1、Class类

(1) java中的各个类属于同一种事物,为了方便管理这些类就用Class类来描述这类事物。

(2) 获取Class的对象的方法(其实就是获取相应类的字节码文件对象)

<1>通过每个对象都具备的方法getClass来获取。

例如:Person p=new Person();

Classcla1=p.getClass();

这种方法的用法:在拿到对象后(不知道对象的具体类型)可以用对象的getClass()方法来获取对象的类型。这种方法的不好之处就在于必须建立具体的对象。

        <2> 每一个数据类型(基本数据类型和引用数据类型)都有一个静态属性:class

例如:Class cla2=Person.class;

这种方法的用法:如果是明确地获得某个类的Class对象,主要用于传参。这种方法的不好处就是必须先明确类

前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成。

        <3>  使用的Class类中的方法,forName

例如:class cla3=forName(“java.lang.String”);

这种做法的好处:指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。

2、 反射   

(1)定义:反射就是把类中的各个成员映射成相应的java类。

注:java类本身可以用Class类的对象来表示;类中的成员变量,方法,构造方法也可以映射出自己的类。

(2) Method类(方法)

<1> 获取类中的所有方法:getMethods()和getDeclaredMethods()获取私有方法

Class cl1=Class.forName("java.lang.String");

Method[] methods = cl1.getMethods();//获取的是该类中的公有方法和父类中的公有方法。

methods = cl1.getDeclaredMethods();//获取的是该类中的所有方法,包括私有方法。

<2>获取指定方法:getMethod(方法名,类型)

Class cl1=Class.forName("java.lang.String");

Method methods= cl1.getMethod("charAt",int.class);//获取指定的方法

method.invoke(obj(实例对象),方法参数);运行方法

<3>运行私有方法:getDeclaredMethod(方法名,类型) 

Class cl1=Class.forName("java.lang.String");

Method method = cl1.getDeclaredMethod("charAt",int.class);//获取指定的方法

method.setAccessible(true);//一般很少用,因为私有就是隐藏起来,所以尽量不要访问

method.invoke(obj(实例对象),方法参数);运行方法

 

(3) Constructor类(构造方法)

<1>  获取一个类中所有构造方法:getConstructors()它的返回类型是一个Constructor类型的数组。

例如:Constructor[]cons=Class.forName(java.lang.String).getConstructors();

<2>  获取某一个构造方法:getConstructor()它的返回类型是一个Constructor类。

例如:Constructor con=Class.forName(java.lang.String).getConstructors(想获取的构造方法的参数);

<3>  调用获得的构造方法:newInstance()

String str=(String)con.newInstance(new StringBuffer(“abc”));

注:这里强转是因为编译时期只看变量名,不知变量的具体内容。

通常的方法:String str=newString(new StringBuffer(“abc”));

 

(4)Field类(成员变量)

<1> 公有成员变量访问

Field field = str.getField(fieldName);//获取指定类的的指定变量

file.get(有访问的对象)//返回类型是具体的变量类型。

<2> 私有成员的访问

Field fy=r.getClass().getDeclaredField("y");

            fy.setAccessible(true);//让私有可以被访问

            System.out.println(fy.get(r));

总结:反射的作用是用来实现框架的功能的.   框架就是在类出现之前就已经把类给用了,由于不知道用到什么类,所以就要用反射来解决这个问题.

三 内省(introspector)------(javabean)

         javaBean是一种 特殊的类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。说白了:javabean就是这样一种类:类里面有一些私有的属性,要访问这些属性就必须提供一些set和get方法(这就是javabean的特殊之处).

        内省是为了解决访问这些私有属性(反射)困难而出现的,

        内省访问javabean的属性有两种方式:

        (1).通过PropertyDescriptor类来操作javabean的属性

例子:

PropertyDescriptor dp=new PropertyDescriptor(propertyName,pt1.getClass());//建立属性描述对象,
                                                                                       // 并和属性以及它所在的类相关联
Method methodGetX=dp.getReadMethod();//通过属性描述类的方法获取getX这个方法
Object reVal=methodGetX.invoke(pt1);//获取具体对象的属性值

         (2)通过Introspector类获得Bean对象的 BeanInfo,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后通过反射机制来调用这些方法。
例子:

BeanInfo beanInfo=Introspector.getBeanInfo(pt1.getClass());//通过内省类的静态方法来获取具体class文件的Bean的信息
PropertyDescriptor[]pds=beanInfo.getPropertyDescriptors();//获取所有属性
//遍历属性,获取需要的属性
for(PropertyDescriptor pd:pds)
{
	if(pd.getName().equals(propertyName))
	{
		Method methodGetX=pd.getReadMethod();
		Object reVal=methodGetX.invoke(pt1);
		break;
	}
}

        由于内省的类过于繁琐,所以便出了BeanUtils包(和Arrays类似).

四.注解

注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,标记可以加载包,类,字段,方法,方法的参数以及局部变量上。
       定义一个简单的注解类
       public @interface MyAnnotation{};
       将次注解类加载到已有类上
       @MyAnnotation(里面可以加注解的参数)
       public class MyClass{}
 
五.类加载器(加载类的工具)
 
         类的加载过程:  JVM把字节码文件从硬盘上加载(加载器的工作)进来,并进行一定处理,然后就成了内存字节码.这里的加载器由类ClassLoader来执行
 
1.系统默认的3个类加载器(Bootstrap,ExtClassLoader,AppClassLoader)
 
(1)BootStrap:  不是java类,不需要被背的类加载,它是由C++编写的,它的作用是:加载其他的系统默认的类加载器ExtClassLoader和AppClassLoader类加载器.  它的作用范围是Java核心类库在文件系统中的位置(被打包到Java的jdk安装目录的子目录jre/lib/rt.jar ) 
 
(2)ExtClassLoader:  BootStrap类的直接子类 它的作用范围是负责加载打包到Java的jdk安装目录的子目录jre/ext/下面所有的jar包.
 
(3)AppClassLoader:  ExtClassLoader类的直接子类   它的作用范围是负责加载系统环境变量classpath指定的目录的所有jar包.

(4)测试这三个类的继承关系

public class Test {  
    public static void main(String[] args) {  
       ClassLoader classLoader =Test.class.getClassLoader();  
        
       while(classLoader !=null){  
           System.out.println(classLoader.getClass().getName());  
           classLoader=classLoader.getParent();  
       }  
       System.out.println(classLoader);  
    }  
}

打印结果是 :AppClassLoader       ExtClassLoader           null

分析:Test.class  存在于classpath指定的目录下,所以一开始classLoader是AppClassLoader(java类) ,循环条件为真,打印出了 AppClassLoader,由它们的继承关系可知AppClassLoader的父类是ExtClassLoader(java类),循环条件为真,打印出ExtClassLoader

  由它们的继承关系可知ExtClassLoader的父类是BootStrap(非java类),循环条件为假,跳出循环将null打印出来.

 

2.类加载器的委托机制

   委托机制的描述:当需要某个类加载器要加载指定的类的时候,并不是立刻到自己的管辖范围去加载指定的字节码文件,而是将这个指定的类传递给父类,由父类尝试去到自己的加载范围去加载这个类。就这样,一级级地向上递推到类加载器的最高父类:Bootstrap类加载器

  加载过程:由某个子类加载器层层向上推进到Bootstrap类加载器加载。若最高父类类加载器无法加载指定的类,又开始层层向下递推到子类加载器进行加载。如果退回到发起者的类加载器还是没有办法加载指定的类,就抛出ClassNotFoundException这个异常。

 

3.自定义类加载器

 (1)自定义类加载器的方式

1) 继承ClassLoader并覆盖父类中loadClass()方法;

2)继承ClassLoader 并覆盖父类中findClass()方法.

两种法能法比较:第一种就必须自己冲新编写委托机制(找父类),过于麻烦(不提倡这种做法)

第二种方法    可以把自己定义类加载器的逻辑写到findClass()中,(loadClass()方法可以调用findClass()).在loadClass()方法的逻辑中如果父类加载失败,就会调用到自定义的findClass方法中的内容。

(2)自定义类加载器的演示:

public class MyClassLoader extendsClassLoader
{  
	//覆盖findClass()方法在里面定义自己的加载方式.
	protected Class<?> findClass(Stringname) throws ClassNotFoundException
	{	
		try
		{  
           		FileInputStreamfis =new FileInputStream(new File(name +".class"));  
           		byte[] classBytes =new byte[1024];  
           		int length =fis.read(classBytes, 0, classBytes.length);  
           		return defineClass(classBytes, 0,length);//将读到的内容转化成Class类的实例.
       		}
		catch (FileNotFoundException e)
		{  
           		e.printStackTrace();  
       		}
		catch (IOException e) 
		{  
           		e.printStackTrace();  
       		}  
       return null;//保证编译可以通过. 
	}   
}  


 

六. 代理
1.定义: 对于已经开发好的类,想要为它加上一些附加功能(异常处理,日志的功能),原程序是不能改变的,这时我们可以用代理类来实现这些功能的添加.
 
2.代理类和目标类(上面提到的已经开发好的类)
(1)二者的关系是:代理类是在目标类的基础上添加了使用者所需要的功能
(2)客户断不能直接使用目标类,而是使用代理类
(3)为了保证目标类和代理类的功能相同.二者必须实现相同的端口.
 
3.面向方面的编程(AOP)
(1)交叉业务: 在不同的模块中具有共同的业务.  例如:学生,课程,管理这三种业务,他们都有共同的内容(涉及到日志管理等内容).
(2)对解决交叉业务编程的问题就是面向方面的编程
(3)AOP和代理的关系:   其实交叉业务也是代理的一种.

 

4.动态代理类的分类(依据:目标类是否实现了特定的接口)

(1)通过JVM生成动态代理类(目标类必须实现某些接口)

(2)通过第三方类库CGLIB生成动态代理库(不需要目标类实现相应的接口)

 

5.系统代码出现在目标类的位置

(1)在调用目标方法前

(2)在调用目标方法之后

(3)在目标方法前后

(4)在处理目标方法异常的catch块中.

 

6 .JVM动态生成类练习

(1)获取动态类的构造方法

package cn.itcast.day3;

import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.Collection;

public class ProxyTest {


	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//获取动态生成类的字节码文件getProxyClass(loader,interface);
		Class clazzProxy=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
		//获取生成类的所有构造方法
		printConstructors(clazzProxy);
		
	}
	//获取生成类的所有构造方法
	public static void printConstructors(Class clazzProxy){
		Constructor[] cons=clazzProxy.getConstructors();
		for(Constructor con:cons)
		{
			String name=con.getName();
			//将name存到一个容器中
			StringBuilder sb=new StringBuilder(name);
			sb.append("(");
			//获取构造函数的参数
			Class[] clazzParams=con.getParameterTypes();
			for(int i=0;i<clazzParams.length;i++)
			{
				//将第一个参数添加到容器中
				sb.append(clazzParams[i].getName());
				if(i!=clazzParams.length-1)
					sb.append(",");	
			}
			sb.append(")");
			//将容器中的内容打印出去
			System.out.println(sb.toString());
		}
	}	
}

打印结果:

$Proxy0(java.lang.reflect.InvocationHandler)

通过分析结果可知:动态生成的代理类只有一个构造方法并且含有参数构造方法的名字是$Proxy0,参数是一个接口.

 (2)创建动态类的实例对象

 newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler handler)//中间的参数只能用数组,不能用可变参数

Collection con1=(Collection)Proxy.newProxyInstance(
	Collection.class.getClassLoader(),
	new Class[]{Collection.class},
	new InvocationHandler() {
		private ArrayList al=new ArrayList();
		public Object invoke(Object proxy,Method method,Object[] args)throws Throwable
		{
			return method.invoke(al,args);
		}
	});

(3)动态代理类的运行原理(借用别人的图)


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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值