Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
c603f18b
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
c603f18b
编写于
5月 10, 2013
作者:
J
jfranck
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8007073: Implement Core Reflection for Type Annotations on parameters
Reviewed-by: darcy, abuckley
上级
fa79aa0a
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
230 addition
and
61 deletion
+230
-61
src/share/classes/java/lang/reflect/Executable.java
src/share/classes/java/lang/reflect/Executable.java
+25
-19
src/share/classes/java/lang/reflect/Field.java
src/share/classes/java/lang/reflect/Field.java
+1
-1
src/share/classes/java/lang/reflect/Parameter.java
src/share/classes/java/lang/reflect/Parameter.java
+13
-0
src/share/classes/sun/reflect/annotation/TypeAnnotation.java
src/share/classes/sun/reflect/annotation/TypeAnnotation.java
+7
-6
src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java
.../classes/sun/reflect/annotation/TypeAnnotationParser.java
+33
-34
test/java/lang/annotation/TypeAnnotationReflection.java
test/java/lang/annotation/TypeAnnotationReflection.java
+151
-1
未找到文件。
src/share/classes/java/lang/reflect/Executable.java
浏览文件 @
c603f18b
...
...
@@ -510,12 +510,12 @@ public abstract class Executable extends AccessibleObject
*/
AnnotatedType
getAnnotatedReturnType0
(
Type
returnType
)
{
return
TypeAnnotationParser
.
buildAnnotatedType
(
getTypeAnnotationBytes
(),
sun
.
misc
.
SharedSecrets
.
getJavaLangAccess
().
getConstantPool
(
getDeclaringClass
()),
this
,
getDeclaringClass
(),
returnType
,
TypeAnnotation
.
TypeAnnotationTarget
.
METHOD_RETURN_TYPE
);
sun
.
misc
.
SharedSecrets
.
getJavaLangAccess
().
getConstantPool
(
getDeclaringClass
()),
this
,
getDeclaringClass
(),
returnType
,
TypeAnnotation
.
TypeAnnotationTarget
.
METHOD_RETURN
);
}
/**
...
...
@@ -535,12 +535,12 @@ public abstract class Executable extends AccessibleObject
*/
public
AnnotatedType
getAnnotatedReceiverType
()
{
return
TypeAnnotationParser
.
buildAnnotatedType
(
getTypeAnnotationBytes
(),
sun
.
misc
.
SharedSecrets
.
getJavaLangAccess
().
getConstantPool
(
getDeclaringClass
()),
this
,
getDeclaringClass
(),
getDeclaringClass
(),
TypeAnnotation
.
TypeAnnotationTarget
.
METHOD_RECEIVER_TYPE
);
sun
.
misc
.
SharedSecrets
.
getJavaLangAccess
().
getConstantPool
(
getDeclaringClass
()),
this
,
getDeclaringClass
(),
getDeclaringClass
(),
TypeAnnotation
.
TypeAnnotationTarget
.
METHOD_RECEIVER
);
}
/**
...
...
@@ -556,7 +556,13 @@ public abstract class Executable extends AccessibleObject
* @since 1.8
*/
public
AnnotatedType
[]
getAnnotatedParameterTypes
()
{
throw
new
UnsupportedOperationException
(
"Not yet"
);
return
TypeAnnotationParser
.
buildAnnotatedTypes
(
getTypeAnnotationBytes
(),
sun
.
misc
.
SharedSecrets
.
getJavaLangAccess
().
getConstantPool
(
getDeclaringClass
()),
this
,
getDeclaringClass
(),
getParameterTypes
(),
TypeAnnotation
.
TypeAnnotationTarget
.
METHOD_FORMAL_PARAMETER
);
}
/**
...
...
@@ -573,12 +579,12 @@ public abstract class Executable extends AccessibleObject
*/
public
AnnotatedType
[]
getAnnotatedExceptionTypes
()
{
return
TypeAnnotationParser
.
buildAnnotatedTypes
(
getTypeAnnotationBytes
(),
sun
.
misc
.
SharedSecrets
.
getJavaLangAccess
().
getConstantPool
(
getDeclaringClass
()),
this
,
getDeclaringClass
(),
getGenericExceptionTypes
(),
TypeAnnotation
.
TypeAnnotationTarget
.
THROWS
);
sun
.
misc
.
SharedSecrets
.
getJavaLangAccess
().
getConstantPool
(
getDeclaringClass
()),
this
,
getDeclaringClass
(),
getGenericExceptionTypes
(),
TypeAnnotation
.
TypeAnnotationTarget
.
THROWS
);
}
}
src/share/classes/java/lang/reflect/Field.java
浏览文件 @
c603f18b
...
...
@@ -1161,6 +1161,6 @@ class Field extends AccessibleObject implements Member {
this
,
getDeclaringClass
(),
getGenericType
(),
TypeAnnotation
.
TypeAnnotationTarget
.
FIELD
_TYPE
);
TypeAnnotation
.
TypeAnnotationTarget
.
FIELD
);
}
}
src/share/classes/java/lang/reflect/Parameter.java
浏览文件 @
c603f18b
...
...
@@ -200,6 +200,19 @@ public final class Parameter implements AnnotatedElement {
return
tmp
;
}
/**
* Returns an AnnotatedType object that represents the use of a type to
* specify the type of the formal parameter represented by this Parameter.
*
* @return an {@code AnnotatedType} object representing the use of a type
* to specify the type of the formal parameter represented by this
* Parameter
*/
public
AnnotatedType
getAnnotatedType
()
{
// no caching for now
return
executable
.
getAnnotatedParameterTypes
()[
index
];
}
private
transient
volatile
Class
<?>
parameterClassCache
=
null
;
/**
...
...
src/share/classes/sun/reflect/annotation/TypeAnnotation.java
浏览文件 @
c603f18b
...
...
@@ -83,12 +83,13 @@ public class TypeAnnotation {
CLASS_TYPE_PARAMETER
,
METHOD_TYPE_PARAMETER
,
CLASS_EXTENDS
,
CLASS_IMPLEMENTS
,
CLASS_PARAMETER_BOUND
,
METHOD_PARAMETER_BOUND
,
METHOD_RETURN_TYPE
,
METHOD_RECEIVER_TYPE
,
FIELD_TYPE
,
CLASS_IMPLEMENTS
,
// Not in the spec
CLASS_TYPE_PARAMETER_BOUND
,
METHOD_TYPE_PARAMETER_BOUND
,
FIELD
,
METHOD_RETURN
,
METHOD_RECEIVER
,
METHOD_FORMAL_PARAMETER
,
THROWS
;
}
public
static
class
TypeAnnotationTargetInfo
{
...
...
src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java
浏览文件 @
c603f18b
...
...
@@ -282,10 +282,10 @@ public class TypeAnnotationParser {
AnnotatedElement
boundsDecl
;
TypeAnnotationTarget
target
;
if
(
decl
instanceof
Class
)
{
target
=
TypeAnnotationTarget
.
CLASS_PARAMETER_BOUND
;
target
=
TypeAnnotationTarget
.
CLASS_
TYPE_
PARAMETER_BOUND
;
boundsDecl
=
(
Class
)
decl
;
}
else
{
target
=
TypeAnnotationTarget
.
METHOD_PARAMETER_BOUND
;
target
=
TypeAnnotationTarget
.
METHOD_
TYPE_
PARAMETER_BOUND
;
boundsDecl
=
(
Executable
)
decl
;
}
return
TypeAnnotation
.
filter
(
TypeAnnotationParser
.
parseAllTypeAnnotations
(
boundsDecl
),
target
);
...
...
@@ -371,14 +371,15 @@ public class TypeAnnotationParser {
private
static
final
byte
LOCAL_VARIABLE
=
(
byte
)
0x40
;
private
static
final
byte
RESOURCE_VARIABLE
=
(
byte
)
0x41
;
private
static
final
byte
EXCEPTION_PARAMETER
=
(
byte
)
0x42
;
private
static
final
byte
CAST
=
(
byte
)
0x43
;
private
static
final
byte
INSTANCEOF
=
(
byte
)
0x44
;
private
static
final
byte
NEW
=
(
byte
)
0x45
;
private
static
final
byte
CONSTRUCTOR_REFERENCE_RECEIVER
=
(
byte
)
0x46
;
private
static
final
byte
METHOD_REFERENCE_RECEIVER
=
(
byte
)
0x47
;
private
static
final
byte
LAMBDA_FORMAL_PARAMETER
=
(
byte
)
0x48
;
private
static
final
byte
METHOD_REFERENCE
=
(
byte
)
0x49
;
private
static
final
byte
METHOD_REFERENCE_TYPE_ARGUMENT
=
(
byte
)
0x50
;
private
static
final
byte
INSTANCEOF
=
(
byte
)
0x43
;
private
static
final
byte
NEW
=
(
byte
)
0x44
;
private
static
final
byte
CONSTRUCTOR_REFERENCE
=
(
byte
)
0x45
;
private
static
final
byte
METHOD_REFERENCE
=
(
byte
)
0x46
;
private
static
final
byte
CAST
=
(
byte
)
0x47
;
private
static
final
byte
CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
=
(
byte
)
0x48
;
private
static
final
byte
METHOD_INVOCATION_TYPE_ARGUMENT
=
(
byte
)
0x49
;
private
static
final
byte
CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
=
(
byte
)
0x4A
;
private
static
final
byte
METHOD_REFERENCE_TYPE_ARGUMENT
=
(
byte
)
0x4B
;
private
static
TypeAnnotation
parseTypeAnnotation
(
ByteBuffer
buf
,
ConstantPool
cp
,
...
...
@@ -417,19 +418,20 @@ public class TypeAnnotationParser {
return
res
;
}}
break
;
case
CLASS_TYPE_PARAMETER_BOUND:
return
parse2ByteTarget
(
TypeAnnotationTarget
.
CLASS_PARAMETER_BOUND
,
buf
);
return
parse2ByteTarget
(
TypeAnnotationTarget
.
CLASS_
TYPE_
PARAMETER_BOUND
,
buf
);
case
METHOD_TYPE_PARAMETER_BOUND:
return
parse2ByteTarget
(
TypeAnnotationTarget
.
METHOD_PARAMETER_BOUND
,
buf
);
return
parse2ByteTarget
(
TypeAnnotationTarget
.
METHOD_
TYPE_
PARAMETER_BOUND
,
buf
);
case
FIELD:
return
new
TypeAnnotationTargetInfo
(
TypeAnnotationTarget
.
FIELD
_TYPE
);
return
new
TypeAnnotationTargetInfo
(
TypeAnnotationTarget
.
FIELD
);
case
METHOD_RETURN:
return
new
TypeAnnotationTargetInfo
(
TypeAnnotationTarget
.
METHOD_RETURN
_TYPE
);
return
new
TypeAnnotationTargetInfo
(
TypeAnnotationTarget
.
METHOD_RETURN
);
case
METHOD_RECEIVER:
return
new
TypeAnnotationTargetInfo
(
TypeAnnotationTarget
.
METHOD_RECEIVER
_TYPE
);
return
new
TypeAnnotationTargetInfo
(
TypeAnnotationTarget
.
METHOD_RECEIVER
);
case
METHOD_FORMAL_PARAMETER:
{
// Todo
byte
index
=
buf
.
get
();
}
break
;
return
new
TypeAnnotationTargetInfo
(
TypeAnnotationTarget
.
METHOD_FORMAL_PARAMETER
,
index
);
}
//unreachable break;
case
THROWS:
return
parseShortTarget
(
TypeAnnotationTarget
.
THROWS
,
buf
);
...
...
@@ -445,30 +447,27 @@ public class TypeAnnotationParser {
short
varLength
=
buf
.
getShort
();
short
index
=
buf
.
getShort
();
}
break
;
return
null
;
case
EXCEPTION_PARAMETER:
{
byte
index
=
buf
.
get
();
}
break
;
case
CAST:
}
return
null
;
case
INSTANCEOF:
case
NEW:
{
short
offset
=
buf
.
getShort
();
}
break
;
case
CONSTRUCTOR_REFERENCE_RECEIVER:
case
METHOD_REFERENCE_RECEIVER:
{
case
NEW:
case
CONSTRUCTOR_REFERENCE:
case
METHOD_REFERENCE:
{
short
offset
=
buf
.
getShort
();
byte
index
=
buf
.
get
();
}
break
;
case
LAMBDA_FORMAL_PARAMETER:
{
byte
index
=
buf
.
get
();
}
break
;
case
METHOD_REFERENCE:
// This one isn't in the spec yet
break
;
}
return
null
;
case
CAST:
case
CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case
METHOD_INVOCATION_TYPE_ARGUMENT:
case
CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case
METHOD_REFERENCE_TYPE_ARGUMENT:
{
short
offset
=
buf
.
getShort
();
byte
index
=
buf
.
get
();
}
break
;
}
return
null
;
default
:
// will throw error below
...
...
test/java/lang/annotation/TypeAnnotationReflection.java
浏览文件 @
c603f18b
...
...
@@ -23,7 +23,7 @@
/*
* @test
* @bug 8004698
* @bug 8004698
8007073
* @summary Unit test for type annotations
*/
...
...
@@ -48,6 +48,8 @@ public class TypeAnnotationReflection {
testParameterizedType
();
testNestedParameterizedType
();
testWildcardType
();
testParameterTypes
();
testParameterType
();
}
private
static
void
check
(
boolean
b
)
{
...
...
@@ -359,6 +361,154 @@ public class TypeAnnotationReflection {
t
=
w
.
getAnnotatedLowerBounds
();
check
(
t
.
length
==
1
);
}
private
static
void
testParameterTypes
()
throws
Exception
{
// NO PARAMS
Method
m
=
Params
.
class
.
getDeclaredMethod
(
"noParams"
,
(
Class
<?>[])
null
);
AnnotatedType
[]
t
=
m
.
getAnnotatedParameterTypes
();
check
(
t
.
length
==
0
);
// ONLY ANNOTATED PARAM TYPES
Class
[]
argsArr
=
{
String
.
class
,
String
.
class
,
String
.
class
};
m
=
Params
.
class
.
getDeclaredMethod
(
"onlyAnnotated"
,
(
Class
<?>[])
argsArr
);
t
=
m
.
getAnnotatedParameterTypes
();
check
(
t
.
length
==
3
);
check
(
t
[
0
].
getAnnotations
().
length
==
1
);
check
(
t
[
0
].
getAnnotation
(
TypeAnno
.
class
)
!=
null
);
check
(
t
[
0
].
getAnnotationsByType
(
TypeAnno
.
class
)[
0
].
value
().
equals
(
"1"
));
check
(
t
[
1
].
getAnnotations
().
length
==
1
);
check
(
t
[
1
].
getAnnotation
(
TypeAnno
.
class
)
!=
null
);
check
(
t
[
1
].
getAnnotationsByType
(
TypeAnno
.
class
)[
0
].
value
().
equals
(
"2"
));
check
(
t
[
2
].
getAnnotations
().
length
==
2
);
check
(
t
[
2
].
getAnnotations
()[
0
].
annotationType
().
equals
(
TypeAnno
.
class
));
check
(
t
[
2
].
getAnnotation
(
TypeAnno
.
class
)
!=
null
);
check
(
t
[
2
].
getAnnotation
(
TypeAnno2
.
class
)
!=
null
);
check
(
t
[
2
].
getAnnotationsByType
(
TypeAnno
.
class
)[
0
].
value
().
equals
(
"3a"
));
check
(
t
[
2
].
getAnnotationsByType
(
TypeAnno2
.
class
)[
0
].
value
().
equals
(
"3b"
));
// MIXED ANNOTATED PARAM TYPES
m
=
Params
.
class
.
getDeclaredMethod
(
"mixed"
,
(
Class
<?>[])
argsArr
);
t
=
m
.
getAnnotatedParameterTypes
();
check
(
t
.
length
==
3
);
check
(
t
[
0
].
getAnnotations
().
length
==
1
);
check
(
t
[
0
].
getAnnotation
(
TypeAnno
.
class
)
!=
null
);
check
(
t
[
0
].
getAnnotationsByType
(
TypeAnno
.
class
)[
0
].
value
().
equals
(
"1"
));
check
(
t
[
1
].
getAnnotations
().
length
==
0
);
check
(
t
[
1
].
getAnnotation
(
TypeAnno
.
class
)
==
null
);
check
(
t
[
1
].
getAnnotation
(
TypeAnno2
.
class
)
==
null
);
check
(
t
[
2
].
getAnnotations
().
length
==
2
);
check
(
t
[
2
].
getAnnotations
()[
0
].
annotationType
().
equals
(
TypeAnno
.
class
));
check
(
t
[
2
].
getAnnotation
(
TypeAnno
.
class
)
!=
null
);
check
(
t
[
2
].
getAnnotation
(
TypeAnno2
.
class
)
!=
null
);
check
(
t
[
2
].
getAnnotationsByType
(
TypeAnno
.
class
)[
0
].
value
().
equals
(
"3a"
));
check
(
t
[
2
].
getAnnotationsByType
(
TypeAnno2
.
class
)[
0
].
value
().
equals
(
"3b"
));
// NO ANNOTATED PARAM TYPES
m
=
Params
.
class
.
getDeclaredMethod
(
"unAnnotated"
,
(
Class
<?>[])
argsArr
);
t
=
m
.
getAnnotatedParameterTypes
();
check
(
t
.
length
==
3
);
check
(
t
[
0
].
getAnnotations
().
length
==
0
);
check
(
t
[
0
].
getAnnotation
(
TypeAnno
.
class
)
==
null
);
check
(
t
[
0
].
getAnnotation
(
TypeAnno2
.
class
)
==
null
);
check
(
t
[
1
].
getAnnotations
().
length
==
0
);
check
(
t
[
1
].
getAnnotation
(
TypeAnno
.
class
)
==
null
);
check
(
t
[
1
].
getAnnotation
(
TypeAnno2
.
class
)
==
null
);
check
(
t
[
2
].
getAnnotations
().
length
==
0
);
check
(
t
[
2
].
getAnnotation
(
TypeAnno
.
class
)
==
null
);
check
(
t
[
2
].
getAnnotation
(
TypeAnno2
.
class
)
==
null
);
}
private
static
void
testParameterType
()
throws
Exception
{
// NO PARAMS
Method
m
=
Params
.
class
.
getDeclaredMethod
(
"noParams"
,
(
Class
<?>[])
null
);
Parameter
[]
p
=
m
.
getParameters
();
check
(
p
.
length
==
0
);
// ONLY ANNOTATED PARAM TYPES
Class
[]
argsArr
=
{
String
.
class
,
String
.
class
,
String
.
class
};
m
=
Params
.
class
.
getDeclaredMethod
(
"onlyAnnotated"
,
(
Class
<?>[])
argsArr
);
p
=
m
.
getParameters
();
check
(
p
.
length
==
3
);
AnnotatedType
t0
=
p
[
0
].
getAnnotatedType
();
AnnotatedType
t1
=
p
[
1
].
getAnnotatedType
();
AnnotatedType
t2
=
p
[
2
].
getAnnotatedType
();
check
(
t0
.
getAnnotations
().
length
==
1
);
check
(
t0
.
getAnnotation
(
TypeAnno
.
class
)
!=
null
);
check
(
t0
.
getAnnotationsByType
(
TypeAnno
.
class
)[
0
].
value
().
equals
(
"1"
));
check
(
t1
.
getAnnotations
().
length
==
1
);
check
(
t1
.
getAnnotation
(
TypeAnno
.
class
)
!=
null
);
check
(
t1
.
getAnnotationsByType
(
TypeAnno
.
class
)[
0
].
value
().
equals
(
"2"
));
check
(
t2
.
getAnnotations
().
length
==
2
);
check
(
t2
.
getAnnotations
()[
0
].
annotationType
().
equals
(
TypeAnno
.
class
));
check
(
t2
.
getAnnotation
(
TypeAnno
.
class
)
!=
null
);
check
(
t2
.
getAnnotation
(
TypeAnno2
.
class
)
!=
null
);
check
(
t2
.
getAnnotationsByType
(
TypeAnno
.
class
)[
0
].
value
().
equals
(
"3a"
));
check
(
t2
.
getAnnotationsByType
(
TypeAnno2
.
class
)[
0
].
value
().
equals
(
"3b"
));
// MIXED ANNOTATED PARAM TYPES
m
=
Params
.
class
.
getDeclaredMethod
(
"mixed"
,
(
Class
<?>[])
argsArr
);
p
=
m
.
getParameters
();
check
(
p
.
length
==
3
);
t0
=
p
[
0
].
getAnnotatedType
();
t1
=
p
[
1
].
getAnnotatedType
();
t2
=
p
[
2
].
getAnnotatedType
();
check
(
t0
.
getAnnotations
().
length
==
1
);
check
(
t0
.
getAnnotation
(
TypeAnno
.
class
)
!=
null
);
check
(
t0
.
getAnnotationsByType
(
TypeAnno
.
class
)[
0
].
value
().
equals
(
"1"
));
check
(
t1
.
getAnnotations
().
length
==
0
);
check
(
t1
.
getAnnotation
(
TypeAnno
.
class
)
==
null
);
check
(
t1
.
getAnnotation
(
TypeAnno2
.
class
)
==
null
);
check
(
t2
.
getAnnotations
().
length
==
2
);
check
(
t2
.
getAnnotations
()[
0
].
annotationType
().
equals
(
TypeAnno
.
class
));
check
(
t2
.
getAnnotation
(
TypeAnno
.
class
)
!=
null
);
check
(
t2
.
getAnnotation
(
TypeAnno2
.
class
)
!=
null
);
check
(
t2
.
getAnnotationsByType
(
TypeAnno
.
class
)[
0
].
value
().
equals
(
"3a"
));
check
(
t2
.
getAnnotationsByType
(
TypeAnno2
.
class
)[
0
].
value
().
equals
(
"3b"
));
// NO ANNOTATED PARAM TYPES
m
=
Params
.
class
.
getDeclaredMethod
(
"unAnnotated"
,
(
Class
<?>[])
argsArr
);
p
=
m
.
getParameters
();
check
(
p
.
length
==
3
);
t0
=
p
[
0
].
getAnnotatedType
();
t1
=
p
[
1
].
getAnnotatedType
();
t2
=
p
[
2
].
getAnnotatedType
();
check
(
t0
.
getAnnotations
().
length
==
0
);
check
(
t0
.
getAnnotation
(
TypeAnno
.
class
)
==
null
);
check
(
t0
.
getAnnotation
(
TypeAnno2
.
class
)
==
null
);
check
(
t1
.
getAnnotations
().
length
==
0
);
check
(
t1
.
getAnnotation
(
TypeAnno
.
class
)
==
null
);
check
(
t1
.
getAnnotation
(
TypeAnno2
.
class
)
==
null
);
check
(
t2
.
getAnnotations
().
length
==
0
);
check
(
t2
.
getAnnotation
(
TypeAnno
.
class
)
==
null
);
check
(
t2
.
getAnnotation
(
TypeAnno2
.
class
)
==
null
);
}
}
class
Params
{
public
void
noParams
()
{}
public
void
onlyAnnotated
(
@TypeAnno
(
"1"
)
String
s1
,
@TypeAnno
(
"2"
)
String
s2
,
@TypeAnno
(
"3a"
)
@TypeAnno2
(
"3b"
)
String
s3
)
{}
public
void
mixed
(
@TypeAnno
(
"1"
)
String
s1
,
String
s2
,
@TypeAnno
(
"3a"
)
@TypeAnno2
(
"3b"
)
String
s3
)
{}
public
void
unAnnotated
(
String
s1
,
String
s2
,
String
s3
)
{}
}
abstract
class
TestWildcardType
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录