集合
一、集合体系
当一个对象具有很多属性和方法时,一般会用一个类来表示。
当有很多对象存在时,就要用到集合来管理。集合中不可能存放的时对象实体,集合和数组一样,存放的是地址。
集合体系图:
二、迭代器
集合中的元素如何取出?集合的取出元素的方式是迭代器。
把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素,那么取出方式就被定义成了内部类,而每一个容器的数据结构也不同,所以取出的动作细节也不一样,但是都有共性内容(判断和取出),那么可以将写共性抽取。
这些内部类符合一个规则,该规则是Iterator,如何获取集合的取出对象呢?通过一个对外提供的方法iterator();
如:
注:
List集合特有的迭代器-------ListIterator。ListIterator是Iterator的子接口。
在迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生并发修改异常。
所以在迭代时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作,如果想要进行其他的操作,如添加,修改等,就需要使用其子接口。ListIterator,该接口只能通过List集合的listIterator方法获取。
三、Collection
Collection分为List和Set两大集合。单列集合。
Set:元素是无序的,元素不可以重复。
List:元素是有序的,元素可以重复。
List子类
List集合保证元素唯一性的办法是:equals()。在判断对象时,一定要重写equals方法。
Set集合子类
Set集合保证元素唯一性的办法是:
(1)HashSet:hashCode()方法和equals()方法
(2)TreeSet:<1>实现Comparable接口,重写CompareTo方法(此接口强制让元素具备比较性。)---------------自然排序。
<2>当元素自身不具备比较性,或者具备的比较性不是所需要的时,需要让集合自身具备比较性。方法是:
定义一个比较器,利用集合的构造函数功能给它在new初始化时传入一个比较器。自定义比较器的方法是:实现Comparator接口,重写其中的Compare方法。
四、Map
存储键值对,一对一对存,而且要保证键的唯一性。双列集合。
Map集合取出自己元素不用迭代器,有自己的方式:ketSet和entrySet。
Map集合保证元素唯一性的办法和Set集合类似。
五、List和Set练习
需求一:将自定义对象作为元素存到ArrayList集合中,并去除重复元素。比如:存人对象。同姓名同年龄,视为同一个人,重复元素。
需求二:往HashSet中存储自定义对象,去除重复对象并排序。
main方法:
需求三:TreeSet集合存储学生对象,自然排序和按照姓名排序。
TreeSet自定义比较器排序
TreeSet排序主函数:
需求四:Map自定义对象存储排序
自定义比较器排序
主函数:
泛型
一、泛型概述
例子:
当编译上面程序时,编译通过,但是运行失败。出现ClassCastException。由此引出泛型。
(1)泛型好处:将运行时期问题转移到了编译时期,有利于让程序员解决问题,避免了强制转换问题。
(2)泛型格式:通过<>来定义要操作的引用数据类型。
(3)在使用java提供的对象时,什么时候使用泛型?
通常在集合框架中很常见,只要见到<>就要定义泛型。其实<>就是用来接收数据类型的。当使用集合时,将集合中要存储的数据类型作为参数传递到<>即可。
二、泛型类
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展,现在定义泛型类来扩展。
例子:
三、泛型方法:为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
注意:静态方法不可以访问类上定义的泛型,如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。
泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就固定 了。为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
例子:
四、泛型接口
五、通配符和泛型限定
?通配符,也可以理解为占位符。好处:可以不用明确传入的类型,提高了扩展性。
? extends E:可以接受E类型或者E的子类型,上限
? super E:可以接受E类型或者E的父类型,下限
反射
一、RTTI和反射。
RTTI(Run-Time Type Information,运行时类型信息。):编译器在编译时打开和检查.class文件。
反射:.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件。
反射就是把java类中的各种成分映射成相应的java类。
二、反射
Class类和java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了Field、Method以及Constructor类。这些类型的对象是由JVM在运行时创建的,用以表示未知类里对应的成员。这样你就可以用Constructor创建新的对象,用get()和set()方法读取和修改与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。另外,还可以调用getFiedls()、getMethods()和getConstructors()等很便利的方法,以返回表示字段、方法以及构造器的对象的数组。
反射在java中是用来支持其他特性的,如对象序列化和JavaBean(一个bean就是一个可重用的软件构件,能够在开发工具中可视化地操作)。
反射机制提供了足够的支持,使得能够创建一个在编译时完全未知的对象,并调用此对象的方法。
三、Class类
1、java程序中的各个java类,属于同一类事物,而描述这类事物的一个类就叫做Class类。这个Class很容易让人混淆。Object类中的getClass()方法将返回一个Class类型的实例。
Class<?> getClass()
每个对象都可以返回一个Class对象,Class对象在硬盘上的形式都是字节码。
如何得到各个字节码对应的Class类对象?
(1)Class c1=对象.getClass();
(2)如String className="java.util.Date"; Class c1=Class.foName(className);
(3)如果T是任意的java类型,T.class将代表匹配的类对象。 Class c1=int.class;
虚拟机为每个类型管理一个Class对象,因此,可以利用==运算符实现两个类对象比较的操作。例如:Employee e; .......if(e.getClass()==Employee.class).........
还有一个很有用的方法newInstance(),可以用来快速地创建一个类的实例。例如:e.getClass().newInstance();创建了一个与e具有相同类类型的实例,newInstance()方法调用默认的构造器初始化新创建的对象。
forName()和newInstance()结合使用:String s="java.util.Date"; Object obj=Class.forName(s).newInstance();
2、利用反射分析类
java.lang.reflect包中的三个类Field、Method和Constructor分别用于描述类的属性,方法和构造函数。
这三个类都有一个叫做getName的方法,用来返回相应的名称。
Field类有一个getType方法,用来返回描述变量所属类型的Class对象。Method和Constructor类有报告参数类型的方法,Method类还有一个可以报告返回类型的方法。
这三个类还有一个叫做getModifiers()的方法,它将返回一个整型数值,我们通过调用Modifier.toString方法将这个返回的整形数值变成字符串,而这个字符串就是我们所需要的修饰符。
Class类中的getFields、getMethods和getConstructors方法将分别返回类提供的public成员、方法和构造器数组,其中包括父类的公有成员。
Class类的getDeclareFields、getDeclaredMethods和getDeclaredConstructors方法将分别返回类中声明的全部成员、方法和构造器,其中包括私有和受保护成员,但不包括父类的成员。
3、写一个小程序,一切都懂了。
定义好以上3个方法后,我们可以在主函数中使用这三个方法来实现我们的目标:打印出某个类中所有的构造方法,成员方法,成员变量。
四、数组的反射
练习说明一切。