标题：javax.print.attribute
属性
简介设置打印作业时，客户端会指定两件事情：打印数据和处理指令。打印数据是要打印的实际内容。处理指令告知打印机如何打印该打印数据，如：使用什么介质，打印多少副本，在纸上是单面打印还是双面打印。客户端使用 Java Print Service API 的属性定义来指定这些处理指令。 
打印数据和处理指令都是独立的实体。这意味着：您可以在不同时间使用不同的处理指令打印同一打印数据。 
例如，您可以在美国信函大小的白纸上双面、装订打印 20 张幻灯片演示文稿副本作为演讲的讲义；还可以在美国信函大小的透明介质上单面打印一份相同的幻灯片演示文稿作为演讲的实际幻灯片。 
您可以在不同时间使用相同的处理指令打印不同的数据。例如，您可以将默认处理指令设置为：美国信函大小的纸张、双面、装订。每当打印一项作业时，会使用这些设置进行打印，除非显式重写它们。 
处理指令不指定打印作业处理该请求的方式；每条处理指令仅是对打印作业结果的描述。打印作业确定实现处理指令所指定结果的方式。将处理指令表示为描述项可为实现打印作业提供更大的灵活性。 
属性类别和值每个打印机都有一组功能，如在不同大小的纸张上打印或打印多个副本。每个功能都有一个范围值。例如，打印机的方向功能可能有以下范围值：[landscape, portrait]。对于每个打印请求，可以将该功能设置为这些值之一。Java Print Service API 使用术语属性类别指打印机功能，使用术语属性值指该功能的值。 
在 Java Print Service API 中，通过实现 Attribute 接口的 Java 类来表示属性类别。属性值是这样的类或其某个子类的实例。例如，要指定副本数，应用程序会构造一个具有所需副本数的 Copies 类的实例，并将 Copies 实例用作打印请求的一部分。在这种情况下，Copies 类表示属性类别，Copies 实例表示属性值。 
属性职责将打印作业提交给打印机时，客户端将提供描述打印数据特征的属性（如，文档名称），以及应如何打印打印数据（如，双面、五份）。如果打印作业由多部分打印数据组成，则不同部分可能具有不同的处理指令，如将 8 × 11 英寸的介质用于第一个文档，11 × 17 英寸的介质用于另一个文档。 
打印机开始处理打印作业之后，关于该作业的其他信息将可供使用，可能包括：作业状态（如完成 或排队）和到目前为止已打印的页数。这些信息片段也是属性。属性还可描述打印机本身，如：打印机名称、打印机位置和已排队的作业数。 
Java Print Service API 使用 Attribute 的五个子接口定义这些不同类型的属性： 
DocAttribute 指定每个文档的特征和应用到每个文档的打印作业设置。 
PrintRequestAttribute 指定应用到整个打印作业和打印作业中所有文档的设置。 
PrintJobAttribute 报告打印作业的状态。 
PrintServiceAttribute 报告打印服务的状态。 
SupportedValuesAttribute 为另一个属性提供支持的值。 
每个属性类实现一个或多个这些标记子接口，以指示在 API 中可以使用该属性的位置。如果属性类实现多个标记子接口，则可以在多个上下文中使用该属性。例如，介质属性可以作为 DocAttribute 应用到打印作业中的一个文档，或作为 PrintRequestAttribute 应用到整个打印作业。某些低级别属性从不用于其自身，但是，总是可以将它们汇集到高级别属性中。这此低级别属性类仅实现接口 Attribute，不能实现任何标记子接口。 
Java Print Service API 定义了一组标准属性类，它可以按照 Internet Printing Protocol (IPP) 版本 1.1 对属性进行建模。标准属性类位于子包 javax.print.attribute.standard 中，目的是保持实际属性类在概念上与包 javax.print.attribute 中定义的一般设备分开。 
属性集在提交打印作业时，客户端通常需要提供多个处理指令。例如，客户端可能需要指定大小为 A4 的介质和横向方向。要发送多个处理指令，客户端将属性收集到 Java Print Service API 通过 AttributeSet 接口所表示的属性集中。 
AttributeSet 接口类似于 Map 接口：它提供键到值的映射，其中每个键都是惟一的，并且只能包含一个值。但是，AttributeSet 接口设计用于专门支持 Java Print Service API 的需求。AttributeSet 要求： 
AttributeSet 中的每个键对应于一个类别，键的值只能是属性值之一，它属于该键表示的类别。因此，与 Map 不同，AttributeSet 限制了键的可能值：不能将属性类别设置为不属于该类别的属性值。 
在同一集合中，不能存在同一类别的两个属性。例如，属性集合决不能同时包含“单面”属性和“双面”属性，因为这两个属性会导致打印机指令冲突。 
只可以将实现 Attribute 接口的属性添加到该集合。 
javax.print.attribute 包中包括了作为属性集接口具体实现的 HashAttributeSet。HashAttributeSet 提供基于哈希映射的属性集。您可以使用此实现，或提供自己的接口 AttributeSet 实现。 
Java Print Service API 提供属性集的四个规范，它们限于仅包含四种属性之一，如属性职责一节所讨论的： 
DocAttributeSet 
PrintRequestAttributeSet 
PrintJobAttributeSet 
PrintServiceAttributeSet 
注意，这里仅列出了四种属性集，但是有五种属性。接口 SupportedValuesAttribute 表示为另一个属性提供支持值的属性。永远不可能将支持值属性汇集到属性集中，因此不存在为它们定义的属性集子接口。 
在某些上下文中，属性集是只读的，这意味着只允许客户端检查属性集的内容，但不能更改它们。在其他上下文中，属性集是可读写的，这意味着允许客户端检查和更改属性集的内容。对于只读属性集，调用更改操作会抛出 UnmodifiableSetException。 
包 javax.print.attribute 包括每个属性集子接口的一个具体实现： 
HashDocAttributeSet 
HashPrintRequestAttributeSet, 
HashPrintJobAttributeSet, 
HashPrintServiceAttributeSet. 
所有这些类都扩展 HashAttributeSet，并强制要求只允许属性集包含相应类型属性的限制。 
属性类设计属性值是一个小的原子数据项，如整数或枚举值。Java Print Service API 不使用基本数据类型（如 int）来表示属性值，原因如下： 
基本数据类型不是类型安全的。例如，编译器不应允许将“copies”属性值用于“sides”属性。 
一些属性必须表示为几个值的记录。打印机分辨率就是一个例子，它需要两个数（如，表示 600 × 300 dpi 的 600 和 300）。 
对于类型安全性和要统一表示所有属性，Java Print Service API 将每个属性类别定义为类，如类 Copies、类 Sides 和 类 PrinterResolution。每个属性类可以包装一个或多个包含属性值的基本数据项。属性集操作在添加属性、在同一类别中查找现有属性和查找给定其类别的属性时经常执行属性类别对象之间的比较。因为属性类别由类表示，所以使用 Class.equals 方法可以执行快速的属性值比较。 
尽管 Java Print Service API 包括大量不同的属性类别，但是仅存在很少的不同类型的属性值。大多数属性可由少量数据类型表示，如：整数值、整数范围、文本或整数值的枚举。类别接受的属性值类型称为属性的抽象语法。为了提供一致性并减少代码重复，Java Print Service API 定义了抽象语法类，以表示每个抽象语法，并且只要可能，可以将这些类用作标准属性的父级。抽象语法类是： 
EnumSyntax 提供类型安全的枚举，其中枚举值表示为单个对象。每个枚举都是包装隐藏 int 值的枚举类实例。 
IntegerSyntax 是用于整数值属性的抽象语法。 
TextSyntax 是用于文本值属性的抽象语法，并且包括立提供文本字符串的自然语言的语言环境。 
SetOfIntegerSyntax 是表示整数范围或整数集的属性的抽象语法。 
ResolutionSyntax 是表示分辨率值（如 600×300 dpi）的属性的抽象语法。 
Size2DSyntax 是表示二维大小（如，纸张大小为 8.5 × 11 英寸）的属性的抽象语法。 
DateTimeSyntax 是其值为日期和时间的属性的抽象语法。 
URISyntax 是其值为统一资源定位符的属性的抽象语法。 
抽象语法类独立于使用它们的属性。事实上，与打印无关的应用程序可以使用抽象语法类。虽然多数标准属性类会扩展某个抽象语法类，但不需要任何属性类扩展上述类之一。抽象语法类仅提供许多属性类可以共享的便捷实现。 
每个属性类可以直接或间接实现 Attribute 接口，以便将其标记为打印属性。在某些上下文的限制属性集中出现的属性类也实现 Attribute 的一个或多个子接口。多数属性类也扩展适当的抽象语法类，以获取该实现。考虑 Sides 属性类： 
public class Sides
extends EnumSyntax
implements DocAttribute, PrintRequestAttribute, PrintJobAttribute
{
public final Object getCategory()
{
return Sides.class;
}
...
}
由于每个属性类会实现 Attribute，所以每个属性类必须提供返回属性类别的 getCategory 方法的实现。对于属性 Sides，getCategory 方法返回 Sides.class。getCategory 方法最终确保了标准属性类的所有供应商定义的子类都显示在同一类别中。每个属性对象在构造之后都是不可变的，这样可以随意地传递属性对象引用。要获取不同的属性值，请构造不同的属性对象。 
属性供应商Java Print Service API 被设计成可让供应商： 
为 javax.print.attribute.standard 中定义的所有标准属性定义新的特定于供应商的值。 
定义表示供应商打印机专用功能（标准属性已不支持）的新属性类别。 
要为属性定义一个新值，客户端可以使用任意值在运行时构造此属性的实例。但是，使用 EnumSyntax 的抽象语法类的枚举属性在编译时将所有的可能属性值指定为属性类的单个实例。这意味着在运行时无法构造新的枚举值。要为标准枚举属性定义新的特定于供应商的值，供应商必须定义一个指定单个新实例的新属性类。要确保新的属性值与标准属性值在相同的类别中，新的属性类必须是标准属性类的子类。 
要定义新的属性类别，供应商需要定义新的属性类。此属性类（与标准属性类类似）实现 Attribute 或其子接口之一，并扩展抽象语法类。供应商可以使用现有的抽象语法类，或者定义新的抽象语法类。无论在哪里（如在 AttributeSet 中）使用 Attribute，都可以使用供应商定义的新属性。 
使用属性典型的打印应用程序使用 PrintRequestAttributeSet，因为打印请求属性是客户端通常指定的属性类型。下面的示例介绍如何创建打印请求属性的属性集，并查找可以按照指定的属性打印文档的打印机： 
FileInputStream psStream;
try {
psstream = new FileInputStream("file.ps");
} catch (FileNotFoundException ffne) {
}
if (psstream == null) {
return;
}
//Set the document type.  See the DocFlavor documentation for
//more information.
DocFlavor psInFormat = DocFlavor.INPUT_STREAM.POSTSCRIPT;
Doc myDoc = new SimpleDoc(pstream, psInFormat, null);  
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(new Copies(5));
aset.add(MediaSize.A4);
aset.add(Sides.DUPLEX);
PrintService[] services = 
PrintServiceLookup.lookupPrintServices(psInFormat, aset);
if (services.length > 0) {
DocPrintJob job = services[0].createPrintJob();
try {
job.print(myDoc, aset);
} catch (PrintException pe) {}
}
请注意：在 javax.print API 中，只有方法中显式地记录 null 引用具有有意义的解释时，方法的 null 引用参数才是正确的。与之相反的用法是不正确的编码，可能立即或在稍后某一时间导致运行时异常。
应用
IllegalArgumentException 和 NullPointerException 是针对这种情况的典型的、可接受的运行时异常的示例。 
从以下版本开始： 
1.4