java基础加强
java ee Java Platform,Enterprise Edition
ide Integrated Development Environment
jms Java Message Service
jmx Java Management Extentions
JDK 1.5的新特性:
静态导入
多参数
加强for循环
自动拆装箱
享元模式 flyweight 如果很多很小的对象,它们有很多相同的东西,那就可以将它们定义成一个对象,把它们不同的东西封装成外部属性,作为方法的参数传入
枚举
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象
如果枚举只有一个成员,就可以当做为一种单例的实现方式
Class类
是描述java程序中各个java类的类,包括类的名字,访问属性,类所属的包名,字段名称的列表,方法名称的列表
Class类代表java类,它的各个实例对象分别对应各个类在内存中的字节码,一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同类的字节码是不同的,所以他们在内存中的内容是不同的,这一个个的空间分别用一个个的对象来表示,这些对象具有相同的类型就是Class
得到各个字节码对应的实例对象的三种方法
1.类名.class System.class
2.对象.getClass() newDate().getClass()
3.Class.forName("类名") Class.forName("java.util.Date");
String str1 = "abc";
Class cls1 = str1.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
System.out.println(cls1==cls2);
System.out.println(cls1==cls3);//结果都为true,因为代表相同的字节码
System.out.println(cls1.isPrimitive());//String类型不属于基本数据类型
System.out.println(int.class.isPrimitive());//int是基本数据类型
System.out.println(int.class == Integer.class);//int和Integer不属于同一个字节码
System.out.println(int.class == Integer.TYPE);//.TYPE方法可以获取Integer包装类的原始类
System.out.println(int[].class.isPrimitive());//是数组类型的字节码
System.out.println(int[].class.isArray());
总之,只要在程序中出现的类型,都有各自的Class实例对象
反射
反射就是把Java类中的各种成分映射成相应的java类
表示java类的Class类显然要提供一系列的方法,来或得其中的变量,
方法,构造函数,修饰符,包等信息,这些信息就是用相应类的实例
对象来表示,它们是Field,Method,Contructor,Package等
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过
调用Class类的方法可以得到这些实例对象
Constructor
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
//获取String这个Class类的构造方法,并且该构造方法的参数是StringBuffer
String str = (String)constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str.charAt(2));
Constructor类代表某个类中的一个构造方法
得到每个类的所有构造方法
Constructor[] constructors=Class.forName("java.lang.String").getConstructors()
得到某一个构造方法
Constructor constructor=Class.forName("java.lang.String").getConstructor(StringBuffer.class)
创建实例对象
通常的方法:String str=new String(new StringBuffer("abc"))
反射方法:String str=(String)constructor.newInstance(new StringBuffer("abc"))
调用获得的方法时,要用到上面相同类型的实例对象
Class.newInstance()
String obj=(String)Class.forName("java.lang.String").newInstance()
Field类
代表某个类中的一个成员变量
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y");
//FieldY代表的不是一个具体对象的值,而是代表类上的一个变量,要用它去取某个对象对应的值
System.out.println(fieldY.get(pt1));
Field fieldX = pt1.getClass().getDeclaredField("x");
//getField()只能获得可见的,对于私有的要用getDeclaredField()
fieldX.setAccessible(true);//暴力反射,强制设置为可访问
System.out.println(fieldX.get(pt1));
Method类代表某个类中的一个成员方法
得到类中的某一个方法:
Method charAt=Class.forName("java.lang.String").getMethod("charAt",int.class)
调用方法:
通常:System.out.println(str.charAt(1))
反射:System.out.println(charAt.invoke(str,1))
如果传递给Method对象的invoke()方法的一个参数是Null,说明Method对象对应的是一个静态方法
用发射方式执行某个类中的main方法
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);
mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
//也可以是mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
//系统会对数组进行拆包,把数组中各个成员分别作为参数,这时需要先对其进行封装,或强转为Object
数组的反射
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象
代表数组的Class实例对象个getSuperClass()方法返回的父类为Object类对应 的Class
基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用 ,非基本类型的一维数组,即可以当做Object类型使用,又可以当做 Object[]类型使用
ArrayList()方法处理int[]和String[]时的差异
ArrayList() 可以将String[]的元素列出来,但不能把int[]给列出来, 因为int[]被转化为Object类型时,被当做为一个数组类型的元素,被列 出来的是它的存储编码
反射的作用->实现框架的功能
框架和工具类的区别:工具类被用户的类调用,而框架则是调用用户提供的类
因为框架可能要调用后来写的类,所以无法预知要被调用的类名,所以程序中无法直接new某个类的实例对象,而要用反射来做
内省 JavaBean
JavaBean是一种特殊的java类,主要用户传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则
一个类被当做javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量
一个符合JavaBean特点的类可以当做普通类一样使用,但把它当做JavaBean用,它会有一些好处
在Java EE开发中,经常要用到JavaBean,很多环境就要求按JavaBean方式进行操作
JDK中提供了对JavaBean进行操作的一些API,这套API就成为内省。
注解
@SuppressWarnings
@Deprecated
@Override
注解相当于一种标记,加了注解就相当于打上了某种标记,没加,,则等于没有某种标记,以后,javac编译器、开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记就去干相应的事,标记可以加在包,类,字段,方法的参数以及局部变量
泛型
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序的非法输入,编译器编译带类型说明的集合时会去除掉“类型信息”,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样,由于编译生成的字节码会去掉泛型的类型信息,只要跳过编译器,就可以往某个集合中加入其他类型的数据
?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法
Java中的泛型类型类似于C++中模板,但这种相似性仅限于表面,Java语言中的泛型基本上完全是在编译器中实现,用于编译器执行类型检查和类型判断,然后生成普通的非泛型的字节码,这种实现技术成为擦除(erasure)(编译器使用泛型类型信息保证类型安全,然后在生成字节码之前将其清除),这是因为扩展虚拟机指令集来支持泛型被认为是无法接受的,这会为Java厂商升级其JVM造成难以逾越的障碍,所以java的泛型采用了完全可以在编译器中实现的擦除方法
只有引用类型才能作为泛型方法的实际参数
用于放置泛型的类型的参数的尖括号应出现在方法的其他所有修饰符之后和在方法的返回类型之前,也就是紧邻返回值之前,按照惯例,类型参数通常用单个大写字母表示
在引用泛型时可以使用extends限定符,在定义泛型时也可以使用extends
普通方法,构造方法和静态方法都可以使用泛型,编译器不允许创建类型变量数组
也可以用类型变量表示异常,称为参数化异常,可以用于方法的throws列表中,但是不能用于catch子句中
在泛型中可以同时有多个类型参数,在定义它们的尖括号中用逗号分开
如果类的实例对象中的多出都用到同一个泛型参数,即这些地方引用的泛型类型要保持一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型
类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的
注意:再对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型
当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型)而不能被静态变量
类加载器
Java虚拟机中可以安装多个类加载器,系统默认三个主要的类加载器,每个类加载器负责加载特定位置的类BootStrap,ExtClassLoader,AppClassLoader
类加载器也是Java类,因为其他是java类的类加载器本身也需要被类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap
Java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象或者默认采用系统类加载器为其父级类加载
当Java虚拟机要加载一个类时,要用哪个类加载器呢
首先当前线程的类加载器去加载线程中的第一个类
如果类A中应用了类B,Java虚拟机将使用加载来A的类加载器来加载类B
还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类
每个类加载器加载类时,又先委托给其上级类加载器
当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛出ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法
对类加载器的层次结构图和委托加载原理
代理的概念和作用
要为已存在的多个具有相同接口的目标类的各个方法增加一些系统共能,例如异常处理,日志等
采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序
动态代理技术
要为系统中的这种接口的类增加代理功能,那就需要太多的代理类,全部采用静态代理的方式,将是一件非常麻烦的事
JVM可以在运行期间动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类
JVM生成的动态类必须实现一个活多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以用CGLIB库
代理的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中
让JVM创建动态类及其实例对象,要给它提供的信息
生成的类中的方法的代码是怎样的,也得由我们提供,把我们的代码 写在一个约定好了的方法中,把对象传递给它,它调用的方法,性党 羽插入了我的代码,提供执行代码的对象就是那个 InvokationHandler对象,他是在创建动态类的实例对象的构造方法 时传递进去的,在上面的InvocationHandler对象的invoke方法中加一点代码,就可以看到这些代码被调用运行了