第一章 《Java SE8 流库》
1.从迭代到流的操作
- 流操作比迭代操作更易读
- 将stream改为parallelStream就可以让流库进行并行的操作
- 流不储存其元素
- 流的操作不会修改其数据源
- 流的操作是尽可能惰性执行的
- 可以使用Collection接口的stream方法将任何集合转换成一个流,也可以通过Stream.of方法来将数组转换成一个流,并且of方法具有可变长参数
- Array.stream(array,from,to)可以从数组中位于from(包括)和to(不包括)的元素中创建一个流
- Array.empty()可以创建不包含任何元素的流
- Stream接口有两个创建无限流的静态方法,generate方法和iterate方法
- generate可以接受一个Supplier<T>接口的对象
- iterate可以接受一个种子值和一个UnaryOperation<T>接口的对象
3.filter、map和flatMap方法
- filter的引元是Predicate<T>,即从T到boolean的函数
- 在使用map方法时,会有一个函数应用到每个元素上,并且其结果是包含了应用该函数后所产生的所有结果的流
- flatMap可以将流中所有的元素所产生的结果拼接到一起
4.抽取子流和连接流
- stream.list(n)会返回一个新的流,它在n个元素之后结束
- stream.skip(n)丢弃前n个元素
- 静态的concat方法可以将两个流连接起来
5.其他的流转换
- distinct方法会返回一个流,它的元素是从原有流产生,即原来的元素按照同样的顺序剔除重复元素后产生
- 流的排序可以通过sorted方法的变体实现
- peek方法会产生一个流,它的元素与原来流中的元素相同,但是在每次获取一个元素时,都会调用一个函数
6.简单约简
- 约简是一种终结操作,它们会将流约简为可以在程序中使用的非流值
- count方法会返回流中元素的数量,max和min会返回最大值和最小值,返回类型是Optional<T>
- findFirst返回的是非空集合中的第一个值,它通常会在与filter组合使用时很有用
- 如果不强调使用第一个匹配,而是任意的匹配都可以,那么可以使用findAny方法
- allMatch和noneMatch方法,它们会在所有元素和没任何元素匹配断言的情况下返回true
7.Optional类型
- Optional<T>对象是一种包装类对象,要么包装了类型T的对象,要么没有包装任何对象
- 它在值不存在的情况下会产生一个替代物,而只有在值存在的情况下才会使用这个值
- ifPresent方法会接受一个函数,如果该可选值存在,那么就会被传递给该函数,否则,不会发生任何事情
- get方法会在Optional值存在的情况下获得其中包装的元素,或者在不存在的情况下抛出一个NoSuchElementException对象
- 可以通过Optional.of(result)或者Optional.empty方法来创建Optional对象
- 可以用flatMap来构建Optional值的函数
8.收集结果
- 可以调用iterator产生可以访问元素的迭代器或者调用forEach方法
- 在并行流中,forEach方法以任意书怒遍历各个元素,如果想要按照流中顺序来处理,可以调用forEachOrdered方法,但这个方法会丧失并行处理的部分甚至全部优势
- 也可以调用toArray方法获得由流的元素构成的数组
- 针对将流中的元素收集到另一个目标中,有一个便捷方法collect可用,它会接受一个Collector接口的实例
9.收集到映射表中
- Collectors.toMap方法有两个引元,用来产生映射表的键和值,如果有很多元素有相同的键,就会抛出IllegalStateException的异常,可以通过第三个函数引元来覆盖这种行为,如果想要得到TreeMap,那么可以将构造器作为第四个引元来提供
10.群组和分区
- 将具有相同特效的值群聚成组是非常常见的,并且goupingBy方法直接就支持它
- 当分类函数是断言函数时,流的元素可以分区为两个列表:该函数返回true的元素和其他元素,在这种情况下,使用partitioningBy比使用groupingBy要更高效
- 如果调用groupingByConcurrent方法,就会在使用并行流时获得一个被并行组装的并行映射表,这与toConcurrentMap方法完全类似
11.下游收集器
- groupingBy方法会产生一个映射表,它的每个值都是一个列表,如果想要以某种方式处理这些列表,就需要提供一个“下游收集器”。
- mapping方法会产生将函数应用到下游结果上的收集器,并将函数值传递给另一个收集器
12.约简操作
- reduce方法是一种用于从流中计算某个值的通用机制,其最简单的形式将接受一个二元函数,并从前两个元素开始持续应用它
13.基本类型流
- 流库中有专门的类型IntStream、LongStream和DoubleStream,用来直接存储基本类型值,而无需使用包装器。如果想要存储short、char、byte和boolean,可以使用IntStream,而对于float,可以使用DoubleStream
- 创建IntStream需要调用IntStream.of和Arrays.stream方法
- 有静态的generate和iterate方法,此外,IntStream和LongStream有静态方法range和rangeClosed,可以生成步长为1的整数范围
14.并行流
- 可以用Collection.parallelStream()方法从任何集合中获取一个并行流
- 流应该可以被高效地分成若干个子部分
- 流操作的工作量应该具有较大的规模
- 流操作不应该被阻塞
第二章 《输入与输出》
1.输入/输出流
- 在Java API中,可以从其中读入一个字节序列的对象称作输入流,而可以向其中写入一个字节序列的对象称作输出流
- 抽象类InputStream和OutputStream构成了输入/输出类层次的结构
- 由于面向字节的流不便于处理以Unicode形式存储的信息,所以从抽象类Reader和Writer中继承出来了一个专门用于处理Unicode字符的单独的类层次结构,这些类拥有的读入与写出操作都是基于两字节的Char值的(Unicode码元),而不是基于byte值的
- InputStream类有一个抽象方法read(),读入一个字节,并返回读入的字节,或者在遇到输入源结尾时返回-1
- read和write方法在执行时都将阻塞,直至字节确实被读入或写出
- available方法可以让我们去检查当前可读入的字节数量
- 当完成读入或输出流时应调用close方法来关闭它
- 关闭一个输出流的同时还会冲刷用于该输出流的缓冲区:所有被临时置于缓冲区中,以便用更大的包的形式传递的字节在关闭输出流时都将被送出,此外,也可以利用flush方法来人为地冲刷这些输出
- 对于Unicode文本,可以使用抽象类Reader和Writer的子类,其中read方法可以返回一个Unicode码元,或者碰到文件结尾时返回-1
- FileInputStream和FileOutputStream可以提供附着在一个磁盘文件上的输入流和输出流
2.文本输入与输出
- 对于文本输出,可以使用PrintWriter,这个类拥有以文本格式打印字符串和数字的方法
- 可以使用Scanner类来读入文本,也可以使用BufferedReader来读取文本
- 常见的编码方式是UTF-8,它将每个Unicode编码点编码为1到4个字节的序列
3.读写二进制数据
- DataInput和DataOutput来读写二进制数据
- RandomAccessFile类可以在文件中的任何位置查找或写入数据
- 在JAVA中,可以使用ZipInputStream来读入ZIP文档
- getNextEntry方法就可以返回一个描述这些项的ZipEntry类型的对象,向ZipInputStream的getInputStream方法传递该项可以获取用于读取该项的输入流,然后调用closeEntry来读入下一项
- 而写出Zip文件,就使用ZipOutputStream,并调用putNextEntry方法来开始写出新文件
4.对象输入/输出流与序列化
- 使用ObjectOutputStream和ObjectInputStream来输出和输入对象流,通过调用writeObject方法和readObject方法
- 对象输出流和输入流中都必须实现Serializable接口,接口中没有任何方法
- 每个对象都是用一个序列号保存的
- 指纹是通过对类、超类、接口、域类型和方法签名按照规范方式排序,然后将安全散列算法(SHA)应用于这些数据而获得的
- 标记为transient的域在对象被序列化时总是被跳过的
- 即使对象的构造器是私有的,序列化机制也可以创建新的对象,因此可以使用readResolve的特殊序列化方法
- 如果一个类具有名为serialVersionUID的静态数据成员,就不再需要人工地计算其指纹,而只需直接使用这个值
- 为克隆使用序列化:直接将对象序列化到输出流中,然后将其都会,这样产生的新对象是对现有对象的一个深拷贝,使用ByteArrayOutStream将数据保存到字节数组中
5.操作文件
- Path和Files类封装了在用户机器上处理文件系统所需的所有功能
- Path.get方法接受一个或多个字符串,并将他们用默认文件系统的路径分隔符连接起来
- p.resolve(q),如果q是绝对路径,则结果就是q,否则根据文件系统规则,将“p后面跟着q”作为结果
- 可以使用new Scanner(Path)或者调用toFile方法访问文件
- Files可以让普通文件的操作变得便捷:包括创建目录(createDirectory),复制(copy),移动(move)
- 静态的Files.list方法会返回一个可以读取目录中各个项的Stream<Path>对象
- Files.walk方法会产生一个可以遍历目录中所有子孙的Stream<Path>对象
- 可以使用glob模式来过滤文件
- Paths类会在默认文件系统中查找路径,即在用户本地磁盘中的文件
6.内存映射文件
- java.nio包使得内存映射变得简单,首先,从文件中获得一个通道,然后调用FileChannel类的map方法从这个通道中获得一个ByteBuffer,一旦有了缓冲区,就可以使用ByteBuffer类和Buffer超类的方法读写数据了
- 有三种映射模式:READ_ONLY,READ_WRITE,PRIVATE
- Buffer类是一个抽象类,有许多子类,但StringBuffer与这些缓冲区没有关系
- 要锁定一个文件,可以调用FileChannel类的lock或tryLock方法,其中参数shared是共享锁开关
- 在某些系统中,文件加锁仅仅是建议性的,如果一个应用未能得到锁,它依旧可以被另一个应用并发锁定的文件执行写操作
- 在某些系统中,不能在锁定一个文件的同时将其映射到内存中
- 文件锁是由整个Java虚拟机持有的
- 在一些系统中,关闭一个通道会释放由Java虚拟机持有的底层文件上的所有锁
- 在网络文件系统上锁定文件是高度依赖于系统的,应尽量避免
7.正则表达式(这部分与其他语言类似,详细可以看原文)
第三章 《XML》
1.XML概述
- 与HTML不同,XML是大小敏感的
- XML中结束标签绝对不能省略
- XML中,只有单个标签而没有相对应的结束标签的元素必须以/结尾
- XML中,属性值必须用引号括起来
- XML所有属性必须都有属性值
- XML文档应当以一个文档头开始,但是可选的
- XML文档的正文包含根元素,根原包含其他元素,元素可以有子元素、文本或两者皆有
- 属性应该只用来修改值的解释,而不是用来制定值
- 字符引用的形式是&#十进制值或十六进制值
- 实体引用的形式是&name
- CDATA部分用<![cdata[ ]]>来限定其界限
- 处理指令是那些专门在处理XML文档的应用程序中使用的指令,它们由<?和?>来限定其界限
- 注释用<!-和-->限定其界限
2.解析XML文档
- 像文档对象模型解析器这样的树型解析器,它们将读入的XML文档转换成树结构
- 像XML简单API解析器这样的流机制解析器,它们在读入XML文档时生成相应的事件
3.验证XML文档(内容较多,建议看原文)
- 如果要指定文档结构,可以提供一个文档类型定义(DTD)或一个XML Schema定义
- XML Schema比起DTD语法更复杂,Schema为每个元素都定义了类型,类型可以是简单类型,即有格式限制的字符串,或者是复杂类型
4.使用XPath来定位信息(具体看原文)
- XPath语言使得访问树节点变得很容易
5.使用命名空间
- XML也有类似的命名空间机制,可以用于元素名和属性名
- 命名空间是由统一资源标识符(URI)来标识的
- 每个节点有三个属性:带有前缀 限定名,由getNodeName和getTagName等方法返回
- 命名空间URI,由getNamespaceURI方法返回
- 不带前缀和命名空间的本地名,由getLocalName方法返回
6.流机制解析器
- 如果文档很大,处理算法又很简单,可以在运行时解析节点而不必看到完整的树形结构,那么DOM可能会显得效率低下了,这种情况下,可以使用流机制解析器
- SAX解析器使用的是事件回调,而StAX解析器提供了遍历解析事件的迭代器
- 事实上,DOM解析器是在SAX解析器的基础上构建的,它在接收到解析器事件时构建DOM树
- 在使用SAX解析器时,需要一个处理器来为各种解析器事件定义事件动作
- startElement和endElement在每当遇到起始或终止标签时调用
- characters在每当遇到字符数据时调用
- startDocument和endDocument分别在文档开始和结束时调用一次
- StAX解析器是一种“拉解析器”,与安装事件处理器不同,你只需使用基本循环来迭代所有的事件
7.生成XML文档
- 通过调用DocumentBuilder类的newDocument方法可以得到一个空文档
- 使用Document类的createElement方法可以构建文档里的元素
- 带有命名空间的XML生成看原文
8.XSL转换(建议看原文)
- XSL转换机制可以指定将XML文档转换为其他格式的规则
第四章 《网络》
1.连接到服务器
- 可以在shell中输入telnet来启动telnet,从而远程连接服务器
- 也可以用java(socket编程)连接服务器
- 实例化Socket对象来创建套接字,然后通过getInputStream来得到一个InputStream对象来获取这个流
- setSoTimeout方法可以设置超时时间,并如果超时就会抛出SocketTimeoutException
- 不用过多考虑英特网地址问题,只要主机操作系统支持IPv6格式的因特网地址,java.net包也将支持它
- 一些访问量较大的主机名通常会对应于多个因特网地址
2.实现服务器
- ServerSocket类用于创建服务器程序套接字
- accept()方法让程序不停等待,直到有客户端连接到这个端口
- 为了实现多个客户端访问,每当程序建立一个新的套接字连接,将会启动一个新的线程爱处理服务器和该客户端之间的连接
- ThreadedEchoHandler类实现了Runnable接口,而且在它的run方法中包含了与客户端循环 通信的代码
- 半关闭提供了这样一种能力:套接字连接的一端可以终止其输出,同时仍旧可以接受来自另一端的数据
3.可中断套接字
- 当连接到一个套接字时,当前线程将会被阻塞直到建立连接或产生超时为止
- 为了中断套接字操作,可以使用java.nio包提供的一个特效——SocketChannel类。其中,通道channel的read和write方法都是通过使用Buffer对象来实现的
4.获取Web数
- URI是个纯粹的语法结构,包含用来指定Web资源的字符串的各种组成部分
- URL是URI的一个特例,它包含了用于定位Web资源的足够信息
- 在java类库中,URI类并不包含任何用于访问资源的方法,唯一作用是解析,URL类可以打开一个到达资源的流
- 包含scheme: 部分的URI称为绝对URI,否则,称为相对URI,如果绝对URI的schemeSpecificPart不是以/开头的,我们就称它是不透明的
- 所有绝对的透明URI和所有相对URI都是分层的
- 操作URL对象步骤:(1)调用URL类中的openConnectipon方法获得URLConnection对象 (2)使用以下方法拉设置任意的请求属性 (3)调用connect方法连接远程资源 (4)与服务器建立连接后,查询头信息 (5)最后,访问资源数据
- 有许多技术可以让Web服务器实现对程序的调用,其中最广为人知的是Java Servlet,JavaServer Face,微软的ASP以及CGI脚本
- 在向Web服务器发送消息时,通常有两个命令被用到:GET和POST,如果是GET命令,只需要将参数附在URL的结尾处,其中,每个参数都具有“名字=值”的形式,参数之间用&隔开。而如果在POST请求中,我们不在URL上附着参数,而是从URLConnection中获得输出流,并将名/值对写入到该输出流中,并用&隔开
- 由于安全问题,在HTTP和HTTPS之间的重定向不被支持
5.发送E-mail(内容较少,见原文)
第五章 《数据库编程》
1.JDBC的设计
- 通过使用标准的SQL语句,甚至是专门的SQL扩展,程序员就可以利用Java语言开发访问数据库的应用,同时还遵守Java语言的相关约定
- 数据库供应商和数据库工具开发商可以提供底层的驱动程序
- 如今三层模型更常见。在三层应用模型中,客户端不直接调用数据库,而是调用服务器上的中间件层,由中间件层完成数据库查询操作。这样的架构可以将可视化表示(客户端)从业务逻辑(位于中间层)和原始数据(数据库)中分离出来
2.结构化查询语言(这部分建议去查相关资料,原文简单说了一下)
3.JDBC配置
- 在连接数据库时,我们必须使用各种与数据库类型相关的参数,例如主机名、端口号和数据库名
- 需要获取数据库的驱动程序的JAR文件
- 启动数据库的步骤基本在终端输入相应启动命令即可
- 如果驱动程序JAR文件不支持自动注册,就需要找出数据库提供商使用的JDBC驱动器类的名字
- 通过使用DriverManager,可以用两种方式来注册驱动器。一种方式是在java程序中加载驱动器类。另一种方式是设置jdbc.drivers属性
- 通过DriverManager的getConnection方法返回一个Connection对象(输入url,username,password)连接成功后执行SQL语句
4.使用JDBC语句
- 执行SQL语句之前,要创建一个Statement对象,然后调用execute相应方法
- 执行executeQuery语句会返回一个ResultSet类型的对象
- 每个Connection对象都可以创建一个或多个Statement对象,同一个Statement对象可以用于多个不想管的命令和查询
- 每个SQLException都有一个由多个SQLException对象构成的链,这些对象可以通过getNextException方法获取。这个异常链是每个异常都具有的由Throwable对象构成的“成因”链之外的异常链
- SQLWarning类是SQLException的子类
- 数据库执行语句操作:(1)连接数据库 (2)使用SQL语句打开文件 (3)使用泛化的execute方法执行每条语句 (4)如果产生结果集就打印出结果集 (5)如果运行过程中出现SQL异常,则打印相关异常 (6)关闭数据库连接
5.执行查询操作
- 在执行预备语句之前,必须使用set方法将变量绑定到实际的值上
- 储存大对象的形式,在SQL中,二进制大对象称为BLOB,字符型大对象称为CLOB
- “转义”语法是各种数据库普遍支持的特效,但是数据库使用的是与数据库相关的语法变体,因此,将转义语法转译为特定数据库的语法是JDBC驱动程序的任务之一
- 转译的主要应用场景:日期和时间字面常量、调用标量函数、调用存储过程、外连接和在LIKE子句中的转义字符
- 标量函数是指仅返回单个值的函数
- 存储过程是在数据库中执行的用数据库相关的语言编写的过程
- 两个标的外连接并不要求每个表的所有行都要根据连接条件进行匹配
- 获取所有结果集的步骤: (1)使用execute方法来执行SQL语句 (2)获取第一个结果集或更新计数 (3)重复调用getMoreResults方法以移动到下一个结果集 (4)当不存在更多的结果集或更新计数时,完成操作
6.可滚动和可更新的结果集(看原文,较为重要)
7.行集
- RowSet接口扩展ResultSet接口,却无需始终与数据库保持连接
8.元数据
- 在SQL中,描述数据库或其组成部分的数据称为元数据
9.事物(重要)
- 我们将一组语句构成一个事务。当所有语句都执行成功后,事务可以被提交。否则,进行回滚。这样做是为了确保数据库完整性
- 默认情况下,数据库连接处于自动提交模式,每个SQL语句一旦执行便提交数据库。因此,在使用事务时,需要关闭这个默认值
- 在使用默写驱动程序时,使用保存点可以更细粒度地控制回滚操作,创建一个保存点意味着稍后只需要返回到这个点而非事务的开头
- 在使用批量更新时,一个语句序列作为一批操作将被同时被收集和提交
*调用executeBatch方法将为所有已提交的语句返回一个记录数的数组
10.高级SQL类型(了解即可)
11.Web与企业应用中国的连接管理(了解即可)
第六章 《日期和时间API》
1.时间线
- 时间线远点为本初子午线所在时区的1970年1月1日的午夜,每天86400秒向前,精确到纳秒
- 静态方法调用Instant.now()会给出当前的时刻
- Duration是两个时刻之间的时间量
2.本地时间
- 本地时间/时期包含当天的时间和日期,但是与时区信息没有任何关联
- LocalDate是带有年、月、日的日期
- 而用于本地日期的等价物是Period,它表示的是流逝的年、月或日的数量
- util方法会产生两个本地日期之间的时长
3.日期调整器
- TemporalAdjusters类提供了大量用于常见调整的静态方法,可以将调整方法的结果传递给with方法
4.本地时间
- LocalTime表示当日时刻,可以用now或of方法创建其实例
- 还有一个表示日期和回见的LocalDateTime类,这个类适合存储固定时区的时间点
5.时区时间
- 互联网编码分配管理机构保存着一个数据库,里面储存着世界上所有已知的时区,它每年会更新数次,而批量更新会处理夏令时的变更规则,JAVA使用了IANA数据库
- 给定一个时区ID,静态方法ZoneId.of(id)可以产生一个ZoneId对象,可以通过调用local.atZone(zoneId)用这个对象将LocalDateTime对象转换为ZonedDateTime对象,或者可以调用静态方法ZonedDateTime.of()来构造一个对象
6.格式化和解析
- DateTImeFormatter类提供了三种用于打印日期/时间值的格式器:预定义的格式器、Locale相关的格式器、带有定制模式的格式器
7.与遗留代码的互操作(见原文表格)
第七章 《国际化》
1.Locale对象
- 为了对格式化进行控制,可以使用Locale类,locale由多达5个部分构成:一种语言、可选的一段脚本、可选的一个国家或地区、可选的一个变体、可选的一个扩展
- 静态的getAvailableLocale方法会返回由Java虚拟机所能够识别的所有Locale构成的数组
2.数字格式
- 对数字格式化的步骤:(1)使用上一节的方法得到Locate对象 (2)使用一个“工厂方法”得到一个格式器对象 (3)使用这个格式器对象来完成格式化和解析工作
3.货币
- 为了格式化货币值,可以使用NumberForat.getCurrencyInstance方法,但它返回的只针对一种货币的格式器,因此,可以使用Currency类来控制被格式器所处理的货币
4.日期和时间
- java.time包中的DateTimeFormatter类可以处理这些问题
5.排序和范化
- Collator类实现了Comparator接口,可以传递一个Collator对象给list.sort(Comparator)方法来对一组字符串进行排序,并且可以设置排序器的强度来选择不同的排序行为
6.消息格式化
- Java类库中有一个MessageFormat类,它支持Local,并且会对数字和日期格式化
7.文本文件和字符集
8.资源包
第八章 《脚本、编译与注解处理》
1.Java平台的脚本
- 脚本语言的优势:便于快速变更,鼓励不断试验;可以修改运行着的程序的行为;支持程序用户的定制化
- 脚本引擎是一个可以执行用某种特定语言编写的脚本的类库
- 一旦拥有了引擎,可以通过engine.eval()直接调用脚本
- 除了向引擎或全局作用添加绑定之外,还可以将绑定收集到一个类型为Bindings的对象中,然后将其传递给eval方法
- 可以通过脚本上下文的setReader和setWriter方法来重定向脚本的标准输入输出
- 在使用许多脚本引擎时,都可以调用脚本语言的函数,而不必对实际的脚本代码进行计算
*一旦脚本被编译,就可以执行它,如果不支持编译,就执行原始版本
2.编译器API
- 编译器会向提供给它的流发送输出和错误消息
- 使用CompilationTask对象来编译过程可以 控制程序需代码的来源、控制类文件的放置位置、监听在编译过程中产生的错误和警告信息和在后台运行编译器
- 为了监听错误消息,需要安装一个DiagnosticListener,这个监听器在编译器报告警告或错误消息时会收到一个Diagnostc对象
3.使用注解(非常重要,建议再找一些资料深入理解)
- 注解是那些插入到源代码中使用其他工具可以对其进行处理的标签
- 注解不会改变程序的编译方式
- 在Java中,注解是当做一个修饰符来使用的,每一个注解的名称前面都加上了@符号
- 注解自身不会做任何事情,它需要工具支持才会有用
- 注解可以定义成包含元素的形式,这些元素可以被读取这些注解的工具去处理
- @interface声明创建了一个真正的java接口
- @Target和@Retention是元注解
- 注解本身不会做任何事情,只是存在于源文件中,编译器将他们置于类文件中,并且虚拟机会将它们载入,我们需要做的是一个分析注解以及安装行为监听器的机制,这也是类ActionListenerInstaller的职责所在
4.注解语法
- 所有的注解接口都隐式地扩展自java.lang.nnotation.Annotation接口
- 如果注解中只有一个特殊名字value,没有其他指定元素,就可以忽略这个元素名以及等号
- 声明和类型用法声明注解可以出现在下列声明处:包、类、接口、方法、构造器、实例域、局部变量、参数变量和类型参数
5.标准注解
- @Deprecated注解可以被添加到任何不再鼓励使用的项上
- @SuppressWarnings注解会告知编译器阻止特定类型的警告信息
- @Override这种注解只能应用到方法上
- @Generated注解的目的是供代码生成工具来使用
- @PostCobstruct和@PreDestroy注解用于控制对象声明周期的环境中,标记这些注解的方法应该在对象被构建之后,或者移除之前,紧接着调用
- @Resource注解用于资源注入
- @Target元注解可以应用于一个注解,以限制该注解可以应用到哪些项上
- @Retention元注解用于指定一条注解应该保留多长时间
- @Documented元注解为像Javadoc这样的归档工具提供一些提示
- @Inherited元注解只能应用于对类的注解
- @Serializable注解应该比其接口更适用
- @Persistent来指明一个类的对象可以存储到数据库中,name该持久类的子类就会自动被注解为是持久性的
6.源码级注解处理
- 注解处理已经集成到了Java编译器中,编译器会定位源文件的注解
- 注解处理器通常通过扩展AbstractProcessor类而实现Processor接口
- 处理器可以声明具体的注解类型或诸如“com.horstmann”这样的通配符,甚至是“”(所有注解)
7.字节码工程(这部分看原文,了解一下)
- 也可以在字节码界别对注解进行处理
第九章 《安全》
1.类加载器
- 虚拟机只加载程序执行所需要的类文件,下面是虚拟机执行步骤
- (1)虚拟机有一个用于加载类文件的机制
- (2)如果类拥有类型为另一个类的域,或者拥有超类,那么这些类文件也会被加载
- (3)虚拟机执行类里面的main方法(静态方法)
- (4)如果main方法要用到更多的类,那么就需要加载这些类
- 类加载器有一种父/子关系,除引导类加载器外,每个加载器都有一个父类加载器,根据规定,类加载器会为它的父类加载器提供一个机会,以便加载任何给定的类,并且只有在其父类加载器加载失败时,它才会加载该给定类
- 每个线程都有一个对类加载器的引用,称为上下文加载器。主线程的上下文类加载器是系统加载器
- 如果要编写自己的类加载器,只需要继承ClassLoader类,然后覆盖findClass(String className)
- 当类加载器将新加载的Java平台类的字节码传递给虚拟机时,这些字节码手下要接受校验器的校验
- 校验器会执行如下检查:(1)变量要在使用之前进行初始化 (2)方法调用与对象引用类型之间要匹配 (3)访问私有数据和方法的规则没有被违法 (4)对本地变量的访问都落在运行时堆栈内 (5)运行时堆栈没有溢出
2.安全管理器与访问权限
- 一旦某个类被加载到虚拟机中,并由检验其检查过之后,Java平台的第二种安全机制就会启动,这个机制就是安全管理器
- 安全管理器是一个负责控制具体操作是否允许执行的类,包括:创建一个新的类加载器、退出虚拟器、使用反射访问另一个类的衬管、访问本地文件、打开socket连接、启动打印作业、访问系统剪贴板、访问AWT事件队列、打开一个顶层窗口
- 代码来源是由衣蛾代码位置和一个证书集指定的
- 证书的目的是要由某一方来保障代码没有被篡改过
- 权限是指由安全管理器负责检查的任何属性
- 每个类都有一个保护域,它是一个用于封装类的代码来源和权限集合的对象
- 策略管理器要丢相应的策略文件,这些文件包含了将代码来源映射为权限的指令
- 如果要实现自己的权限类,可以继承Permission类
3.用户认证
- Java认证和授权服务(JAAS)包含两个部分:“认证”部分主要负责确定程序使用者的身份,而“授权”将各个用户映射到相应的权限
- JAAS是一个可插拨的API,可以将Java应用程序与实现认证的特定技术分离开来
- 各个模块依次执行,直到有一个sufficient的模块认证成功,或者有一个requisite的模块认证失败,或者已经执行到最后一个模块时才停止
- 当标记为required和requisite的所有模块都认证成功,或者它们都没有被执行,但至少有一个sufficient或optional的模块认证成功时,这次认证就成功了
4.数字签名(关于加密问题建议进一步查找相关资料)
- 消息摘要是数据块的数字指纹,有两个基本属性:(1)如果数据的1位或者几位改变了,那么消息摘要也将改变 (2)拥有给定消息的伪造者不能创建与原消息具有相同摘要的假消息
5.加密(关于加密问题建议进一步查找相关资料)
第十章 《高级Swing》(跳过)
第十一章 《高级AWT》 《跳过》
第十二章 《本地方法》(这一章主要将java调用c方法,有兴趣的可以查阅更多资料了解)
1.从Java程序中调用C函数
- Java编程语言用关键字native表示本地方法
- 为了实现本地代码,需要编写一个相应的C函数,必须按照虚拟机与其的那样来命名这个函数,其规则是:(1)使用完整的Java方法名 (2)用下划线替换掉所有的句号,并加上Java_前缀 (3)如果类名含有非ASCII字母或数字,用_0xxxx来替代它们
2.数值参数与返回值
- 由于在不同平台基本类型的比特位不一致,因此,Java本地接口定义了jint,jlong等类型
3.字符串参数
- Java编程语言中的字符串是UTF-16编码点的序列,而C的字符串则是以null结尾的字节序列