Netty权威指南(笔记一)
转载:http://blog.csdn.net/clarkkentyang/article/details/52529785
第一章(略)
第二章 NIO入门
2.1传统的BIO编程(同步阻塞I/O服务端通信模型【一客户一线程】)
网络编程的基本模型:Client/Server模型,也就是2个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务端监听的地址发起连接请求,通过三次握手建立连接,如果连接建立成功,双方就可以通过网络套接字(Socket)进行通信。
传统同步阻塞模型开发中,ServerSocket负责绑定IP地址,启动监听端口;Socket负责发起连接操作。连接成功之后,双方通过输入和输出流进行同步阻塞式通信。
缺点:缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,由于线程是Java虚拟机非常宝贵的系统资源,当线程数膨胀之后,系统的性能将急剧下降,随着并发访问量的继续增大,系统会发生线程堆栈溢出、创建新线程失败等问题,并最终导致进程宕机或者僵死,不能对外提供服务。
服务端代码:
- <span style="white-space:pre"> </span>public static void main(String[] args) throws IOException {
- int port = 8080;
- if (args != null && args.length > 0) {
- try {
- port = Integer.valueOf(args[0]);
- } catch (NumberFormatException e) {
- // 采用默认值
- }
- }
- ServerSocket server = null;
- try {
- server = new ServerSocket(port);
- System.out.println("The time server is start in port : " + port);
- Socket socket = null;
- while (true) {
- socket = server.accept();
- new Thread(new TimeServerHandler(socket)).start();
- }
- } finally {
- if (server != null) {
- System.out.println("The time server close");
- server.close();
- server = null;
- }
- }
- }
TimeServerHandler代码:
- public class TimeServerHandler implements Runnable {
- private Socket socket;
- public TimeServerHandler(Socket socket) {
- this.socket = socket;
- }
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run() {
- BufferedReader in = null;
- PrintWriter out = null;
- try {
- in = new BufferedReader(new InputStreamReader(
- this.socket.getInputStream()));
- out = new PrintWriter(this.socket.getOutputStream(), true);
- String currentTime = null;
- String body = null;
- while (true) {
- body = in.readLine();
- if (body == null)
- break;
- System.out.println("The time server receive order : " + body);
- currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new java.util.Date(
- System.currentTimeMillis()).toString() : "BAD ORDER";
- out.println(currentTime);
- }
- } catch (Exception e) {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- }
- if (out != null) {
- out.close();
- out = null;
- }
- if (this.socket != null) {
- try {
- this.socket.close();
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- this.socket = null;
- }
- }
- }
- }
客户端代码:
- <span style="white-space:pre"> </span>public static void main(String[] args) {
- int port = 8080;
- if (args != null && args.length > 0) {
- try {
- port = Integer.valueOf(args[0]);
- } catch (NumberFormatException e) {
- // 采用默认值
- }
- }
- Socket socket = null;
- BufferedReader in = null;
- PrintWriter out = null;
- try {
- socket = new Socket("127.0.0.1", port);
- in = new BufferedReader(new InputStreamReader(
- socket.getInputStream()));
- out = new PrintWriter(socket.getOutputStream(), true);
- out.println("QUERY TIME ORDER");
- System.out.println("Send order 2 server succeed.");
- String resp = in.readLine();
- System.out.println("Now is : " + resp);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (out != null) {
- out.close();
- out = null;
- }
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- in = null;
- }
- if (socket != null) {
- try {
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- socket = null;
- }
- }
- }
2.2伪异步I/O编程
在BIO的基础上进行优化,后端通过一个线程池来处理多个客户端的请求接入,通过线程池可以灵活的调配线程资源,设置线程的最大值,防止由于海量并发接入导致线程耗尽。
服务端代码:
- public static void main(String[] args) throws IOException {
- int port = 8080;
- if (args != null && args.length > 0) {
- try {
- port = Integer.valueOf(args[0]);
- } catch (NumberFormatException e) {
- // 采用默认值
- }
- }
- ServerSocket server = null;
- try {
- server = new ServerSocket(port);
- System.out.println("The time server is start in port : " + port);
- Socket socket = null;
- TimeServerHandlerExecutePool singleExecutor = new TimeServerHandlerExecutePool(
- 50, 10000);// 创建IO任务线程池
- while (true) {
- socket = server.accept();
- singleExecutor.execute(new TimeServerHandler(socket));
- }
- } finally {
- if (server != null) {
- System.out.println("The time server close");
- server.close();
- server = null;
- }
- }
- }
连接池代码:
- public class TimeServerHandlerExecutePool {
- private ExecutorService executor;
- public TimeServerHandlerExecutePool(int maxPoolSize, int queueSize) {
- executor = new ThreadPoolExecutor(Runtime.getRuntime()
- .availableProcessors(), maxPoolSize, 120L, TimeUnit.SECONDS,
- new ArrayBlockingQueue<java.lang.Runnable>(queueSize));
- }
- public void execute(java.lang.Runnable task) {
- executor.execute(task);
- }
- }
优点:避免了为每个请求都创建一个独立线程造成的线程资源耗尽问题。
缺点:但是由于它底层的通信依然采用同步阻塞模型,因此无法从跟本上解决问题。
2.3 NIO编程
NIO为New I/O的简称,也是非阻塞I/O。
INO提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。这两种新增的通道都支持阻塞和非阻塞两种模式。开发人员可以根据自己需求选择合适的模式。一般来说,低负载,低并发的应用程序可以选择同步阻塞I/O以降低编程复杂度,但是对于高负载,高并发的网络应用,需要使用NIO的非阻塞模式进行开发。
2.3.1 NIO类库解析
1.缓冲区Buffer
最常用的缓冲区为ByteBuffer,提供了一组功能用于操作数组。除此之外,还有CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer,DoubleBuffer。
2.通道Channel
是一个通道,主要通过它读取和写入数据。
Channel主要分为网络读写SelectableChannel和文件操作FileChannel
Netty主要涉及ServerSocketChannel和SocketChannel都是SelectableChannel的子类
3.多路复用器Selector
不断的扫描新的TCP连接接入、读和写事件的Channel,如果有,Channel就会处于就绪状态,被Selector轮询出来,然后通过selectionKey可以获取就绪Channel的集合,进行后续的I/O操作。
2.3.2 NIO源码
1.服务端代码
- public static void main(String[] args) throws IOException {
- int port = 8080;
- if (args != null && args.length > 0) {
- try {
- port = Integer.valueOf(args[0]);
- } catch (NumberFormatException e) {
- // 采用默认值
- }
- }
- MultiplexerTimeServer timeServer = new MultiplexerTimeServer(port);
- new Thread(timeServer, "NIO-MultiplexerTimeServer-001").start();
2.MultiplexerTimeServer类
- public class MultiplexerTimeServer implements Runnable {
- private Selector selector;
- private ServerSocketChannel servChannel;
- private volatile boolean stop;
- /**
- * 初始化多路复用器、绑定监听端口
- *
- * @param port
- */
- public MultiplexerTimeServer(int port) {
- try {
- selector = Selector.open();
- servChannel = ServerSocketChannel.open();
- servChannel.configureBlocking(false);
- servChannel.socket().bind(new InetSocketAddress(port), 1024);
- servChannel.register(selector, SelectionKey.OP_ACCEPT);
- System.out.println("The time server is start in port : " + port);
- } catch (IOException e) {
- e.printStackTrace();
- System.exit(1);
- }
- }
- public void stop() {
- this.stop = true;
- }
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run() {
- while (!stop) {
- try {
- selector.select(1000);
- Set<SelectionKey> selectedKeys = selector.selectedKeys();
- Iterator<SelectionKey> it = selectedKeys.iterator();
- SelectionKey key = null;
- while (it.hasNext()) {
- key = it.next();
- it.remove();
- try {
- handleInput(key);
- } catch (Exception e) {
- if (key != null) {
- key.cancel();
- if (key.channel() != null)
- key.channel().close();
- }
- }
- }
- } catch (Throwable t) {
- t.printStackTrace();
- }
- }
- // 多路复用器关闭后,所有注册在上面的Channel和Pipe等资源都会被自动去注册并关闭,所以不需要重复释放资源
- if (selector != null)
- try {
- selector.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- private void handleInput(SelectionKey key) throws IOException {
- if (key.isValid()) {
- // 处理新接入的请求消息
- if (key.isAcceptable()) {
- // Accept the new connection
- ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
- SocketChannel sc = ssc.accept();
- sc.configureBlocking(false);
- // Add the new connection to the selector
- sc.register(selector, SelectionKey.OP_READ);
- }
- if (key.isReadable()) {
- // Read the data
- SocketChannel sc = (SocketChannel) key.channel();
- ByteBuffer readBuffer = ByteBuffer.allocate(1024);
- int readBytes = sc.read(readBuffer);
- if (readBytes > 0) {
- readBuffer.flip();
- byte[] bytes = new byte[readBuffer.remaining()];
- readBuffer.get(bytes);
- String body = new String(bytes, "UTF-8");
- System.out.println("The time server receive order : "
- + body);
- String currentTime = "QUERY TIME ORDER"
- .equalsIgnoreCase(body) ? new java.util.Date(
- System.currentTimeMillis()).toString()
- : "BAD ORDER";
- doWrite(sc, currentTime);
- } else if (readBytes < 0) {
- // 对端链路关闭
- key.cancel();
- sc.close();
- } else
- ; // 读到0字节,忽略
- }
- }
- }
- private void doWrite(SocketChannel channel, String response)
- throws IOException {
- if (response != null && response.trim().length() > 0) {
- byte[] bytes = response.getBytes();
- ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
- writeBuffer.put(bytes);
- writeBuffer.flip();
- channel.write(writeBuffer);
- }
- }
- }
3.客户端代码
- public static void main(String[] args) {
- int port = 8080;
- if (args != null && args.length > 0) {
- try {
- port = Integer.valueOf(args[0]);
- } catch (NumberFormatException e) {
- // 采用默认值
- }
- }
- new Thread(new TimeClientHandle("127.0.0.1", port), "TimeClient-001")
- .start();
- }
4.TimeClientHandle类
- public class TimeClientHandle implements Runnable {
- private String host;
- private int port;
- private Selector selector;
- private SocketChannel socketChannel;
- private volatile boolean stop;
- public TimeClientHandle(String host, int port) {
- this.host = host == null ? "127.0.0.1" : host;
- this.port = port;
- try {
- selector = Selector.open();
- socketChannel = SocketChannel.open();
- socketChannel.configureBlocking(false);
- } catch (IOException e) {
- e.printStackTrace();
- System.exit(1);
- }
- }
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run() {
- try {
- doConnect();
- } catch (IOException e) {
- e.printStackTrace();
- System.exit(1);
- }
- while (!stop) {
- try {
- selector.select(1000);
- Set<SelectionKey> selectedKeys = selector.selectedKeys();
- Iterator<SelectionKey> it = selectedKeys.iterator();
- SelectionKey key = null;
- while (it.hasNext()) {
- key = it.next();
- it.remove();
- try {
- handleInput(key);
- } catch (Exception e) {
- if (key != null) {
- key.cancel();
- if (key.channel() != null)
- key.channel().close();
- }
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(1);
- }
- }
- // 多路复用器关闭后,所有注册在上面的Channel和Pipe等资源都会被自动去注册并关闭,所以不需要重复释放资源
- if (selector != null)
- try {
- selector.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- private void handleInput(SelectionKey key) throws IOException {
- if (key.isValid()) {
- // 判断是否连接成功
- SocketChannel sc = (SocketChannel) key.channel();
- if (key.isConnectable()) {
- if (sc.finishConnect()) {
- sc.register(selector, SelectionKey.OP_READ);
- doWrite(sc);
- } else
- System.exit(1);// 连接失败,进程退出
- }
- if (key.isReadable()) {
- ByteBuffer readBuffer = ByteBuffer.allocate(1024);
- int readBytes = sc.read(readBuffer);
- if (readBytes > 0) {
- readBuffer.flip();
- byte[] bytes = new byte[readBuffer.remaining()];
- readBuffer.get(bytes);
- String body = new String(bytes, "UTF-8");
- System.out.println("Now is : " + body);
- this.stop = true;
- } else if (readBytes < 0) {
- // 对端链路关闭
- key.cancel();
- sc.close();
- } else
- ; // 读到0字节,忽略
- }
- }
- }
- private void doConnect() throws IOException {
- // 如果直接连接成功,则注册到多路复用器上,发送请求消息,读应答
- if (socketChannel.connect(new InetSocketAddress(host, port))) {
- socketChannel.register(selector, SelectionKey.OP_READ);
- doWrite(socketChannel);
- } else
- socketChannel.register(selector, SelectionKey.OP_CONNECT);
- }
- private void doWrite(SocketChannel sc) throws IOException {
- byte[] req = "QUERY TIME ORDER".getBytes();
- ByteBuffer writeBuffer = ByteBuffer.allocate(req.length);
- writeBuffer.put(req);
- writeBuffer.flip();
- sc.write(writeBuffer);
- if (!writeBuffer.hasRemaining())
- System.out.println("Send order 2 server succeed.");
- }
- }
2.4 AIO编程
JDK7的产物,即NIO2.0。
1.服务端代码
- public class TimeServer {
- /**
- * @param args
- * @throws IOException
- */
- public static void main(String[] args) throws IOException {
- int port = 8080;
- if (args != null && args.length > 0) {
- try {
- port = Integer.valueOf(args[0]);
- } catch (NumberFormatException e) {
- // 采用默认值
- }
- }
- AsyncTimeServerHandler timeServer = new AsyncTimeServerHandler(port);
- new Thread(timeServer, "AIO-AsyncTimeServerHandler-001").start();
- }
- }
2.AsyncTimeServerHandler类
- public class AsyncTimeServerHandler implements Runnable {
- private int port;
- CountDownLatch latch;
- AsynchronousServerSocketChannel asynchronousServerSocketChannel;
- public AsyncTimeServerHandler(int port) {
- this.port = port;
- try {
- asynchronousServerSocketChannel = AsynchronousServerSocketChannel
- .open();
- asynchronousServerSocketChannel.bind(new InetSocketAddress(port));
- System.out.println("The time server is start in port : " + port);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run() {
- latch = new CountDownLatch(1);
- doAccept();
- try {
- latch.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- public void doAccept() {
- asynchronousServerSocketChannel.accept(this,
- new AcceptCompletionHandler());
- }
- }
3.AcceptCompletionHandler类
- public class AcceptCompletionHandler implements
- CompletionHandler<AsynchronousSocketChannel, AsyncTimeServerHandler> {
- @Override
- public void completed(AsynchronousSocketChannel result,
- AsyncTimeServerHandler attachment) {
- attachment.asynchronousServerSocketChannel.accept(attachment, this);
- ByteBuffer buffer = ByteBuffer.allocate(1024);
- result.read(buffer, buffer, new ReadCompletionHandler(result));
- }
- @Override
- public void failed(Throwable exc, AsyncTimeServerHandler attachment) {
- exc.printStackTrace();
- attachment.latch.countDown();
- }
- }
4.ReadCompletionHandler类
- public class ReadCompletionHandler implements
- CompletionHandler<Integer, ByteBuffer> {
- private AsynchronousSocketChannel channel;
- public ReadCompletionHandler(AsynchronousSocketChannel channel) {
- if (this.channel == null)
- this.channel = channel;
- }
- @Override
- public void completed(Integer result, ByteBuffer attachment) {
- attachment.flip();
- byte[] body = new byte[attachment.remaining()];
- attachment.get(body);
- try {
- String req = new String(body, "UTF-8");
- System.out.println("The time server receive order : " + req);
- String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(req) ? new java.util.Date(
- System.currentTimeMillis()).toString() : "BAD ORDER";
- doWrite(currentTime);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- }
- private void doWrite(String currentTime) {
- if (currentTime != null && currentTime.trim().length() > 0) {
- byte[] bytes = (currentTime).getBytes();
- ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
- writeBuffer.put(bytes);
- writeBuffer.flip();
- channel.write(writeBuffer, writeBuffer,
- new CompletionHandler<Integer, ByteBuffer>() {
- @Override
- public void completed(Integer result, ByteBuffer buffer) {
- // 如果没有发送完成,继续发送
- if (buffer.hasRemaining())
- channel.write(buffer, buffer, this);
- }
- @Override
- public void failed(Throwable exc, ByteBuffer attachment) {
- try {
- channel.close();
- } catch (IOException e) {
- // ingnore on close
- }
- }
- });
- }
- }
- @Override
- public void failed(Throwable exc, ByteBuffer attachment) {
- try {
- this.channel.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
5.客户端代码
- public class TimeClient {
- /**
- * @param args
- */
- public static void main(String[] args) {
- int port = 8080;
- if (args != null && args.length > 0) {
- try {
- port = Integer.valueOf(args[0]);
- } catch (NumberFormatException e) {
- // 采用默认值
- }
- }
- new Thread(new AsyncTimeClientHandler("127.0.0.1", port),
- "AIO-AsyncTimeClientHandler-001").start();
- }
- }
6.AsyncTimeClientHandler
- public class AsyncTimeClientHandler implements
- CompletionHandler<Void, AsyncTimeClientHandler>, Runnable {
- private AsynchronousSocketChannel client;
- private String host;
- private int port;
- private CountDownLatch latch;
- public AsyncTimeClientHandler(String host, int port) {
- this.host = host;
- this.port = port;
- try {
- client = AsynchronousSocketChannel.open();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void run() {
- latch = new CountDownLatch(1);
- client.connect(new InetSocketAddress(host, port), this, this);
- try {
- latch.await();
- } catch (InterruptedException e1) {
- e1.printStackTrace();
- }
- try {
- client.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void completed(Void result, AsyncTimeClientHandler attachment) {
- byte[] req = "QUERY TIME ORDER".getBytes();
- ByteBuffer writeBuffer = ByteBuffer.allocate(req.length);
- writeBuffer.put(req);
- writeBuffer.flip();
- client.write(writeBuffer, writeBuffer,
- new CompletionHandler<Integer, ByteBuffer>() {
- @Override
- public void completed(Integer result, ByteBuffer buffer) {
- if (buffer.hasRemaining()) {
- client.write(buffer, buffer, this);
- } else {
- ByteBuffer readBuffer = ByteBuffer.allocate(1024);
- client.read(
- readBuffer,
- readBuffer,
- new CompletionHandler<Integer, ByteBuffer>() {
- @Override
- public void completed(Integer result,
- ByteBuffer buffer) {
- buffer.flip();
- byte[] bytes = new byte[buffer
- .remaining()];
- buffer.get(bytes);
- String body;
- try {
- body = new String(bytes,
- "UTF-8");
- System.out.println("Now is : "
- + body);
- latch.countDown();
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void failed(Throwable exc,
- ByteBuffer attachment) {
- try {
- client.close();
- latch.countDown();
- } catch (IOException e) {
- // ingnore on close
- }
- }
- });
- }
- }
- @Override
- public void failed(Throwable exc, ByteBuffer attachment) {
- try {
- client.close();
- latch.countDown();
- } catch (IOException e) {
- // ingnore on close
- }
- }
- });
- }
- @Override
- public void failed(Throwable exc, AsyncTimeClientHandler attachment) {
- exc.printStackTrace();
- try {
- client.close();
- latch.countDown();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
2.5 4中I/O对比
Netty权威指南(笔记一)的更多相关文章
- Netty权威指南
Netty权威指南(异步非阻塞通信领域的经典之作,国内首本深入剖析Netty的著作,全面系统讲解原理.实战和源码,带你完美进阶Netty工程师.) 李林锋 著 ISBN 978-7-121-233 ...
- Struts2权威指南笔记
Struts2权威指南笔记 1.mvc特点包括: ① 多个视图可以对应一个模型 ② 模型返回的数据与显示逻辑分离 ③ 应用层被分隔为三层,降低了各层之间的耦合,提供了应用的可扩展性 ④ 控制层的概念也 ...
- 《Netty权威指南》
<Netty权威指南> 基本信息 作者: 李林锋 出版社:电子工业出版社 ISBN:9787121233432 上架时间:2014-5-29 出版日期:2014 年6月 开本:16开 页码 ...
- 《Netty 权威指南(第2 版)》目录
图书简介:<Netty 权威指南(第2 版)>是异步非阻塞通信领域的经典之作,基于最新版本的Netty 5.0 编写,是国内很难得一见的深入介绍Netty 原理和架构的书籍,也是作者多年实 ...
- netty权威指南学习笔记六——编解码技术之MessagePack
编解码技术主要应用在网络传输中,将对象比如BOJO进行编解码以利于网络中进行传输.平常我们也会将编解码说成是序列化/反序列化 定义:当进行远程跨进程服务调用时,需要把被传输的java对象编码为字节数组 ...
- netty权威指南学习笔记二——netty入门应用
经过了前面的NIO基础知识准备,我们已经对NIO有了较大了解,现在就进入netty的实际应用中来看看吧.重点体会整个过程. 按照权威指南写程序的过程中,发现一些问题:当我们在定义handler继承Ch ...
- netty权威指南学习笔记八——编解码技术之JBoss Marshalling
JBoss Marshalling 是一个java序列化包,对JDK默认的序列化框架进行了优化,但又保持跟java.io.Serializable接口的兼容,同时增加了一些可调参数和附加特性,这些参数 ...
- netty权威指南学习笔记七——编解码技术之GoogleProtobuf
首先我们来看一下protobuf的优点: 谷歌长期使用成熟度高: 跨语言支持多种语言如:C++,java,Python: 编码后消息更小,更利于存储传输: 编解码性能高: 支持不同协议版本的兼容性: ...
- netty权威指南学习笔记五——分隔符和定长解码器的应用
TCP以流的方式进行数据传输,上层应用协议为了对消息进行区分,通常采用以下4中方式: 消息长度固定,累计读取到长度综合为定长LEN的报文后,就认为读取到了一个完整的消息,将计数器置位,重新开始读取下一 ...
随机推荐
- jQuery validator plugin之概要
jQuery validator 主页 github地址 demo学习 效果: Validate forms like you've never validated before! 自定义Valida ...
- Go 使用 JSON
Encode 将一个对象编码成 JSON 数据,接受一个 interface{} 对象,返回 []byte 和 err func Marshal(v interface{}) {[]byte,err} ...
- E: Unable to locate package git
git can’t install 报错信息: root@281eef85bb5d:~# apt-get install git Reading package lists... Done Build ...
- js +与?优先级
var val = 'smtg'; console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing'); // A. Value ...
- JAVA-抽象类/类继承
1.当一个类继承一个抽象类的时候,必须实现抽象类的方法.如果子类没有实现父类的抽象方法,则必须将子类也定义为abstract类. 2.被final修饰的类为最终类,不能被继承.而类前面如果有abstr ...
- eclipse get set 自动添加注释
编码的时候通常要用到 JavaBean ,而在我们经常把注释写在字段上面,但生成的Get/Set方法不会生成,通过修改Eclipse源码可解决,直接上例子: /** * 员工ID */ private ...
- 『TensotFlow』转置卷积
网上解释 作者:张萌链接:https://www.zhihu.com/question/43609045/answer/120266511来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业 ...
- 【Java】【9】String Date Calendar之间的转换
前言: 1, Calendar 转化 String 2, Calendar 转化 Date 3,Date 转化 String 4,Date 转化 Calendar 5,String 转化 Calend ...
- 一个二维码如何自动识别是安卓(Android)还是苹果(IOS)
思考问题: 通常,我们开发一个APP,有Android版本.IOS版本. 但是只有一个二维码?怎么办呢? 怎么让IOS用户扫描二维码下载IOS版本,Android用户扫描二维码下载到Android版本 ...
- Oracle数据库联机重定义讲解及错误处理
1.1. 关键字:联机重定义/SYNC_INTERIM_TABLE/GATHER_TABLE_STATS 1.2. 需求:数据表的清理机制需要优化 离线消息表采用delete的方式定期对过期的数据进行 ...