您的位置:首页 > 编程语言 > Java开发

java基础加强学习笔记

2011-02-27 21:28 387 查看
学习了Eclipse的一些使用,
静态导入,
可变参数方法,(int i, int... args){}(可变参数必须是最后一个参数,以数组的形式来访问可变参数)
for循环加强形式(foreach),
基本数据类型的自动装箱和拆箱,如果数值在一个字节之内(-128~127之间的数值),那么这个数值会缓存起来,如果下一次同样的数据需要装箱,那么就直接拿这一份数据来用。
比如:Integer i = 23; Integer j = 23; 那么 i==j;如果Integer i = 128; Integer j = 128; 那么 i!=j; (享元模式:很多小的对象,有很多相同的属性的时候,可以考虑使用享元模式。不同的属性就设为方法的参数传进来,叫外部属性或外部状态。)
枚举类的学习,枚举里面的每一个元素都是一个类的实际对象。如:
public enum WeekDate {
 SUN(1),MON,TUE;  //没指定参数列表的时候调用无参数的构造方法,指定了参数就调用对应的构造方法。
 private WeekDate(){} //构造方法必须是私有的。
 private WeekDate(int day){}
}
实现带有抽象方法的枚举
枚举只有一个成员时,就可以作为一种单例的实现方式。

Class类的使用。
得到字节码(Class类)的方式有三种:
类名.class;
对象名.getClass();
Class.forName("类名");

有9个预定义的Class实例对象(8个基本数据类型和void)。
int.class = Integer.TYPE;

int.class.isPrimitive();-----true    //判断class类是否为基本数据类型。
int[].class.isArray();-----true   //判断Class类是否为数组类。

理解了反射的概念,构造方法的反射应用,成员变量的反射,成员方法的反射(静态方法的反射调用时,对象的值可以是null,如:methodTest.invoke(null, "hello")),
对接收数组参数的成员方法进行反射的2种解决方案:new Object(arrays[]),(object)arrays[]。
数组类型:如果有相同的维数和相同的类型,他们就同一份字节码,即同一个Class类。
Array工具类用于完成对数组的反射操作,如:Array.getLength(obj); Array.get(obj, index);
温习了ArrayList与HashSet的比较,学习了Hashcode的分析,按照Hash算法存储的内存分配是按区域来算的,效率高。equals与hashcode方法的适当使用。

**有一个问题得注意:当一个对象被存储进HashSet集合之后,就不能修改这个对象中那些参与计算哈希值的字段,否则,对象修改后的哈希值与最初存储进HashSet时的哈希值就不同了,
在这种情况下,即使在contains方法使用该对象的当前引用作为参数去HashSet集合中检索对象,也将找不到对象,这将导致无法从HashSet集合中单独删除当前对象,从而造成内存泄漏。 

通过简单的案例温习了反射技术开发框架的原理(扩展:流类之所以需要使用后调用close()关闭流,释放系统资源。这个java本身的垃圾回收机制是两回事,java垃圾回收机制是回收java本身的垃圾对象内存,而调用
close()是释放对象关联的系统资源。)

用类加载器加载资源文件this.class.getClassLoader().getResourceAsStream(path)/this.class.getResourceAsStream(path);

javaBean的简单介绍。JDK提供了对JavaBean进行操作的一些API,这套API称为内省。

对JavaBean的简单内省操作:java.beans.PropertyDescriptor属性描述符类。new PropertyDescriptor(propertyName, class);
对JavaBean的复杂内省操作:java.beans.Introspector.getBeanInfo(class);这种方法复杂一些。

使用BeanUtils工具包操作JavaBean,需下载和导入beanutils和logging包。使用BeanUtils操作JavaBeam方便快捷。
BeanUtils的setProperty()和getProperty()方法支持属性的级联。如:BeanUtils.setProperty(pt1, "birthday.time", "111");因为示例类中的birthday属性是属于Date类型,而Date类有一个方法为setTime(),所以级联属性为birthday.time可以设置其中的值。BeanUtils类还可以操作Map类(key-value)。
另外还有一个类PropertyUtils的功能和BeanUtils功能差不多,但是BeanUtils是以字符串的形式对值进行操作,但是PropertyUtils是以属性本身的类型进行操作。

了解了注解和入门注解的应用。注解的定义与反射调用。Class类中的isAnnotationPresent(),getAnnotation()的用法。Retention元注解描述注解的生命周期,Target元注解描述注解的所适用的程序元素的种类,如:TYPE,METHOD,FIELD等。
(扩展:class文件并不是一份字节码,当类加载到内存以后的二进制码才叫字节码。)
一个注解的生命周期有三个阶段:RetentionPolicy.CLASS(class文件阶段), RetentionPolicy,RUNTIME(内存中的字节码阶段), RetentionPolicy.SOURCE(源文件阶段),RetentionPolicy是枚举类。
学习了为注解增加属性,定义的时候是方法的形式(String color();),赋值的时候是属性的形式(color="red"),读取的时候还是用方法的形式调用(.color())。
如果只有一个属性需要指定,并且这个属性名字是value,那么赋值的时候可以省略“属性名=”,直接("属性值")即可。
定义属性的时候可以指定缺省的默认值,如:String color() default "blue";

学习了为注解增加各种属性。如数组,枚举,甚至是注解。

使用泛型,首先的一个好处是避免强制类型转换。

泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样,由于编译生成的字节码会去掉泛型的类型信息,所以只要能跳过编译器,就可以往某个泛型集合中加入其他类型的数据。例如:用反射得到集合,再调用其add()方法即可。如:collection1.getClass().getMethod("add", Object.class).invoke(collection1, "haha");

注意:以下语句合法:Collection<String> c = new Vector();      Collection c = new Vector<String>();

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

泛型的通配符是“?”,使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
泛型通配符的扩展:Vector<? extends Number> v = new Vector<Integer>();    Vector<? super Integer> v = new Vector<Number>();

通过泛型集合的综合案例学习了Map.Entry的使用。Map中有一个方法entrySet()将返回一个Set集合,里面放置了Map.Entry,里面是key-value对,Map.Entry中的常用方法getKey(),getValue();

自定义泛型方法及应用。如:
private static <T> T add(T x, T y) {
 return null;
}

如果是泛型的加法,将返回的值是各个加数的类型的交集的类型,如:add(2, "hello")将返回Object对象,Obj
4000
ect result = add(2, "hello");

下面是实现数组中两个元素值的交换:

private static <T> void swap(T[] a, int i, int j) {
 T tmp = a[i];
 a[i] = a[j];
 a[j] = tmp;
}

注意:只有引用类型才能作为泛型方法的实际参数,如swap(new String[]{"a", "b", c}, 0, 1);是没问题的,但是:swap(new int[]{1, 2, 3}, 0, 1);是不能通过编译的。
除了在应用泛型是可以使用extends限定符,在定义泛型时也可以使用extends限定符,例如:Class.getAnnotation()方法的定义,并且可以使用&符号来指定多个边界,如
<V extends Serializable & cloneable> void method() {}。

我们也可以用类型变量表示异常,称为参数化异常,可以用于方法的throws 列表中,但是不能用于catch()字句中。

在泛型中,可以同时有多个类型参数,在定义他们的尖括号中用“,”分隔,例如:public static <K, V> V getValue(K key) {return map.get(key);}

下面方法可以将Object的类型转换为任何类型:     //此方法很有趣,可以根据他的返回值类型自动转换。
public static <T> T autoConvert(Object obj) {
 return (T)obj;
}

如:Object o = "aaa";
String str = autoConvert(o);       //因为此语句返回值类型是String,所以可以根据他的返回值类型自动转换return (T)obj;这个(T)就是将obj强制转换成跟返回值一样的类型。

学习了自定义泛型类的应用。

类里面的静态成员不能使用泛型类型的变量。

学习了通过反射获得泛型的实际类型参数。主要代码如下:(GenericTest类是自定义的示例类)

Method applyMethod = GenericTest.class.getMethod("applyVector", Vector.class);
Type[] types = applyMethod.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType)types[0];
System.out.println(pType.getRawType());
System.out.println(pType.getActualTypeArguments()[0]);

public static void applyVector(Vector<Date> v1){}

其中原理:不能通过集合对象本身获取,只能通过反射的方法进行取得。

类加载器之间的父子关系:BootStrap(爷)------ExtClassLoader(父)-----AppClassLoader(子)
注意:BootStrap不是一个java类,是直接在虚拟机里面的一个加载器。其他两个加载器都是java类。

BootStrap加载JRE/lib/rt.jar里面的类
ExtClassLoader加载JRE/lib/ext/*.jar里面的类
AppClassLoader加载classpath指定的所有jar或目录里面的类
我们还可以写自己的类加载器去加载指定的特殊的目录
(自定义的类加载器必须继承ClassLoader,loadClass()方法和findClass()方法,difineClass()方法)

类加载器的委托机制:从子类开始委托,一直到爷爷祖先类,也就是说先让BootStrap加载,找不到的话再让ExtClassLoader加载,再找不到的话就让AppClassLoader加载,再找不到的话
就让自定义类加载器加载。。。

(扩展:模版方法设计模式:父类loadClass/findClass-----子类1,子类2,子类3。。。)

(有包名的类不能调用无包名的类!)

学习了自己编写的解密类加载器。

学习了类加载器的一个高级问题的实验分析。(如果A类用到了B类,那么B类由加载A类的加载器去加载。)

学习了代理类的作用与原理和AOP概念(面向方面编程:目标就是要使交叉业务模块化)。
只要是面向方面的编程就涉及到代理。

JVM(Java虚拟机)可以在运行期动态生成出类的字节码,这种动态生成的类往往被用过代理类,即动态代理类。
JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
如果目标类没有实现接口,要想生成他的代理,那么就用CGLIB库(第三方类库,不是JAVA标准),CGLIB可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果
要为一个没有实现接口的类生成动态代理类,那么就用CGLIB库。

(扩展:StringBuilder与StringBuffer的区别:他们都是可变的字符序列,
不同的是在单线程编程里面用StringBuilder效率要高一些,因为StringBuilder不用考虑线程安全,而多线程里面要考虑线程安全的话就使用StringBuffer);

Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);  //动态代理类的生成示例。

学习了创建动态类的实例对象及调用其方法。

完成InvocationHandler对象的内部功能,主要就是要重写
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {}这个方法。
学习了InvocationHandler对象的运行原理
让动态生成的类成为目标类的代理。
学习了动态代理类的设计原理与结构

学习了编写可生成代理和插入通告的通用方法(主要是传一个目标和编写实现系统功能的对象进去。)

学习了实现类似spring的可配置的AOP框架

(扩展:JavaBean必须要有一个不带参数的构造方法。)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息