Java中的数据结构主要包括以下几种接口和类:
以上这些类是传统遗留的,在Java2中引入了一种新的框架-集合框架(Collection)
枚举(Enumeration)接口虽然它本身不属于数据结构,但它在其他数据结构的范畴里应用很广。 枚举(The Enumeration)接口定义了一种从数据结构中取回连续元素的方式。
例如,枚举定义了一个叫nextElement 的方法,该方法用来得到一个包含多元素的数据结构的下一个元素。
位集合类实现了一组可以单独设置和清除的位或标志。
该类在处理一组布尔值的时候非常有用,你只需要给每个值赋值一"位",然后对位进行适当的设置或清除,就可以对布尔值进行操作了。
向量(Vector)类和传统数组非常相似,但是Vector的大小能根据需要动态的变化。
和数组一样,Vector对象的元素也能通过索引访问。
使用Vector类最主要的好处就是在创建对象的时候不必给对象指定大小,它的大小会根据需要动态的变化。
栈(Stack)实现了一个**后进先出(LIFO)**的数据结构。
你可以把栈理解为对象的垂直分布的栈,当你添加一个新元素时,就将新元素放在其他元素的顶部。
当你从栈中取元素的时候,就从栈顶取一个元素。换句话说,最后进栈的元素最先被取出。
字典(Dictionary) 类是一个抽象类,它定义了键映射到值的数据结构。
当你想要通过特定的键而不是整数索引来访问数据的时候,这时候应该使用Dictionary。
由于Dictionary类是抽象类,所以它只提供了键映射到值的数据结构,而没有提供特定的实现。
注: Dictionary类已经过时了。在实际开发中,你可以实现Map接口来获取键/值的存储功能。
Hashtable类提供了一种在用户定义键结构的基础上来组织数据的手段。
例如,在地址列表的哈希表中,你可以根据邮政编码作为键来存储和排序数据,而不是通过人名。
哈希表键的具体含义完全取决于哈希表的使用情景和它包含的数据。
Hashtable是原始的java.util的一部分, 是一个Dictionary具体的实现 。
然而,Java 2 重构的Hashtable实现了Map接口,因此,Hashtable现在集成到了集合框架中。它和HashMap类很相似,但是它支持同步。
Properties 继承于 Hashtable.Properties 类表示了一个持久的属性集。属性列表中每个键及其对应值都是一个字符串。
Properties 类被许多Java类使用。例如,在获取环境变量时它就作为System.getProperties()方法的返回值。
Java 中的 Iterator 功能比较简单,并且只能单向移动:
集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:
除了集合,该框架也定义了几个Map接口和类。Map里存储的是键/值对。尽管Map不是collections,但是它们完全整合在集合中。
1) 同步性:Vector是线程安全的,也就是说是同步的 ,而ArrayList 是线程序不安全的,不是同步的 数2。
2)数据增长:当需要增长时,Vector默认增长为原来一倍 ,而ArrayList却是原来的50% ,这样,ArrayList就有利于节约内存空间。 如果涉及到堆栈,队列等操作,应该考虑用Vector,如果需要快速随机访问元素,应该使用ArrayList 。
Hashtable和HashMap它们的性能方面的比较类似 Vector和ArrayList,比如Hashtable的方法是同步的,而HashMap的不是。
ArrayList的内部实现是基于内部数组Object[],所以从概念上讲,它更象数组,但LinkedList的内部实现是基于一组连接的记录,所以,它更象一个链表结构,所以,它们在性能上有很大的差别: 从上面的分析可知,在ArrayList的前面或中间插入数据时,你必须将其后的所有数据相应的后移,这样必然要花费较多时间,所以,当你的操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能; 而访问链表中的某个元素时,就必须从链表的一端开始沿着连接方向一个一个元素地去查找,直到找到所需的元素为止,所以,当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。
来源:
泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。 要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("菜鸟教程"));
System.out.printf("整型值为 :%d\n\n", integerBox.get());
System.out.printf("字符串为 :%s\n", stringBox.get());
}
}
输出结果:
整型值为 :10
字符串为 :菜鸟教程
实例:
public class GenericTest {
public static void main(String[] args) {
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number = new ArrayList<Number>();
name.add("icon");
age.add(18);
number.add(314);
//getUperNumber(name);//1
getUperNumber(age);//2
getUperNumber(number);//3
}
public static void getData(List<?> data) {
System.out.println("data :" + data.get(0));
}
public static void getUperNumber(List<? extends Number> data) {
System.out.println("data :" + data.get(0));
}
}
输出结果:
data :18
data :314
解析: 在(//1)处会出现错误,因为getUperNumber()方法中的参数已经限定了参数泛型上限为Number,所以泛型为String是不在这个范围之内,所以会报错
额外资料 泛型继承的几种写法
---更新到(一)
java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。
java.net 包中提供了两种常见的网络协议的支持:
这是使用最广泛的网络概念。 套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。
当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行进行通信。
java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。
连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。
TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送。以下是一些类提供的一套完整的有用的方法来实现 socket。
服务器应用程序通过使用 java.net.ServerSocket 类以获取一个端口,并且侦听客户端请求。
创建非绑定服务器套接字。 如果 ServerSocket 构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。
java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个 Socket 对象通过实例化 ,而 服务器获得一个 Socket 对象则通过 accept() 方法的返回值。
当 Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。
这个类表示互联网协议(IP)地址。
public class GreetingClient {
public static void main(String[] args){
String serverName = args[0];
int port = Integer.parseInt(args[1]);
System.out.println("连接到主机:" + serverName + " ,端口号:" + port);
try {
//创建一个流套接字并将其连接到指定主机上的指定端口号。
Socket client = new Socket(serverName,port);
//getRemoteSocketAddress()返回此套接字连接的端点的地址,如果未连接则返回 null。
System.out.println("远程主机地址:" + client.getRemoteSocketAddress());
//返回此套接字的输出流。
OutputStream outToServer = client.getOutputStream();
//数据输出流(DataOutputStream)允许应用程序以与机器无关方式将Java基本数据类型写到底层输出流。
DataOutputStream out = new DataOutputStream(outToServer);
//getLocalSocketAddress获取本地的IP和端口---输出流-传递信息给服务器端
out.writeUTF(" Hello from "+client.getLocalSocketAddress());
//输入流-获取服务器端返回的响应。
InputStream inFormServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFormServer);
System.out.println("服务器响应:"+in.readUTF());
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class GreetingServer extends Thread {
private ServerSocket serverSocket;
public GreetingServer(int port) throws IOException{
//创建绑定到特定端口的服务器套接字。
serverSocket = new ServerSocket(port);
//通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。
serverSocket.setSoTimeout(10000);
}
public void run(){
while (true){
try {
System.out.println("等待远程连接,端口号为:" + serverSocket.getLocalPort() + "...");
//侦听并接受到此套接字的连接。
Socket server = serverSocket.accept();
System.out.println("远程主机地址:" + server.getRemoteSocketAddress());
//输入流-获取客户端传来的消息
DataInputStream in = new DataInputStream(server.getInputStream());
System.out.println("服务端打印:"+in.readUTF());
//输出流-将服务端响应返给客户端
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF("谢谢连接我:" + server.getLocalSocketAddress() + "\nGoodbye!");
server.close();
} catch (SocketTimeoutException e){
System.out.println("Socket timed out!");
break;
}catch (IOException e) {
e.printStackTrace();
break;
}
}
}
public static void main(String[] args){
int port = Integer.parseInt(args[0]);
try {
Thread r= new GreetingServer(port);
r.run();
} catch (IOException e) {
e.printStackTrace();
}
}
}
编译以上两个 java 文件代码,并执行以下命令来启动服务,使用端口号为 6066:
$ javac GreetingServer.java
$ java GreetingServer 6066
等待远程连接,端口号为:6066...
新开一个命令窗口,执行以上命令来开启客户端:
$ javac GreetingClient.java
$ java GreetingClient localhost 6066
连接到主机:localhost ,端口号:6606
远程主机地址:localhost/127.0.0.1:6606
服务器响应:谢谢连接我:/127.0.0.1:6606
Goodbye!
同时,服务端窗口会增加:
远程主机地址:/127.0.0.1:54277
服务端打印: Hello from /127.0.0.1:54277
若超过10s后,服务端会自动断开,并输出:
Socket timed out!
此时再通过客户端访问,会因为无服务连接报java.net.ConnectException: Connection refused: connect的错误。
URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。表示为互联网上的资源,如网页或者FTP地址。
URL可以分为如下几个部分。
protocol://host:port/path?query#fragment
protocol(协议) 可以是 HTTP、HTTPS、FTP 和 File,port 为端口号,path为文件路径及文件名。 HTTP 协议的 URL 实例如下:
https://windcoder.com/index.html?language=cn#j2se
URL 解析:
实例:
public class URLDemo {
public static void main(String[] args) {
try {
URL url = new URL("https://windcoder.com/index.html?language=cn#j2se");
System.out.println("URL 为:" + url.toString());
System.out.println("协议为:" + url.getProtocol());
System.out.println("验证信息:" + url.getAuthority());
System.out.println("文件名及请求参数:" + url.getFile());
System.out.println("主机名:" + url.getHost());
System.out.println("路径:" + url.getPath());
System.out.println("端口:" + url.getPort());
System.out.println("默认端口:" + url.getDefaultPort());
System.out.println("请求参数:" + url.getQuery());
System.out.println("定位位置:" + url.getRef());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
由于未调用openConnection(),所以并未建立连接。
openConnection() 返回一个 java.net.URLConnection。 例如:
public class URLConnDemo {
public static void main(String[] args) {
try {
//通过给定的URL字符串创建URL
URL url = new URL("http://www.baidu.com");
//打开一个URL连接,并运行客户端访问资源。连接HTTP协议的URL, openConnection() 方法返回 HttpURLConnection 对象。
URLConnection urlConnection = url.openConnection();
HttpURLConnection connection = null;
if (urlConnection instanceof HttpURLConnection){
connection = (HttpURLConnection) urlConnection;
}else {
System.out.println("请输入 URL 地址");
return;
}
//读取资源
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuffer urlString = new StringBuffer();
String current;
while ((current =in.readLine())!=null){
urlString.append(current);
}
System.out.println(urlString.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
进程:
一个线程完整的生命周期
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
如果一个线程执行了sleep(睡眠)、suspend(挂起) 等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
1、每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。
2、Java 线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。
3、默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。
4、具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。
5、使用setPriority设置:
Thread t1 = new MyThread1();
Thread t2 = new Thread(new MyRunnable());
t1.setPriority(10);
t2.setPriority(1);
t2.start();
t1.start();
Java 提供了三种创建线程的方法:
创建一个线程,最简单的方法是创建一个实现 Runnable 接口的类。
为了实现 Runnable,一个类只需要执行一个方法调用 run(),声明如下:
public void run()
该方法可以被重写, run() 可以调用其他方法,使用其他类,并声明变量,就像主线程一样。
在创建一个实现 Runnable 接口的类之后,你可以在类中实例化一个线程对象。
Thread 定义了几个构造方法,下面的这个是我们经常使用的:
Thread(Runnable threadOb,String threadName);
这里,threadOb 是一个实现 Runnable 接口的类的实例,并且 threadName 指定新线程的名字。 新线程创建之后,你调用它的 start() 方法它才会运行。
void start();
创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。
继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。
该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。
接触Callable和Future太少,留些资料,之后深究。 Java程序员必须掌握的线程知识-Callable和Future Java 多线程(七) 线程间的通信 JAVA中线程同步的方法(7种)汇总
当一个线程进入一个对象的一个synchronized方法后,其它线程可以访问该对象的非同步方法。
一个线程在访问一个对象的同步方法时,另一个线程不能同时访问这个同步方法。
一个线程在访问一个对象的同步方法时,另一个线程不能同时访问这个对象的另一个同步方法。
当一个同步方法已经执行,线程能够调用对象上的非同步实例方法。
延伸 关于多线程常见问题 Java程序员面试中的多线程问题 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? java 多线程面试题 从面试题看问题之线程篇(一)
原理:一般来说,java应用程序访问数据库的过程是:
分析
数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。
大大提供了数据库连接的利用率,减小了内存吞吐的开销。