3.2 反射
我们通常写的程序,都是静态的代码,比如:调用
class A
示例的
put
方法:
A a = new A();
a.put(“Hello!”);
第二行,
a.put
就是一种静态的写法。在编译阶段,就完成对
a
类型的解析,对
a
是否具有
put
方法进行了判断。如果
a
对象没有
put
方法,则编译不通过。
可是,在另外一些情况下,我们需要在运行时动态的对一些对象的指定方法进行调用,比如我们想写一个通用的函数,传入一个对象,把这个对象的属性名和属性值都打印出来,这就需要使用反射技术。
反射,是在
JDK 1.5
引入的,
JDK 1.4
以及以前的版本不支持。
在
java.lang.reflect
包中,定义了一些类,用于动态解析和调用对象,常用的如下:
Constructor
:构造函数
Field
:
成员变量
Method
:
成员方法
Type
:
类型
另外,
java.lang
包中,
Class
类是非常值得重视的,通常用它来动态创建对象。对于声明了无参数的构造函数、或者有默认构造函数的类,动态创建一个对象的代码如下:
Class cls = Class.forName(“com.test.ServiceImpl”);
Object obj = cls.newInstance();
这样,一个
com.test.ServiceImpl
类的实例就创建出来了。
假如
ServiceImpl
类有个
registerUser
方法,实现用户注册功能,如下:
public int registerUser(String userName, String passwd);
如何动态调用呢?代码示例如下:
//
动态加载类
Class cls = Class.forName("com.test.ServiceImpl");
//
动态创建对象
Object obj = cls.newInstance();
//
获取相应的方法
Method method = cls.getDeclaredMethod("registerUser", String.class, String.class);
String userName = "zhangsan";
String passwd = "hello123";
//
动态调用对象的方法
Object result = method.invoke(obj, new Object[] {userName, passwd});
//
强制类型转换,获取函数调用的返回值
int userId = ((Integer)result).intValue();
System.out.println("userId=" + userId);
以上代码,需用
try { }
包括起来,捕获异常。
3.3 数据结构
本节对编程中经常使用的线性数据结构和非线性数据结构进行了简单介绍。线性数据结构介绍两种:ArrayList
和LinkedList
。非线性数据结构介绍两种:HashSet
和HashMap
。这些数据结构,都在
java.util
包中定义。
3.3.1 ArrayList
ArrayList
是个线性的数据结构,可以在任何位置对元素进行增加和删除。但请注意以下要点:
1)
ArrayList
是非同步的。也就是说,在多线程并发操作
ArrayList
的场景下,需要我们来写代码对
ArrayList
进行同步;
2)
ArrayList
内部是用数组来实现的,对元素的增加和删除都会引起数组的内存分配空间动态发生变化。因此,对其进行插入和删除速度较慢,但检索速度很快。
3)
ArrayList
中可以同时存放不同的对象;
ArrayList
常用的方法有:
boolean add(Object element) ; //
在尾部添加一个对象
void add(int index, Object element); //
在指定位置插入元素
, index
从
0
计起
Object get(int index); //
获取指定位置的元素
boolean contains(Object elem); //
判断是否包含此元素
int indexOf(Object elem); //
获取指定元素在链表中的位置
Object remove(int index); //
删除指定位置的元素
boolean remove(Object o); //
删除指定的对象
int size(); //
获取链表中元素的数量
void clear(); //
清空链表
3.3.2 LinkedList
LinkedList
也是一个线性的数据结构,可以在任何位置对元素进行增加和删除。使用
LinkedList
时,需注意以下:
1)
LinkedList
是非同步的。也就是说,在多线程并发操作
LinkedList
的场景下,需要我们来写代码对
LinkedList
进行同步;
2)
LinkedList
内部就是用动态链表来实现的,因此与
ArrayList
相比,其增加和删除元素速度很快,整个
List
不需要重新分配空间,但检索速度较慢;
3)
LinkedList
实现了
Queue
接口,可以用做一个先进先出的队列来使用;
LinkedList
常用的方法与
ArrayList
类似,增加了
Queue
接口的方法如下:
boolean offer(Object element); //
增加元素到队列尾部
Object peek(); //
获取队列头部的元素,并且不从队列中移出
Object poll(); //
获取队列头部的元素,并且从队列中移出
Object remove(); //
将队列头部元素移出
3.3.3 HashSet
HashSet
是个集合类型的数据结构,实现了
Set
接口,满足数学上对集合的定义:无序、不重复。使用
HashSet
时需要注意:
1)
HashSet
是非同步的。也就是说,在多线程并发操作
HashSet
的场景下,需要我们来写代码对
HashSet
进行同步;
2)
HashSet
内部是用
HashMap
来实现的,对元素的增加、删除、检索有很高的性能;
3)
HashSet
中元素是无序的,因此对
HashSet
进行遍历,不保证遍历元素的顺序都一致;
4)
HashSet
中没有重复的元素,因此将相同的多个对象加入到
HashSet
中,则最终
HashSet
中只有一个对象;、
HashSet
常用的方法如下:
boolean add(Object o); //
增加元素到集合中
boolean remove(Object o); //
从集合中删除元素
boolean contains(Object o); //
判断集合中是否包含指定的对象
Iterator iterator(); //
返回集合的迭代器,用于遍历集合
boolean isEmpty(); //
判断集合是否为空
int size(); //
获取集合中元素的数量
void clear(); //
清空集合
3.3.4 HashMap
HashMap
,又称杂凑表、散列表,它是一个非线性的数据结构。其中每个元素由
Key
和
Value
对构成,
Key
用来做索引,
Value
是实际要存储的值。使用
HashMap
时需要注意:
1)
HashMap
是非同步的。也就是说,在多线程并发操作
HashMap
的场景下,需要我们来写代码对
HashMap
进行同步;
2)
HashMap
对元素插入、删除、检索的速度都非常快,在高性能的情况下被大量使用,其缺点是内存占用较多。
3)
HashMap
中可以存放不同类型的对象,包括
null
。
HashMap
常用的方法如下:
Object put(Object key, Object value); //
将
Key-Value
对放入
Map
中
Object get(Object key); //
用
Key
获取
Value
对象
Object remove(Object key); //
从
Map
中删除
Key-Value
对
boolean containsKey(Object key); //
判断是否包括指定的
Key
boolean containsValue(Object value); //
判断是否包含指定的
Value
Set keySet(); //
获取
Key
的集合,配合
get
方法,可以遍历
Map
Set entrySet(); //
获取
Map.Entry
的集合,可以通过
Map.Entry
直接遍历每个
Key
和
Value
boolean isEmpty(); //
判断是否为空
int size(); //
判断
Map
中的元素个数
void clear(); //
清空
Map
本文出自 “expert” 博客,转载请与作者联系!