26.ArrayList_HashSet的比较及Hashcode分析
HashSet就是采用哈希算法存储对象的集合,它内部采用对某个数字进行取余的方式对哈希码进行分组和划分对象的存储区域。object类中定义了一个hashCode()方法来返回每个对象的哈希码,当从HashSet集合中查找某个对象时,java系统首先调用对象的hashCode()方法获取该对象的哈希码,然后根据哈希码找到相应存储区域,最后取出该区域的每个元素与该对象进行equals方法比较,这样就不用遍历整个集合就可以得到结论。
当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中的哈希值就不同了,这样就无法找到该对象,这也导致无法从HashSet中单独删除当前对象,从而造成内存泄漏。
27.框架的概念及用反射技术开发框架的原理
框架调用用户提供的类,用户调用工具类;在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象了,而是用反射方式来做。
28.用类加载器的方式管理资源和配置文件
不要用相对路径放置配置文件,一定要记住用完整的路径,但不是硬编码,而是运算出来。 让用户去选择放置,然后去获取这个路径
getRealPath();//项目目录/内部
配置文件的加载往往是用类加载器去加载的
只读方法:
(1)InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream
("cn/itcast/day1/config.properties");//类加载器的方式
(2)InputStream ips = ReflectTest2.class.getResourceAsStream
("resources/config.properties");//隐含了类加载器,resources与day1在同个目录下
(3) InputStream ips = ReflectTest2.class.getResourceAsStream
("/cn/itcast/day1/resources/config.properties");//跳回根目录再去找
29.由内省引出JavaBean的讲解
内省主要用于JavaBean的操作
introSpector->JavaBean->特殊的java类,其方法符合某种特殊规则
JavaBean是一种特殊的java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象称之为值对象(Value Object,简称VO)。目的只是传递值,动作方法就没了,这些信息在类中用私有字段存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,JavaBean的属性是根据setter和getter方法来确定的。如方法名为getId,中文意思即为获取id,至于你从哪个变量取,不要管。去掉前缀剩余的就是属性名,
如果第二个字母为少写,则把首字母改成小的。
30.对JavaBean的简单内省操作
一个符合JavaBean特点的类可以当作普通类来处理,也可以当作JavaBean来操作。
jdk中提供了对JavaBean进行操作的一些API,这套API就称为内省。
31.对JavaBean的复杂内省操作
get:
PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodGetX = pd.getReadMethod();
Object retVal = methodGetX.invoke(pt1);
set:
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodSetX = pd2.getWriteMethod();
methodSetX.invoke(pt1,value);
复杂的get:
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object retVal = null;
for(PropertyDescriptor pd : pds){
if(pd.getName().equals(propertyName))
{
Method methodGetX = pd.getReadMethod();
retVal = methodGetX.invoke(pt1);
break;
}
}
return retVal;
32.使用BeanUtils工具包操作JavaBean
添加BeanUtils jar包操作:在工程目录下创建lib文件夹并把jar包复制到这里来,选择jar包右键选择Build Path->Add to Build Path
同时还要用到日记开发包logging,也增加到Build Path
BeanUtils工具包应用举例:
BeanUtils.getProperty(pt1, "x");
BeanUtils.setProperty(pt1, "x", "9");//已经转换成字符串,不用我们去改,在web开发经常用到。
BeanUtils.setProperty(pt1, "birthday.time", "111");//birthday为Date类型,Date().setTime()的属性就是time,所以BeanUtils可以获取更深的属性
System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));
PropertyUtils.setProperty(pt1, "x", 9);//不进行类型转换,x还是integer,与BeanUtils形成对比
//java7的新特性
Map map = {name:"zxx",age:18};
BeanUtils.setProperty(map, "name", "lhm");
================第6单元:java5的注解===================
33.了解和入门注解的应用
注解就是用于告诉开发工具或者是编译器,向它传递某种信息。
一个注解就是一个类。
注解相当于一种标记,在程序中加了注解就等于为程序打了某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,去干相应的事。标记可以加在包,类,字段,方法的参数已经局部变量上。
jdk自带的三个注解:@SuppressWarnings(去除警告) @Deprecated(添加警告) @Override(提示覆盖)
34.注解的定义与反射调用
注解的应用结构:
@interface A{}(注解类)->@A Class B(应用了注解类的类)
->Class C{B.class.isAnnotionPresent(A.class);
A a=B.class.getAnnotion)(A.class)}(对应用注解类的类进行
反射操作的类)
默认时编译器在编译时会去掉注释,所以我们要在注释类中再添加注释让编译器知道这个注释类要保留到运行时
引出@Retention元注释的讲解,有三种取值:
RetetionPolicy.SOURCRE、RetetionPolicy.CLASS、RetetionPolicy.RUNTIMR;分别对应:java源文件->class文件->内存中的字节码。自定义注释默认值是保留到class阶段
@SuppressWarnings(SOURCRE阶段) @Deprecated(RUNTIMR阶段)
@Override(SOURCRE阶段)
设置注释可以保留到哪个阶段:@Retention(RetentionPolicy.RUNTIME)
设置注释能够加到什么类型身上:@Target({ElementType.METHOD,ElementType.TYPE})
TYPE是class、enum等的更高层次即父类
35.为注解增加各种属性
public @interface ItcastAnnotation {
String color() default "blue";
String value();//
int[] arrayAttr() default {3,4,4};//数组类型属性
EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED;//枚举属性
MetaAnnotation annotationAttr() default @MetaAnnotation("lhm");//注释类型属性
}
应用:
@ItcastAnnotation(annotationAttr=@MetaAnnotation("flx"),color="red",value="abc",arrayAttr=1)
class AnnotationTest{}
调用:
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
ItcastAnnotation annotation =
(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.color());
System.out.println(annotation.value());
System.out.println(annotation.arrayAttr().length);
System.out.println(annotation.lamp().nextLamp().name());
System.out.println(annotation.annotationAttr().value());
}
================第7单元:java5的泛型===================
36.入门泛型的基本应用
泛型应用 ArrayList后加<String>说明这个是String类型的
ArrayList<String> collection2=new ArrayList<String>();
collection2.add("abc");
STring element=collection2.get(1); //不用类型转换了
总结:没用泛型时,不管什么类型的对象都可以存储进同个集合,使用泛型集合可以将集合的元素限定为特殊类型,这样更安全,同时获取它时不需要对对象进行强制类型转换
37.泛型的内部原理及更深应用
泛型编译后类型信息会被去掉(去类型化)
应用:可以用反射透过编译器在其中加入其他类型数据
如:collection3.getClass().getMethod("add",Object.class).invoke(collection3,"abc");
system.out.println(collection3.get(0));
泛型术语
如ArrayList<E>的E称为类型变量或类型参数
而ArrayList<Integer>的integer称为类型参数的实例。<>念typeof
ArrayList称为原始类型
参数化类型与原始类型的兼容性
//可不可以还不是编译器的一句话的事
参数化类型不考虑类型参数的继承关系
38.泛型的通配符扩展应用
<? > 使用?通配符可以引用其他各种参数化类型,?通配符主要是作为引用,可以调用参数无关的方法,不能调用参数化有关的方法
collection.size()
<? extends >?通配符的扩展
extends 限定通配符的上边界
super 限定通配符的下边界
39.泛型集合的综合应用案例
Map->Set,然后进行迭代
HashMap<String,Integer> maps = new HashMap<String, Integer>();
maps.put("zxx", 28);
maps.put("lhm", 35);
maps.put("flx", 33);
Set<Map.Entry<String,Integer>> entrySet = maps.entrySet();
for(Map.Entry<String, Integer> entry : entrySet){
System.out.println(entry.getKey() + ":" + entry.getValue());
}
40.自定义泛型方法及其应用
类型推断,返回xy的交集:
private static<T> T add(T x,T y)
add(3,5);
Number x1 = add(3.5,3);
Object x2 = add(3,"abc");
引用不能是基本数据类型:
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[]{"abc","xyz","itcast"},1,2);
//swap(new int[]{1,3,5,4,5},3,4);T的引用不能是基本数据类型(int)
41.自定义泛型方法的练习与类型推断总结
实现自动将Object类型的对象转换成其他类型:
private static <T> T autoConvert(Object obj){
return (T)obj;
}
Object obj = "abc";
String x3 = autoConvert(obj);
定义一个方法,可以将任意类型的数组中的所有元素填充为相应类型的某个对象:
private static <T> void fillArray(T[] a,T obj){
for(int i=0;i<a.length;i++){
a[i] = obj;
}
}
采用自定义泛型方法的方式打印出任意参数化类型的集合中的所有内容:
public static void printCollection(Collection<?> collection){
System.out.println(collection.size());
for(Object obj : collection){
System.out.println(obj);
}
}
public static <T> void printCollection2(Collection<T> collection){
System.out.println(collection.size());
for(Object obj : collection){
System.out.println(obj);
}
}
定义一个方法,把任意参数类型的集合中的数据安全的复制到相应类型的数组中:
public static <T> void copy1(Collection<T> dest,T[] src){
}
public static <T> void copy2(T[] dest,T[] src){
}
copy1(new Vector<String>(),new String[10]);
copy2(new Date[10],new String[10]);//取交集即Object
//copy1(new Vector<Date>(),new String[10]);出错,泛型具有传播性,既然<Date>已经确定,<T>也就确定为<Date>了。
泛型方法的定义:只要在返回值之前用<T>来说明类型即可
42.自定义泛型类的应用
在类身上定义泛型
public class GenericDao<E> {
public void add(E x){
}
public E findById(int id){
return null;
}
}
43.通过反射获得泛型的实际类型参数
得到方法的参数的实际类型
public static void applyVector(Vector<Date> v1){
}
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]);
}