- 所有已实现的接口:
-
Closeable
,AutoCloseable
Socket
,并使用诸如"安全套接字层"(SSL)或IETF"传输层安全性"(TLS)协议提供安全套接字。
这些套接字是普通的流套接字,但它们在底层网络传输协议上增加了一层安全保护,例如TCP。这些保护包括:
- 完整性保护。SSL可防止主动窃听者修改消息。
- 身份验证。在大多数模式下,SSL提供对等身份验证。通常服务器会被验证,客户端可能会根据服务器的要求进行验证。
- 机密性(隐私保护)。在大多数模式下,SSL加密在客户端和服务器之间发送的数据。这保护了数据的机密性,使得被动窃听者无法看到敏感数据,如金融信息或各种个人信息。
这些保护类型由"密码套件"指定,它是给定SSL连接使用的加密算法的组合。在协商过程中,两个端点必须就两个环境中都可用的密码套件达成一致。如果没有共同的套件,就无法建立SSL连接,也无法交换数据。
使用的密码套件是通过称为"握手"的协商过程建立的。此过程的目标是创建或重新加入一个"会话",该会话可以随时间保护许多连接。握手完成后,您可以通过使用getSession方法访问会话属性。在此连接上的初始握手可以通过以下三种方式之一启动:
- 调用
startHandshake
显式开始握手,或 - 在此套接字上尝试读取或写入应用程序数据会导致隐式握手,或
- 调用
getSession
尝试设置会话(如果当前没有有效会话),并执行隐式握手。
如果由于任何原因握手失败,SSLSocket
将被关闭,无法进行进一步通信。
在管理密码套件时,您需要了解两组密码套件:
- 支持的密码套件:SSL实现支持的所有套件。此列表使用getSupportedCipherSuites报告。
- 已启用的密码套件,可能少于完整支持的套件集。此组使用setEnabledCipherSuites方法设置,并使用getEnabledCipherSuites方法查询。最初,新套接字上将启用一组默认密码套件,表示建议的最低配置。
实现默认要求默认情况下仅启用对服务器进行身份验证并提供机密性的密码套件。只有在双方明确同意不进行身份验证和/或非私密(未加密)通信时,才会选择这样的密码套件。
当创建SSLSocket
时,不会执行任何握手,以便应用程序可以首先设置其通信首选项:要使用的密码套件,套接字应处于客户端还是服务器模式等。但是,一旦应用程序数据通过连接发送,安全性将始终得到保障。
您可以注册以接收握手完成的事件通知。这涉及使用两个附加类。HandshakeCompletedEvent对象传递给此API的用户注册的HandshakeCompletedListener实例。通过SSLSocketFactory
创建SSLSocket
,或通过从SSLServerSocket
接受连接来创建SSLSocket
。
SSL套接字必须选择在客户端模式或服务器模式下运行。这将确定由哪一方开始握手过程,以及每个方发送哪些消息。每个连接必须有一个客户端和一个服务器,否则握手将无法正确进行。一旦初始握手开始,套接字就无法在执行重新协商时在客户端和服务器模式之间切换。
此类中的方法返回的String
值是由对等方发送的网络字节表示。这些字节可以直接进行比较,也可以将其转换为其UnicodeString
格式进行比较。
String networkString = sslSocket.getHandshakeApplicationProtocol(); byte[] bytes = networkString.getBytes(StandardCharsets.ISO_8859_1); // // 使用字节进行匹配: // // "http/1.1" (7位ASCII值在UTF-8中相同) // MEETEI MAYEK LETTERS "HUK UN I" (Unicode 0xabcd->0xabcf) // String HTTP1_1 = "http/1.1"; byte[] HTTP1_1_BYTES = HTTP1_1.getBytes(StandardCharsets.UTF_8); byte[] HUK_UN_I_BYTES = new byte[] { (byte) 0xab, (byte) 0xcd, (byte) 0xab, (byte) 0xce, (byte) 0xab, (byte) 0xcf}; if ((Arrays.compare(bytes, HTTP1_1_BYTES) == 0 ) || Arrays.compare(bytes, HUK_UN_I_BYTES) == 0) { ... } // // 或者,如果我们知道ALPN值是使用特定字符集(例如UTF-8)从String
编码的, // 则可以使用string.equals()进行匹配。在使用之前,必须将ALPN值正确解码为UnicodeString
。 // String unicodeString = new String(bytes, StandardCharsets.UTF_8); if (unicodeString.equals(HTTP1_1) || unicodeString.equals("\uabcd\uabce\uabcf")) { ... }
- API注释:
-
当连接不再需要时,客户端和服务器应用程序应分别关闭各自连接的两侧。可以通过调用
Socket.close()
一次性关闭,或通过分别关闭每一侧使用Socket.shutdownOutput()
/Socket.shutdownInput()
来关闭,这对于支持半关闭连接的协议版本很有用。请注意,在某些情况下,关闭输入流可能取决于对等方的输出流先关闭。如果连接未按顺序关闭(例如在接收对等方的写入关闭通知之前调用了
Socket.shutdownInput()
),可能会引发异常以指示发生错误。一旦
SSLSocket
关闭,它就不可重用:必须创建一个新的SSLSocket
。 - 自从:
- 1.4
- 参见:
-
Constructor Summary
ModifierConstructorDescriptionprotected
仅由子类使用。protected
仅由子类使用。protected
SSLSocket
(String host, int port, InetAddress clientAddress, int clientPort) 仅由子类使用。protected
SSLSocket
(InetAddress address, int port) 仅由子类使用。protected
SSLSocket
(InetAddress address, int port, InetAddress clientAddress, int clientPort) 仅由子类使用。 -
Method Summary
Modifier and TypeMethodDescriptionabstract void
注册事件侦听器以接收此连接上的SSL握手完成通知。返回为此连接协商的最新应用程序协议值。abstract String[]
返回当前在此连接上启用的SSL密码套件的名称。abstract String[]
返回当前在此连接上启用的协议版本的名称。abstract boolean
如果此套接字可以建立新的SSL会话,则返回true。返回当前正在进行的SSL/TLS握手中协商的应用程序协议值。检索在SSL/TLS/DTLS握手期间选择应用程序协议值的回调函数。返回在SSL/TLS握手期间构建的SSLSession
。abstract boolean
如果套接字将要求客户端身份验证,则返回true。abstract SSLSession
返回此连接正在使用的SSL会话。返回对此SSLSocket生效的SSLParameters。abstract String[]
返回可在此连接上启用的密码套件的名称。abstract String[]
返回可在SSL连接上启用的协议的名称。abstract boolean
如果在握手时套接字设置为使用客户端模式,则返回true。abstract boolean
如果套接字将请求客户端身份验证,则返回true。abstract void
删除先前注册的握手完成侦听器。abstract void
setEnabledCipherSuites
(String[] suites) 设置在此连接上启用的密码套件。abstract void
setEnabledProtocols
(String[] protocols) 设置在此连接上启用的协议版本。abstract void
setEnableSessionCreation
(boolean flag) 控制此套接字是否可以建立新的SSL会话。void
注册回调函数以为SSL/TLS/DTLS握手选择应用程序协议值。abstract void
setNeedClientAuth
(boolean need) 配置套接字以要求客户端身份验证。void
setSSLParameters
(SSLParameters params) 将SSLParameters应用于此套接字。abstract void
setUseClientMode
(boolean mode) 在握手时配置套接字使用客户端(或服务器)模式。abstract void
setWantClientAuth
(boolean want) 配置套接字以请求客户端身份验证。abstract void
在此连接上启动SSL握手。Methods declared in class java.net.Socket
bind, close, connect, connect, getChannel, getInetAddress, getInputStream, getKeepAlive, getLocalAddress, getLocalPort, getLocalSocketAddress, getOOBInline, getOption, getOutputStream, getPort, getReceiveBufferSize, getRemoteSocketAddress, getReuseAddress, getSendBufferSize, getSoLinger, getSoTimeout, getTcpNoDelay, getTrafficClass, isBound, isClosed, isConnected, isInputShutdown, isOutputShutdown, sendUrgentData, setKeepAlive, setOOBInline, setOption, setPerformancePreferences, setReceiveBufferSize, setReuseAddress, setSendBufferSize, setSocketImplFactory, setSoLinger, setSoTimeout, setTcpNoDelay, setTrafficClass, shutdownInput, shutdownOutput, supportedOptions, toString
-
Constructor Details
-
SSLSocket
protected SSLSocket()仅由子类使用。构造一个未初始化、未连接的TCP套接字。 -
SSLSocket
仅由子类使用。构造到指定端口的命名主机的TCP连接。这充当SSL客户端。如果存在安全管理器,则将使用主机地址和
port
作为参数调用其checkConnect
方法。这可能导致SecurityException。- 参数:
-
host
- 要连接的主机名,或null
表示回环地址。 -
port
- 服务器端口号 - 抛出:
-
IOException
- 如果创建套接字时发生I/O错误 -
SecurityException
- 如果存在安全管理器且其checkConnect
方法不允许该操作。 -
UnknownHostException
- 如果主机未知 -
IllegalArgumentException
- 如果端口参数超出有效端口值范围,有效端口值为0到65535(包括0和65535)。 - 参见:
-
SSLSocket
仅供子类使用。构造一个到指定地址和端口的服务器的TCP连接。这充当SSL客户端。如果存在安全管理器,则将使用主机地址和
port
作为参数调用其checkConnect
方法。这可能导致SecurityException。- 参数:
-
address
- 服务器的主机 -
port
- 其端口 - 抛出:
-
IOException
- 如果创建套接字时发生I/O错误 -
SecurityException
- 如果存在安全管理器且其checkConnect
方法不允许该操作。 -
IllegalArgumentException
- 如果端口参数超出有效端口值范围,有效端口值为0到65535(包括0和65535)。 -
NullPointerException
- 如果address
为null。 - 参见:
-
SSLSocket
protected SSLSocket(String host, int port, InetAddress clientAddress, int clientPort) throws IOException, UnknownHostException 仅供子类使用。构造一个到指定地址和TCP端口的服务器的SSL连接,将连接的客户端一侧绑定到给定的地址和端口。这充当SSL客户端。如果存在安全管理器,则将使用主机地址和
port
作为参数调用其checkConnect
方法。这可能导致SecurityException。- 参数:
-
host
- 要连接的主机名,或null
表示回环地址。 -
port
- 服务器端口号 -
clientAddress
- 套接字绑定到的客户端地址,或null
表示anyLocal
地址。 -
clientPort
- 套接字绑定到的客户端端口,或zero
表示系统选择的空闲端口。 - 抛出:
-
IOException
- 如果创建套接字时发生I/O错误 -
SecurityException
- 如果存在安全管理器且其checkConnect
方法不允许该操作。 -
UnknownHostException
- 如果主机未知 -
IllegalArgumentException
- 如果端口参数或clientPort参数超出有效端口值范围,有效端口值为0到65535(包括0和65535)。 - 参见:
-
SSLSocket
protected SSLSocket(InetAddress address, int port, InetAddress clientAddress, int clientPort) throws IOException 仅供子类使用。构造一个到指定地址和TCP端口的服务器的SSL连接,将连接的客户端一侧绑定到给定的地址和端口。这充当SSL客户端。如果存在安全管理器,则将使用主机地址和
port
作为参数调用其checkConnect
方法。这可能导致SecurityException。- 参数:
-
address
- 服务器的主机 -
port
- 其端口 -
clientAddress
- 套接字绑定到的客户端地址,或null
表示anyLocal
地址。 -
clientPort
- 套接字绑定到的客户端端口,或zero
表示系统选择的空闲端口。 - 抛出:
-
IOException
- 如果创建套接字时发生I/O错误 -
SecurityException
- 如果存在安全管理器且其checkConnect
方法不允许该操作。 -
IllegalArgumentException
- 如果端口参数或clientPort参数超出有效端口值范围,有效端口值为0到65535(包括0和65535)。 -
NullPointerException
- 如果address
为null。 - 参见:
-
-
Method Details
-
getSupportedCipherSuites
返回可用于此连接的密码套件的名称。通常,默认情况下只有这些密码套件的子集会被启用,因为此列表可能包括不符合这些默认服务质量要求的密码套件。这些密码套件可能在专门的应用程序中有用。返回的数组包括来自Java安全标准算法名称规范的JSSE密码套件名称部分的标准密码套件,还可能包括提供程序支持的其他密码套件。
- 返回:
- 一个密码套件名称数组
- 参见:
-
getEnabledCipherSuites
返回当前在此连接上启用的SSL密码套件的名称。当创建SSLSocket时,所有启用的密码套件都支持最低服务质量。因此,在某些环境中,此值可能为空。请注意,即使启用了密码套件,也可能永远不会使用。如果对等方不支持它,或者其使用受限制,或者没有支持该协议的启用密码套件(和私钥),或者启用了匿名套件但需要身份验证。
返回的数组包括来自Java安全标准算法名称规范的JSSE密码套件名称部分的标准密码套件,还可能包括提供程序支持的其他密码套件。
- 返回:
- 一个密码套件名称数组
- 参见:
-
setEnabledCipherSuites
设置此连接上启用的密码套件。参数
suites
中的每个密码套件必须已在getSupportedCipherSuites()中列出,否则该方法将失败。成功调用此方法后,只有suites
参数中列出的套件才会被启用。请注意,标准密码套件名称列表可以在Java安全标准算法名称规范的JSSE密码套件名称部分中找到。提供程序可能支持未在此列表中找到的密码套件名称,或者可能不使用某个密码套件的推荐名称。
有关为什么特定密码套件可能永远不会在连接上使用的更多信息,请参见
getEnabledCipherSuites()
。- 参数:
-
suites
- 要启用的所有密码套件的名称 - 抛出:
-
IllegalArgumentException
- 当参数命名的一个或多个密码套件不受支持,或者参数为null时。 - 参见:
-
getSupportedProtocols
返回可用于SSL连接的协议的名称。- 返回:
- 支持的协议数组
-
getEnabledProtocols
返回当前在此连接上启用的协议版本的名称。请注意,即使启用了协议,也可能永远不会使用。这可能发生在对等方不支持该协议,或者其使用受限,或者没有受协议支持的启用密码套件,或者启用了匿名套件但需要身份验证的情况下。
- 返回:
- 协议数组
- 参见:
-
setEnabledProtocols
设置此连接可用的协议版本。这些协议必须已经在
getSupportedProtocols()
中列出为受支持的。成功调用此方法后,只有protocols
参数中列出的协议才能被启用。- 参数:
-
protocols
- 要启用的所有协议的名称。 - 抛出:
-
IllegalArgumentException
- 当参数命名的一个或多个协议不受支持或协议参数为null时。 - 参见:
-
getSession
返回此连接正在使用的SSL会话。这些会话可以长期存在,并且通常对应于某个用户的整个登录会话。该会话指定了会话中所有连接正在使用的特定密码套件,以及会话的客户端和服务器的身份。如果在初始握手期间发生错误,此方法将返回一个无效的会话对象,该对象报告一个无效的密码套件"SSL_NULL_WITH_NULL_NULL"。
- 返回:
-
SSLSession
-
getHandshakeSession
返回在SSL/TLS握手期间正在构建的SSLSession
。TLS协议可能会在使用此类的实例时协商需要的参数,但在
SSLSession
完全初始化并通过getSession
可用之前。例如,有效签名算法的列表可能会限制在TrustManager决策期间可以使用的证书类型,或者最大的TLS片段数据包大小可以调整以更好地支持网络环境。此方法提供对正在构建的
SSLSession
的早期访问。根据握手的进展程度,某些数据可能尚不可用。例如,如果远程服务器将发送证书链,但该链尚未被处理,则SSLSession
的getPeerCertificates
方法将抛出SSLPeerUnverifiedException。一旦该链被处理,getPeerCertificates
将返回正确的值。与
getSession()
不同,此方法不会启动初始握手,并且不会阻塞直到握手完成。- 返回:
-
如果此实例当前未进行握手,或当前握手尚未进行到足以创建基本SSLSession的程度,则返回null。否则,此方法返回当前正在协商的
SSLSession
。 - 抛出:
-
UnsupportedOperationException
- 如果底层提供程序未实现该操作。 - 自:
- 1.7
- 参见:
-
addHandshakeCompletedListener
注册事件侦听器以接收SSL握手在此连接上完成的通知。- 参数:
-
listener
- 握手完成事件侦听器 - 抛出:
-
IllegalArgumentException
- 如果参数为null。 - 参见:
-
removeHandshakeCompletedListener
移除先前注册的握手完成侦听器。- 参数:
-
listener
- 握手完成事件侦听器 - 抛出:
-
IllegalArgumentException
- 如果侦听器未注册,或参数为null。 - 参见:
-
startHandshake
在此连接上启动SSL握手。常见原因包括需要使用新的加密密钥,更改密码套件或启动新会话。要强制进行完整重新认证,可以在启动此握手之前使当前会话无效。如果在连接上已经发送了数据,则在此握手期间数据将继续流动。当握手完成时,将通过事件发出信号。对于连接上的初始握手,此方法是同步的,并在协商的握手完成时返回。某些协议可能不支持在现有套接字上进行多次握手,并可能抛出IOException。
- 抛出:
-
IOException
- 在网络级别发生错误时 - 参见:
-
setUseClientMode
public abstract void setUseClientMode(boolean mode) 在握手时配置套接字以使用客户端(或服务器)模式。必须在任何握手发生之前调用此方法。一旦握手开始,该模式在此套接字的生命周期内将无法重置。
服务器通常会对自身进行身份验证,而客户端则无需这样做。
- 参数:
-
mode
- 如果套接字应在"客户端"模式下开始握手,则为true - 抛出:
-
IllegalArgumentException
- 如果在初始握手开始后尝试更改模式。 - 参见:
-
getUseClientMode
public abstract boolean getUseClientMode()如果套接字在握手时设置为使用客户端模式,则返回true。- 返回:
- 如果套接字应在"客户端"模式下进行握手,则返回true
- 参见:
-
setNeedClientAuth
public abstract void setNeedClientAuth(boolean need) 配置套接字以要求客户端身份验证。此选项仅对服务器模式下的套接字有用。套接字的客户端身份验证设置为以下之一:
- 需要客户端身份验证
- 请求客户端身份验证
- 不需要客户端身份验证
与
setWantClientAuth(boolean)
不同,如果设置了此选项并且客户端选择不提供有关自身的身份验证信息,协商将停止并且连接将被断开。调用此方法将覆盖此方法或
setWantClientAuth(boolean)
之前设置的任何先前设置。- 参数:
-
need
- 如果需要客户端身份验证,则设置为true;如果不需要客户端身份验证,则设置为false。 - 参见:
-
getNeedClientAuth
public abstract boolean getNeedClientAuth()如果套接字将要求客户端身份验证,则返回true。此选项仅对服务器模式下的套接字有用。- 返回:
- 如果需要客户端身份验证,则返回true;如果不需要客户端身份验证,则返回false。
- 参见:
-
setWantClientAuth
public abstract void setWantClientAuth(boolean want) 配置套接字以请求客户端身份验证。此选项仅对服务器模式下的套接字有用。套接字的客户端身份验证设置为以下之一:
- 需要客户端身份验证
- 请求客户端身份验证
- 不需要客户端身份验证
与
setNeedClientAuth(boolean)
不同,如果设置了此选项并且客户端选择不提供有关自身的身份验证信息,协商将继续。调用此方法将覆盖此方法或
setNeedClientAuth(boolean)
之前设置的任何先前设置。- 参数:
-
want
- 如果请求客户端身份验证,则设置为true;如果不需要客户端身份验证,则设置为false。 - 参见:
-
getWantClientAuth
public abstract boolean getWantClientAuth()如果套接字将请求客户端身份验证,则返回true。此选项仅对服务器模式下的套接字有用。- 返回值:
- 如果请求客户端身份验证,则为true;如果不需要客户端身份验证,则为false。
- 参见:
-
setEnableSessionCreation
public abstract void setEnableSessionCreation(boolean flag) 控制此套接字是否可以建立新的SSL会话。如果不允许创建会话,并且没有现有会话可供恢复,则不会成功握手。- 参数:
-
flag
- true表示可以创建会话;这是默认值。false表示必须恢复现有会话 - 参见:
-
getEnableSessionCreation
public abstract boolean getEnableSessionCreation()返回true,如果此套接字可以建立新的SSL会话。- 返回值:
- true表示可以创建会话;这是默认值。false表示必须恢复现有会话
- 参见:
-
getSSLParameters
返回此SSLSocket生效的SSLParameters。返回的SSLParameters的密码套件和协议始终非空。- 返回值:
- 此SSLSocket生效的SSLParameters。
- 自从:
- 1.6
-
setSSLParameters
将SSLParameters应用于此套接字。这意味着:
- 如果
params.getCipherSuites()
非空,则使用该值调用setEnabledCipherSuites()
。 - 如果
params.getProtocols()
非空,则使用该值调用setEnabledProtocols()
。 - 如果
params.getNeedClientAuth()
或params.getWantClientAuth()
返回true
,则分别调用setNeedClientAuth(true)
和setWantClientAuth(true)
;否则调用setWantClientAuth(false)
。 - 如果
params.getServerNames()
非空,则套接字将使用该值配置其服务器名称。 - 如果
params.getSNIMatchers()
非空,则套接字将使用该值配置其SNI匹配器。
- 参数:
-
params
- 参数 - 抛出:
-
IllegalArgumentException
- 如果调用setEnabledCipherSuites()或setEnabledProtocols()失败 - 自从:
- 1.6
- 如果
-
getApplicationProtocol
返回此连接为此连接协商的最新应用程序协议值。如果底层SSL/TLS/DTLS实现支持,应用程序名称协商机制(例如RFC 7301,应用层协议协商(ALPN))可以在对等方之间协商应用级值。
- 实现要求:
-
此类中的实现会抛出
UnsupportedOperationException
,并且不执行其他操作。 - 返回值:
-
如果尚未确定是否可以为此连接使用应用程序协议,则为null;如果不会使用应用程序协议值,则为空
String
;如果成功协商了一个非空应用程序协议String
,则为该值。 - 抛出:
-
UnsupportedOperationException
- 如果底层提供程序未实现该操作。 - 自从:
- 9
-
getHandshakeApplicationProtocol
返回当前正在进行的SSL/TLS握手中协商的应用程序协议值。类似于
getHandshakeSession()
,连接可能处于握手过程中。应用程序协议可能尚未可用。- 实现要求:
-
此类中的实现会抛出
UnsupportedOperationException
,并且不执行其他操作。 - 返回值:
-
如果尚未确定是否可以为此握手使用应用程序协议,则为null;如果不会使用应用程序协议值,则为空
String
;如果成功协商了一个非空应用程序协议String
,则为该值。 - 抛出:
-
UnsupportedOperationException
- 如果底层提供程序未实现该操作。 - 自从:
- 9
-
setHandshakeApplicationProtocolSelector
public void setHandshakeApplicationProtocolSelector(BiFunction<SSLSocket, List<String>, String> selector) 注册一个回调函数,用于为SSL/TLS/DTLS握手选择应用程序协议值。该函数会覆盖使用SSLParameters.setApplicationProtocols
提供的任何值,并支持以下类型参数:-
SSLSocket
-
函数的第一个参数允许检查当前的
SSLSocket
,包括握手会话和配置设置。 -
List<String>
- 函数的第二个参数列出TLS对等方广告的应用程序协议名称。
-
String
-
函数的结果是一个应用程序协议名称,或null表示没有一个广告的名称是可接受的。如果返回值是空的
String
,则不会使用应用程序协议指示。如果返回值为null(未选择任何值)或是对等方未广告的值,则底层协议将决定采取什么行动。(例如,ALPN将发送“no_application_protocol”警报并终止连接。)
serverSocket.setHandshakeApplicationProtocolSelector( (serverSocket, clientProtocols) -> { SSLSession session = serverSocket.getHandshakeSession(); return chooseApplicationProtocol( serverSocket, clientProtocols, session.getProtocol(), session.getCipherSuite()); });
- API注释:
-
此方法应在TLS服务器应用程序开始TLS握手之前调用。此外,此
SSLSocket
应配置为与回调函数选择的应用程序协议兼容的参数。例如,启用不良选择的密码套件可能导致没有合适的应用程序协议。请参阅SSLParameters
。 - 实现要求:
-
此类中的实现会抛出
UnsupportedOperationException
,并且不执行其他操作。 - 参数:
-
selector
- 回调函数,或null以取消注册。 - 抛出:
-
UnsupportedOperationException
- 如果底层提供程序未实现该操作。 - 自从:
- 9
-
-
getHandshakeApplicationProtocolSelector
检索在SSL/TLS/DTLS握手期间选择应用程序协议值的回调函数。有关函数的类型参数,请参见setHandshakeApplicationProtocolSelector
。- 实现要求:
-
此类中的实现会抛出
UnsupportedOperationException
,并且不执行其他操作。 - 返回值:
- 回调函数,如果未设置任何函数则为null。
- 抛出:
-
UnsupportedOperationException
- 如果底层提供程序未实现该操作。 - 自从:
- 9
-