首页 文章 精选 留言 我的

精选列表

搜索[千问小酒窝],共10004篇文章
优秀的个人博客,低调大师

Java面试必问通信框架NIO,原理详解

NIO流与块通道与缓冲区缓冲区状态变量文件 NIO 实例选择器套接字 NIO 实例内存映射文件NIO与IO对比PathFilesNIO新的输入/输出 (NIO) 库是在 JDK 1.4 中引入的,弥补了原来的 I/O 的不足,提供了高速的、面向块的 I/O。 NIO核心组件: 通道(Channels)缓冲区(Buffers)选择器(Selectors)流与块I/O 与 NIO 最重要的区别是数据打包和传输的方式,I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。 面向流的 I/O 一次处理一个字节数据:一个输入流产生一个字节数据,一个输出流消费一个字节数据。 为流式数据创建过滤器非常容易,链接几个过滤器,以便每个过滤器只负责复杂处理机制的一部分。不利的一面是,面向流的 I/O 通常相当慢。 面向块的 I/O 一次处理一个数据块,按块处理数据比按流处理数据要快得多。 但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。 I/O 包和 NIO 已经很好地集成了,java.io. 已经以 NIO 为基础重新实现了,所以现在它可以利用 NIO 的一些特性。 例如,java.io. 包中的一些类包含以块的形式读写数据的方法,这使得即使在面向流的系统中,处理速度也会更快。 通道与缓冲区 通道通道 Channel 是对原 I/O 包中的流的模拟,可以通过它读取和写入数据。 通道与流的不同之处在于,流只能在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类), 而通道是双向的,可以用于读、写或者同时用于读写。 通道包括以下类型: FileChannel:从文件中读写数据;DatagramChannel:通过 UDP 读写网络中数据;SocketChannel:通过 TCP 读写网络中数据;ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。 缓冲区发送给一个通道的所有数据都必须首先放到缓冲区中,同样地,从通道中读取的任何数据都要先读到缓冲区中。也就是说,不会直接对通道进行读写数据,而是要先经过缓冲区。 缓冲区实质上是一个数组,但它不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。 缓冲区包括以下类型: ByteBufferCharBufferShortBufferIntBufferLongBufferFloatBufferDoubleBuffer缓冲区状态变量capacity:最大容量;position:当前已经读写的字节数;limit:还可以读写的字节数。状态变量的改变过程举例: ① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0,而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。 ② 从输入通道中读取 5 个字节数据写入缓冲区中,此时 position 为 5,limit 保持不变。 ③ 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position,并将 position 设置为 0。 ④ 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。 ⑤ 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。 文件 NIO 实例FileChannel的使用开启FileChannel从FileChannel读取数据/写入数据3.关闭FileChannel public class FileChannelDemo { public static void main(String[] args) throws IOException { //1.创建一个RandomAccessFile(随机访问文件)对象通过RandomAccessFile对象的getChannel()方法。 RandomAccessFile raf=new RandomAccessFile("demo6.txt","rw"); FileChannel fc=raf.getChannel(); //使用FileChannel的read()方法读取数据: ByteBuffer byteBuffer=ByteBuffer.allocate(1024); int bys=fc.read(byteBuffer); //使用FileChannel的write()方法写入数据: ByteBuffer byteBuffer2=ByteBuffer.allocate(1024); byteBuffer2.put("hello".getBytes()); fc.write(byteBuffer2); //3.关闭FileChannel fc.close(); } }以下展示了使用 NIO 快速复制文件的实例:public class CopyFile { public static void main(String[] args) throws IOException { String srcFile="国旗歌.mp4"; String destFile="demo3.mp4"; long start = System.currentTimeMillis(); //copyFile(srcFile,destFile); //共耗时:75309毫秒 //copyFile2(srcFile,destFile); //共耗时:153毫秒 //copyFile3(srcFile,destFile);//共耗时:282毫秒 //copyFile4(srcFile,destFile);//共耗时:44毫秒 copyFile5(srcFile,destFile);//共耗时:共耗时:113毫秒 long end = System.currentTimeMillis(); System.out.println("共耗时:" + (end - start) + "毫秒"); } /** * 基本字节流一次读写一个字节 */ public static void copyFile(String srcFile,String destFile) throws IOException { FileInputStream fis=new FileInputStream(srcFile); FileOutputStream fos=new FileOutputStream(destFile); int by=0; while((by=fis.read())!=-1){ fos.write(by); } fis.close(); fos.close(); } /** * 基本字节流一次读写一个字节数组 */ public static void copyFile2(String srcFile,String destFile) throws IOException{ FileInputStream fis=new FileInputStream(srcFile); FileOutputStream fos=new FileOutputStream(destFile); int len=0; byte[] bys=new byte[1024]; while((len=fis.read(bys))!=-1){ fos.write(bys,0,len); } fis.close(); fos.close(); } /** * 高效字节流一次读写一个字节 */ public static void copyFile3(String srcFile,String destFile) throws IOException{ BufferedInputStream bis=new BufferedInputStream(new FileInputStream(srcFile)); BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(destFile)); int by=0; while((by=bis.read())!=-1){ bos.write(by); } bis.close(); bos.close(); } /** * 高效字节流一次读写一个字节数组 */ public static void copyFile4(String srcFile,String destFile) throws IOException{ BufferedInputStream bis=new BufferedInputStream(new FileInputStream(srcFile)); BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(destFile)); int len=0; byte[] bys=new byte[1024]; while((len=bis.read(bys))!=-1){ bos.write(bys,0,len); } bis.close(); bos.close(); } /** * 使用FileChannel复制文件 */ public static void copyFile5(String srcFile,String destFile) throws IOException{ FileInputStream fis=new FileInputStream(srcFile); //获取输入字节流的文件通道 FileChannel fcin=fis.getChannel(); FileOutputStream fos=new FileOutputStream(destFile); //获取输出字节流的文件通道 FileChannel fcout=fos.getChannel(); //为缓冲区分配 1024 个字节 ByteBuffer buffer = ByteBuffer.allocateDirect(1024); while(true){ //从输入通道中读取数据到缓冲区中 int r = fcin.read(buffer); // read() 返回 -1 表示 EOF if(r==-1){ break; } //切换读写 buffer.flip(); //把缓冲区的内容写入输出文件中 fcout.write(buffer); //清空缓冲区 buffer.clear(); } } }SocketChannel和ServerSocketChannel的使用SocketChannel用于创建基于TCP协议的客户端对象,因为SocketChannel中不存在accept()方法, 所以,它不能成为一个服务端程序。 通过connect()方法,SocketChannel对象可以连接到其他TCP服务器程序。 ServerSocketChannel允许我们监听TCP协议请求,通过ServerSocketChannel的accept()方法创建一个SocketChannel对象用户从客户端读/写数据。 服务端:通过ServerSocketChannel 绑定ip地址和端口号通过ServerSocketChannel的accept()方法创建一个SocketChannel对象用户从客户端读/写数据创建读数据/写数据缓冲区对象来读取客户端数据或向客户端发送数据关闭SocketChannel和ServerSocketChannelpublic class Server { public static void main(String[] args) throws IOException { //通过ServerSocketChannel 的open()方法创建一个ServerSocketChannel对象 ServerSocketChannel ssc=ServerSocketChannel.open(); //1. 通过ServerSocketChannel 绑定ip地址和端口号 ssc.socket().bind(new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),8888)); //2. 通过ServerSocketChannel的accept()方法创建一个SocketChannel对象用户从客户端读/写数据 SocketChannel sc=ssc.accept(); //3. 创建读数据/写数据缓冲区对象来读取客户端数据或向客户端发送数据 //读取客户端发送的数据 ByteBuffer buffer=ByteBuffer.allocate(1024); //从通道中读取数据到缓冲区 sc.read(buffer); StringBuffer sb=new StringBuffer(); buffer.flip(); while(buffer.hasRemaining()){ sb.append((char)buffer.get()); } System.out.println(sb.toString()); ByteBuffer buffer2=ByteBuffer.allocate(1024); //向客户端发送数据 buffer2.put("data has been received.".getBytes()); buffer2.flip(); sc.write(buffer2); //4. 关闭SocketChannel和ServerSocketChannel sc.close(); ssc.close(); } }客户端:1.通过SocketChannel连接到远程服务器 2.创建读数据/写数据缓冲区对象来读取服务端数据或向服务端发送数据 3.关闭SocketChannel public class Client { public static void main(String[] args) throws IOException { //1.通过SocketChannel连接到远程服务器 SocketChannel sc=SocketChannel.open(); sc.connect(new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),8888)); //2.创建读数据/写数据缓冲区对象来读取服务端数据或向服务端发送数据 //向通道中写入数据 ByteBuffer buffer=ByteBuffer.allocate(1024); buffer.put("hello".getBytes()); buffer.flip(); sc.write(buffer); //读取从客户端中获取的数据 ByteBuffer buffer2=ByteBuffer.allocate(1024); sc.read(buffer2); StringBuffer sb=new StringBuffer(); buffer2.flip(); while(buffer2.hasRemaining()){ sb.append((char)buffer2.get()); } System.out.println(sb.toString()); //3.关闭SocketChannel sc.close(); } }DatagramChannel的使用DataGramChannel,类似于java 网络编程的DatagramSocket类; 使用UDP进行网络传输, UDP是无连接,面向数据报文段的协议。 服务端:public class Server { public static void main(String[] args) throws IOException { DatagramChannel dc= DatagramChannel.open(); dc.bind(new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),8888)); //创建读数据/写数据缓冲区对象来读取客户端数据或向客户端发送数据 //读取客户端发送的数据 ByteBuffer buffer=ByteBuffer.allocate(1024); //从通道中读取数据到缓冲区 dc.receive(buffer); StringBuffer sb=new StringBuffer(); buffer.flip(); while(buffer.hasRemaining()){ sb.append((char)buffer.get()); } System.out.println(sb.toString()); ByteBuffer buffer2=ByteBuffer.allocate(1024); //向客户端发送数据 buffer2.put("data has been received.".getBytes()); buffer2.flip(); dc.send(buffer2,new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),9999)); dc.close(); } }客户端:public class Client { public static void main(String[] args) throws IOException { DatagramChannel dc= DatagramChannel.open(); dc.bind(new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),9999)); //创建读数据/写数据缓冲区对象来读取服务端数据或向服务端发送数据 //向通道中写入数据 ByteBuffer buffer=ByteBuffer.allocate(1024); buffer.put("hello".getBytes()); buffer.flip(); dc.send(buffer,new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),8888)); //读取从客户端中获取的数据 ByteBuffer buffer2=ByteBuffer.allocate(1024); dc.receive(buffer2); StringBuffer sb=new StringBuffer(); buffer2.flip(); while(buffer2.hasRemaining()){ sb.append((char)buffer2.get()); } System.out.println(sb.toString()); dc.close(); } }通道之间的数据传输在Java NIO中如果一个channel是FileChannel类型的,那么他可以直接把数据传输到另一个channel。 transferFrom() :transferFrom方法把数据从通道源传输到FileChanneltransferTo() :transferTo方法把FileChannel数据传输到另一个FileChhannelpublic static void copyFile6(String srcFile,String destFile) throws IOException { FileInputStream fis = new FileInputStream(srcFile); //获取输入字节流的文件通道 FileChannel fcin = fis.getChannel(); FileOutputStream fos = new FileOutputStream(destFile); //获取输出字节流的文件通道 FileChannel fcout = fos.getChannel(); //fcin通道中读出count bytes ,并写入fcout通道中 //fcin.transferTo(0,fcin.size(),fcout); //或者 fcout.transferFrom(fcin,0,fcin.size()); }选择器NIO 常常被叫做非阻塞 IO,主要是因为 NIO 在网络通信中的非阻塞特性被广泛使用。 NIO 实现了 IO 多路复用中的 Reactor 模型,一个线程 Thread 使用一个选择器 Selector 通过轮询的方式 去监听多个通道 Channel 上的事件,从而让一个线程就可以处理多个事件。 通过配置监听的通道 Channel 为非阻塞,那么当 Channel 上的 IO 事件还未到达时, 就不会进入阻塞状态一直等待,而是继续轮询其它 Channel,找到 IO 事件已经到达的 Channel 执行。 因为创建和切换线程的开销很大,因此使用一个线程来处理多个事件而不是一个线程处理一个事件, 对于 IO 密集型的应用具有很好地性能。 应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能, 为 FileChannel 配置非阻塞也没有意义。 使用Selector的优点: 使用更少的线程来就可以来处理通道了, 相比使用多个线程, 避免了线程上下文切换带来的开销。 创建选择器Selector selector = Selector.open(); 将通道注册到选择器上ServerSocketChannel ssChannel = ServerSocketChannel.open(); ssChannel.configureBlocking(false);//通道必须配置为非阻塞模式ssChannel.register(selector, SelectionKey.OP_ACCEPT);通道必须配置为非阻塞模式,否则使用选择器就没有任何意义了,因为如果通道在某个事件上被阻塞,那么服务器就不能响应其它事件,必须等待这个事件处理完毕才能去处理其它事件,显然这和选择器的作用背道而驰。 在将通道注册到选择器上时,还需要指定要注册的具体事件,主要有以下几类: SelectionKey.OP_CONNECTSelectionKey.OP_ACCEPTSelectionKey.OP_READSelectionKey.OP_WRITE它们在 SelectionKey 的定义如下: public static final int OP_READ = 1 << 0;public static final int OP_WRITE = 1 << 2;public static final int OP_CONNECT = 1 << 3;public static final int OP_ACCEPT = 1 << 4;可以看出每个事件可以被当成一个位域,从而组成事件集整数。例如: int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; 监听事件 num = selector.select(); 使用 select() 来监听到达的事件,它会一直阻塞直到有至少一个事件到达。 获取到达的事件Set keys = selector.selectedKeys(); Iterator keyIterator = keys.iterator();while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isAcceptable()) { // ... } else if (key.isReadable()) { // ... } keyIterator.remove(); } 事件循环因为一次 select() 调用不能处理完所有的事件,并且服务器端有可能需要一直监听事件,因此服务器端处理事件的代码一般会放在一个死循环内。 while (true) { int num = selector.select(); Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = keys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isAcceptable()) { // ... } else if (key.isReadable()) { // ... } keyIterator.remove(); } }套接字 NIO 实例public class NIOServer { public static void main(String[] args) throws IOException { //1. 创建选择器 Selector selector = Selector.open(); //2.将通道注册到选择器上 ServerSocketChannel ssChannel = ServerSocketChannel.open(); ssChannel.configureBlocking(false); //通道必须配置为非阻塞模式,否则使用选择器就没有任何意义了 ssChannel.register(selector, SelectionKey.OP_ACCEPT); ServerSocket ss=ssChannel.socket(); ss.bind(new InetSocketAddress("127.0.0.1",8888)); while (true){ //3. 监听事件 selector.select(); //4. 获取到达的事件 Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = keys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isAcceptable()) { ServerSocketChannel ssChannel1 = (ServerSocketChannel) key.channel(); // 服务器会为每个新连接创建一个 SocketChannel SocketChannel sChannel = ssChannel1.accept(); sChannel.configureBlocking(false); // 这个新连接主要用于从客户端读取数据 sChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { SocketChannel sChannel = (SocketChannel) key.channel(); System.out.println(readDataFromSocketChannel(sChannel)); sChannel.close(); } keyIterator.remove(); } } } private static String readDataFromSocketChannel(SocketChannel sChannel) throws IOException { ByteBuffer buffer = ByteBuffer.allocate(1024); StringBuilder data = new StringBuilder(); while (true) { buffer.clear(); int r = sChannel.read(buffer); if (r == -1) { break; } buffer.flip(); int limit = buffer.limit(); char[] dst = new char[limit]; for (int i = 0; i < limit; i++) { dst[i] = (char) buffer.get(i); } data.append(dst); buffer.clear(); } return data.toString(); } }public class NIOClient { public static void main(String[] args) throws IOException { Socket socket = new Socket("127.0.0.1", 8888); OutputStream out = socket.getOutputStream(); String s = "hello world"; out.write(s.getBytes()); out.close(); } }内存映射文件内存映射文件 I/O 是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的 I/O 快得多。 向内存映射文件写入可能是危险的,只是改变数组的单个元素这样的简单操作,就可能会直接修改磁盘上的文件。修改数据与将数据保存到磁盘是没有分开的。 下面代码行将文件的前 1024 个字节映射到内存中,map() 方法返回一个 MappedByteBuffer,它是 ByteBuffer 的子类。因此,可以像使用其他任何 ByteBuffer 一样使用新映射的缓冲区,操作系统会在需要时负责执行映射。 MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 1024);NIO与IO对比NIO 与普通 I/O 的区别主要有以下三点: NIO 是非阻塞的;NIO 面向块,I/O 面向流。NIO有选择器,而I/O没有。PathJava7中文件IO发生了很大的变化,专门引入了很多新的类来取代原来的 基于java.io.File的文件IO操作方式。 创建一个Path使用Paths工具类的get()方法创建Path对象 public class PathDemo { public static void main(String[] args) { //方式一 Path path=Paths.get("demo5.txt"); System.out.println(path); //方式二 Path path2 = FileSystems.getDefault().getPath("demo5.txt"); System.out.println(path2); } }File和Path之间的转换,File和URI之间的转换public class PathDemo2 { public static void main(String[] args) { Path path=Paths.get("demo5.txt"); File file=path.toFile(); URI uri=path.toUri(); System.out.println(path); System.out.println(file); System.out.println(uri); } }demo5.txtdemo5.txtfile:///F:/Java_Review/05Java/JavaIO/demo5.txt获取Path的相关信息public class PathDemo3 { public static void main(String[] args) { Path path= Paths.get("demo3\\test3.txt"); System.out.println("文件名:"+ path.getFileName()); System.out.println("名称元素的数量:"+path.getNameCount()); System.out.println("父路径:"+ path.getParent()); System.out.println("根路径:"+ path.getRoot()); System.out.println("是否是绝对路径:"+path.isAbsolute()); //startWith() 参数既可以是字符串,也可以是Path System.out.println("是否是以路径demo3开头:"+path.startsWith(Paths.get("demo3"))); System.out.println("该路径的字符串形式:"+path.toString()); } }文件名:test3.txt名称元素的数量:2父路径:demo3根路径:null是否是绝对路径:false是否是以路径demo3开头:true该路径的字符串形式:demo3test3.txt移除Path中的冗余项 .表示的是当前目录 ..表示父目录或者说是上一级目录 normalize() : 返回一个路径,该路径是取出冗余项的路径。 toRealPath() : 可以看成,先进行toAbsolutePath()操作,然后进行normalize()操作 public class PathDemo4 { public static void main(String[] args) throws IOException { Path path= Paths.get("./demo3"); System.out.println("original :"+ path.toAbsolutePath()); System.out.println("after normalize:"+ path.toAbsolutePath().normalize()); System.out.println("after toRealPath:"+ path.toRealPath()); } }original :F:Java_Review05JavaJavaIO.demo3after normalize:F:Java_Review05JavaJavaIOdemo3after toRealPath:F:Java_Review05JavaJavaIOdemo3public class PathDemo5 { public static void main(String[] args) throws IOException { Path path= Paths.get("../JavaIO"); System.out.println("original :"+ path.toAbsolutePath()); System.out.println("after normalize:"+ path.toAbsolutePath().normalize()); System.out.println("after toRealPath:"+ path.toRealPath()); } }original :F:Java_Review05JavaJavaIO..JavaIOafter normalize:F:Java_Review05JavaJavaIOafter toRealPath:F:Java_Review05JavaJavaIOFilesjava.nio.file.Files类是和java.nio.file.Path相结合使用的 检查给定的Path在文件系统中是否存在Files.exists():检测文件路径是否存在 public class FilesDemo { public static void main(String[] args) { Path path = Paths.get("demo5.txt"); //LinkOptions.NOFOLLOW_LINKS:表示检测时不包含符号链接文件。 boolean isExist= Files.exists(path,new LinkOption[]{LinkOption.NOFOLLOW_LINKS}); System.out.println(isExist); } }创建文件/文件夹Files.createFile():创建文件 Files.createDirectory(): 创建文件夹 Files.createDirectories(): 创建文件夹 public class FilesDemo2 { public static void main(String[] args) throws IOException { Path path= Paths.get("demo7.txt"); if(!Files.exists(path)){ Files.createFile(path); } Path path2=Paths.get("demo4"); if(!Files.exists(path2)){ Files.createDirectory(path2); } Path path3=Paths.get("demo5\\test"); if(!Files.exists(path3)){ Files.createDirectories(path3); } } }删除文件或目录Files.delete():删除一个文件或目录 public class FilesDemo3 { public static void main(String[] args) throws IOException { Path path= Paths.get("demo7.txt"); Files.delete(path); } }把一个文件从一个地址复制到另一个位置Files.copy():把一个文件从一个地址复制到另一个位置 public class FilesDemo4 { public static void main(String[] args) throws IOException { Path srcPath= Paths.get("demo6.txt"); Path destPath=Paths.get("demo7.txt"); //Files.copy(srcPath,destPath); //强制覆盖已经存在的目标文件 Files.copy(srcPath,destPath, StandardCopyOption.REPLACE_EXISTING); } }获取文件属性public class FilesDemo5 { public static void main(String[] args) throws IOException { Path path= Paths.get("demo7.txt"); System.out.println(Files.getLastModifiedTime(path)); System.out.println(Files.size(path)); System.out.println(Files.isSymbolicLink(path)); System.out.println(Files.isDirectory(path)); System.out.println(Files.readAttributes(path,"*")); } }遍历一个文件夹public class FilesDemo6 { public static void main(String[] args) throws IOException { Path path= Paths.get("demo3\\demo2"); DirectoryStream<Path> paths=Files.newDirectoryStream(path); for(Path p:paths){ System.out.println(p.getFileName()); } } }遍历整个文件目录FileVisitor需要调用方自行实现,然后作为参数传入walkFileTree(); FileVisitor的每个方法会在遍历过程中被调用多次。 public class FilesDemo7 { public static void main(String[] args) throws IOException { Path path= Paths.get("demo3\\demo2"); List<Path> paths=new ArrayList<>(); Files.walkFileTree(path,new FileVisitor(paths)); System.out.println("paths:"+paths); } private static class FileVisitor extends SimpleFileVisitor<Path> { private List<Path> paths; public FileVisitor(List<Path> paths){ this.paths=paths; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if(file.toString().endsWith(".txt")){ paths.add(file.getFileName()); } return super.visitFile(file, attrs); } } }输出结果: paths:[a.txt, test2.txt, test.txt, test3.txt]

优秀的个人博客,低调大师

Java 面试题经典 77 问(含答案)!

image 推荐:成为架构师的十阶段学习资料 金三银四了,3月底,4月初,找工作换单位的黄金时期。4月初将会有有一大批职场人士流动。。。 作为Java开发码农的你是不是也在蠢蠢欲动,或者已经搞了几轮车轮战了? 我们为大家准备了 77 道经典 Java 面试题,如果你面试不力,基础还不够强,那么你或许会受用! 1、什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? 2、JDK和JRE的区别是什么? 3、static关键字是什么意思?Java中是否可以覆盖(override)一个private或者是 static的方法? 4、是否可以在static环境中访问非static变量? 5、Java支持的数据类型有哪些?什么是自动拆装箱? 6、Java中的方法覆盖(Overriding)和方法重载(Overloading)是什么意思? 7、Java中,什么是构造函数?什么是构造函数重载?什么是复制构造函数? 8、Java支持多继承么? 9、接口和抽象类的区别是什么? 10、什么是值传递和引用传递? 11、进程和线程的区别是什么? 12、创建线程有几种不同的方式?你喜欢哪一种?为什么? 13、概括的解释下线程的几种可用状态。 14、同步方法和同步代码块的区别是什么? 15、什么是死锁(deadlock)? 16、如何确保N个线程可以访问N个资源同时又不导致死锁? 17、Java集合类框架的基本接口有哪些? 18、为什么集合类没有实现Cloneable和Serializable接口? 19、什么是迭代器(Iterator)? 20、Iterator和ListIterator的区别是什么? 21、快速失败(fail-­fast)和安全失败(fail-­safe)的区别是什么? 22、Java中的HashMap的工作原理是什么? 23、hashCode()和equals()方法的重要性体现在什么地方? 24.HashMap和Hashtable有什么区别? 25、数组(Array)和列表(ArrayList)有什么区别?什么时候应该使用Array而不是 ArrayList? 26、ArrayList和LinkedList有什么区别? 27、Comparable和Comparator接口是干什么的?列出它们的区别。 28、什么是Java优先级队列(Priority Queue)? 29、你了解大O符号(big-­O notation)么?你能给出不同数据结构的例子么? 30、如何权衡是使用无序的数组还是有序的数组? 31、Java集合类框架的最佳实践有哪些? 32、Enumeration接口和Iterator接口的区别有哪些? 33、HashSet和TreeSet有什么区别? 34、System.gc()和Runtime.gc()会做什么事情? 35、finalize()方法什么时候被调用?析构函数(finalization)的目的是什么? 36、果对象的引用被置为null,垃圾收集器是否会立即释放对象占用的内存? 37、Java堆的结构是什么样子的?什么是堆中的永久代(Perm Gen space)? 38、串行(serial)收集器和吞吐量(throughput)收集器的区别是什么? 39、在Java中,对象什么时候可以被垃圾回收? 40、JVM的永久代中会发生垃圾回收么? 41、Java中的两种异常类型是什么?他们有什么区别? 42、Java中Exception和Error有什么区别? 43、throw和throws有什么区别? 44、异常处理完成以后,Exception对象会发生什么变化? 45、finally代码块和finalize()方法有什么区别? 46、什么是JDBC? 47、解释下驱动(Driver)在JDBC中的角色。 48、Class.forName()方法有什么作用? 49、PreparedStatement比Statement有什么优势? 50、什么时候使用CallableStatement?用来准备CallableStatement的方法是什么? 51、数据库连接池是什么意思? 52、什么是RMI? 53、什么是分布式垃圾回收(DGC)?它是如何工作的? 54、解释下Serialization和Deserialization。 55、什么是Servlet? 56、说一下Servlet的体系结构。 57、GenericServlet和HttpServlet有什么区别? 58、解释下Servlet的生命周期。 59、doGet()方法和doPost()方法有什么区别? 60、什么是服务端包含(Server Side Include)? 61、什么是Servlet链(Servlet Chaining)? 62、如何知道是哪一个客户端的机器正在请求你的Servlet? 63、HTTP响应的结构是怎么样的? 64、什么是cookie?session和cookie有什么区别? 65、浏览器和Servlet通信使用的是什么协议? 66、什么是HTTP隧道? 67、sendRedirect()和forward()方法有什么区别? 68、什么是URL编码和URL解码? 69、JSP请求是如何被处理的? 70、什么是JSP指令(Directive)?JSP中有哪些不同类型的指令? 71、什么是JSP动作(JSP action)? 72、隐含对象是什么意思?有哪些隐含对象? 73、面向对象软件开发的优点有哪些? 74、封装的定义和好处有哪些? 75、多态的定义? 76、继承的定义? 77、抽象的定义?抽象和封装的不同点? 推荐:Spring Boot & Cloud 最强技术教程 扫描关注我们的微信公众号,干货每天更新。 image 在以下公众号回复 "答案" 获取全部参考答案。 image

优秀的个人博客,低调大师

每个CIO都应该问的IT转型问题

2017年企业对于IT最需要什么?效率,效率,效率。 根据德勤公司2016-2017年度的全球CIO调查,业界对CIO的期望值得期待,希望可以改善流程,降低成本,提高效率。这与“技术商业研究”的2016年报告相一致,这个报告发现效率指标是采用云专业服务的主要驱动力。 当然,问题是使业务更高效,说起来容易做起来难。它通常需要对现有IT系统进行重大改造。但即使如此,CIO们也明白要做到这一点:德勤公司在提出哪些能力对他们的成功最为重要的时候,绝大多数CIO(近75%)表示,“将IT活动与业务相结合战略和绩效目标。” 那么,IT如何有意义地提高效率?如果您的组织正在追求批发IT转型,那么您应该努力回答的一些复杂问题 - 倾向于内部主题专家和主要战略合作伙伴的指导: 企业的业​​务哪些领域最受益于云计算? 成功的IT转型项目始终是确定新技术和管理服务投资将产生最大影响的领域。 企业的开发团队或业务部门是否呼吁自助服务基础设施功能?企业是否需要支持物联网,机器学习和大数据计划等新兴用例?由于产品推出或收购,企业是否很快需要支持大幅增长?基于云计算的电子邮件服务(如Office 365)相对于企业当前的解决方案而言是否成本更低和更容易管理?是否有某些应用程序不能从云计算中获益? 企业的垂直的独特需求是什么? 企业是否经营一个电子商务网站,由于季节性或营销活动而导致大量流量峰值?企业是医疗保健或金融服务公司,遵守规定是否需要内部部署基础设施?企业是否面临传统制造业务与复杂的传统技术挑战?企业的管理服务合作伙伴在多大程度上能够展示其行业的专业知识和体验? 什么业务流程和文化变化会使企业更有效率? 根据Gartner公司最近的一项研究,许多CIO认为“文化/组织结构”是其成功的首要障碍,仅仅是专门知识和预算限制。企业的IT组织是否遭受“孤岛”团队或过时的部署过程?企业是否可以从现代DevOps实践中获益,例如持续集成和部署(CI / CD),基础架构自动化或改进开发与IT团队之间的沟通?企业IT组织应该更多地成为企业基于云的服务的代理商吗?如果是这样,如何最好地访问在部署和运行的生命周期中提供建议的服务管理专业知识? 企业将投资哪些平台和技术? 企业将如何使用AWS,Microsoft Azure和/或谷歌云平台?企业会继续投资运营自己的数据中心吗?企业将使用VMWare,Microsoft或OpenStack构建私有云解决方案?企业将如何浏览日益复杂的多云世界?是否会利用尖端技术,例如Docker进行容器化,或将AWS Lambda用于“无服务器架构”?哪些管理服务提供商可以帮助企业为其业务做出最佳的技术和服务交付决策? 企业成功的最大障碍是什么? 根据Gartner公司的这份报告,“人力资源现在已被全球公认为CIO实现其目标的最大问题”,其中大数据和分析的最大差距。同样,RightScale的2016云状态显示,缺乏专业知识已经超越了安全和合规性问题,成为云计算第一大问题。 你的组织是这样的情况吗?关于预算限制,传统技术现实和文化问题的问题呢? 企业最大的专业差距在哪里? 企业可以接触所需的人员以最好地支持上述的技术决策吗?例如,企业是否准备好计划和执行必要的迁移?如何在AWS平台,Azure或OpenStack等云平台上构建解决方案?企业是否具备实施持续集成和部署(CI / CD)最佳做法所需的DevOps体验?企业的网页内容管理或电子商务平台所需的专业应用级专业知识如何?企业是否需要熟练的人力来处理持续的操作挑战,例如维护,安全和数据库调整? 根据这些需求,企业雇用或培训更多内部资源有什么意义?在特定技术能力和运营经验范围内,从规模经济中获益的合作伙伴,企业在哪方面更有成本效益? 结论 这些只是一些企业需要回答的复杂的技术和服务交付问题,如果想真正改变它,并提升主要的新效率。 例如Rackspace公司,都能看到每天的主要IT转型计划的实际影响。 例如,Rackspace公司最近将英国都市银行迁移到基于VMWare的私有云解决方案,以帮助他们在满足安全需求的同时扩展业务。在迁移后的第二天,他们的日常营业报告处理速度提高了50%。 这就意味着提高效率,使IT与业务战略和目标保持一致。 本文转自d1net(转载)

优秀的个人博客,低调大师

几个绘图小案例

昨天给一个做无人机的机构开发了一节流水灯的课程,不过由于没有实物,只能用turtle库模拟一下效果,便于放到课程中; 步骤图: 代码: (没有无人机,没法测试,纯靠看文档编的) 完成后有了一些新的想法,就在现有的流水灯程序上进行修改,完成了一些其它demo。 手串 代码: 绘制多边形 代码: 多边形内外接圆 代码: (全文完) 长按二维码,加关注!叶子陪你玩 欢迎转载,转载请注明出处! 欢迎关注公众微信号:叶子陪你玩编程 分享自己的python学习之路 本文分享自微信公众号 - 叶子陪你玩编程(gh_cd062460d25e)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

Docker命令小总结

attach Attach to a running container # 当前 shell 下 attach 连接指定运行镜像 build Build an image from a Dockerfile # 通过 Dockerfile 定制镜像 commit Create a new image from a container changes # 提交当前容器为新的镜像 cp Copy files/folders from the containers filesystem to the host path #从容器中拷贝指定文件或者目录到宿主机中 create Create a new container # 创建一个新的容器,同 run,但不启动容器 diff Inspect changes on a container's filesystem # 查看 docker 容器变化 events Get real time events from the server # 从 docker 服务获取容器实时事件 exec Run a command in an existing container # 在已存在的容器上运行命令 export Stream the contents of a container as a tar archive # 导出容器的内容流作为一个 tar 归档文件[对应 import ] history Show the history of an image # 展示一个镜像形成历史 images List images # 列出系统当前镜像 import Create a new filesystem image from the contents of a tarball # 从tar包中的内容创建一个新的文件系统映像[对应export] info Display system-wide information # 显示系统相关信息 inspect Return low-level information on a container # 查看容器详细信息 kill Kill a running container # kill 指定 docker 容器 load Load an image from a tar archive # 从一个 tar 包中加载一个镜像[对应 save] login Register or Login to the docker registry server # 注册或者登陆一个 docker 源服务器 logout Log out from a Docker registry server # 从当前 Docker registry 退出 logs Fetch the logs of a container # 输出当前容器日志信息 port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT # 查看映射端口对应的容器内部源端口 pause Pause all processes within a container # 暂停容器 ps List containers # 列出容器列表 pull Pull an image or a repository from the docker registry server # 从docker镜像源服务器拉取指定镜像或者库镜像 push Push an image or a repository to the docker registry server # 推送指定镜像或者库镜像至docker源服务器 restart Restart a running container # 重启运行的容器 rm Remove one or more containers # 移除一个或者多个容器 rmi Remove one or more images # 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除] run Run a command in a new container # 创建一个新的容器并运行一个命令 save Save an image to a tar archive # 保存一个镜像为一个 tar 包[对应 load] search Search for an image on the Docker Hub # 在 docker hub 中搜索镜像 start Start a stopped containers # 启动容器 stop Stop a running containers # 停止容器 tag Tag an image into a repository # 给源中镜像打标签 top Lookup the running processes of a container # 查看容器中运行的进程信息 unpause Unpause a paused container # 取消暂停容器 version Show the docker version information # 查看 docker 版本号 wait Block until a container stops, then print its exit code # 截取容器停止时的退出状态值

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册