-
Notifications
You must be signed in to change notification settings - Fork 0
/
chapter-6.txt
2132 lines (1216 loc) · 114 KB
/
chapter-6.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Chapter 6. Names
Table of Contents
6.1. Declarations
6.2. Names and Identifiers
6.3. Scope of a Declaration
6.3.1. Scope for Pattern Variables in Expressions
6.3.1.1. Conditional-And Operator &&
6.3.1.2. Conditional-Or Operator ||
6.3.1.3. Logical Complement Operator !
6.3.1.4. Conditional Operator ? :
6.3.1.5. Pattern Match Operator instanceof
6.3.1.6. switch Expressions
6.3.1.7. Parenthesized Expressions
6.3.2. Scope for Pattern Variables in Statements
6.3.2.1. Blocks
6.3.2.2. if Statements
6.3.2.3. while Statements
6.3.2.4. do Statements
6.3.2.5. for Statements
6.3.2.6. switch Statements
6.3.2.7. Labeled Statements
6.3.3. Scope for Pattern Variables in case Labels
6.4. Shadowing and Obscuring
6.4.1. Shadowing
6.4.2. Obscuring
6.5. Determining the Meaning of a Name
6.5.1. Syntactic Classification of a Name According to Context
6.5.2. Reclassification of Contextually Ambiguous Names
6.5.3. Meaning of Module Names and Package Names
6.5.3.1. Simple Package Names
6.5.3.2. Qualified Package Names
6.5.4. Meaning of PackageOrTypeNames
6.5.4.1. Simple PackageOrTypeNames
6.5.4.2. Qualified PackageOrTypeNames
6.5.5. Meaning of Type Names
6.5.5.1. Simple Type Names
6.5.5.2. Qualified Type Names
6.5.6. Meaning of Expression Names
6.5.6.1. Simple Expression Names
6.5.6.2. Qualified Expression Names
6.5.7. Meaning of Method Names
6.5.7.1. Simple Method Names
6.6. Access Control
6.6.1. Determining Accessibility
6.6.2. Details on protected Access
6.6.2.1. Access to a protected Member
6.6.2.2. Access to a protected Constructor
6.7. Fully Qualified Names and Canonical Names
Names are used to refer to entities declared in a program.
A declared entity (§6.1) is a package, a class, an interface, a member (class, interface, field, or method) of a reference type, a type parameter, a formal parameter, an exception parameter, or a local variable.
Names in programs are either simple, consisting of a single identifier, or qualified, consisting of a sequence of identifiers separated by "." tokens (§6.2).
Every declaration that introduces a name has a scope (§6.3), which is the part of the program text within which the declared entity can be referred to by a simple name.
A qualified name N.x may be used to refer to a member of a package or reference type, where N is a simple or qualified name and x is an identifier. If N names a package, then x is a member of that package, which is either a class, an interface, or a subpackage. If N names a reference type or a variable of a reference type, then x names a member of that type, which is either a class, an interface, a field, or a method.
In determining the meaning of a name (§6.5), the context of the occurrence is used to disambiguate among packages, types, variables, and methods with the same name.
Access control (§6.6) can be specified in a class, interface, method, or field declaration to control when access to a member is allowed. Access is a different concept from scope. Access specifies the part of the program text within which the declared entity can be referred to by a qualified name. Access to a declared entity is also relevant in a field access expression (§15.11), a method invocation expression in which the method is not specified by a simple name (§15.12), a method reference expression (§15.13), or a qualified class instance creation expression (§15.9). In the absence of an access modifier, most declarations have package access, allowing access anywhere within the package that contains its declaration; other possibilities are public, protected, and private.
Fully qualified and canonical names (§6.7) are also discussed in this chapter.
6.1. Declarations
A declaration introduces one of the following entities into a program:
A module, declared in a module declaration (§7.7)
A package, declared in a package declaration (§7.4)
An imported class or interface, declared in a single-type-import declaration or a type-import-on-demand declaration (§7.5.1, §7.5.2)
An imported static member, declared in a single-static-import declaration or a static-import-on-demand declaration (§7.5.3, §7.5.4)
A class, declared by a normal class declaration (§8.1), an enum declaration (§8.9), or a record declaration (§8.10)
An interface, declared by a normal interface declaration (§9.1) or an annotation interface declaration (§9.6).
A type parameter, declared as part of the declaration of a generic class, interface, method, or constructor (§8.1.2, §9.1.2, §8.4.4, §8.8.4)
A member of a reference type (§8.2, §9.2, §8.9.3, §9.6, §10.7), one of the following:
A member class (§8.5, §9.5)
A member interface (§8.5, §9.5)
A field, one of the following:
A field declared in a class (§8.3)
A field declared in an interface (§9.3)
An implicitly declared field of a class corresponding to an enum constant or a record component
The field length, which is implicitly a member of every array type (§10.7)
A method, one of the following:
A method (abstract or otherwise) declared in a class (§8.4)
A method (abstract or otherwise) declared in an interface (§9.4)
An implicitly declared accessor method corresponding to a record component
An enum constant (§8.9.1)
A record component (§8.10.3)
A formal parameter, one of the following:
A formal parameter of a method of a class or interface (§8.4.1)
A formal parameter of a constructor of a class (§8.8.1)
A formal parameter of a lambda expression (§15.27.1)
An exception parameter of an exception handler declared in a catch clause of a try statement (§14.20)
A local variable, one of the following:
A local variable declared by a local variable declaration statement in a block (§14.4.2)
A local variable declared by a for statement or a try-with-resources statement (§14.14, §14.20.3)
A local variable declared by a pattern (§14.30.1)
A local class or interface (§14.3), one of the following:
A local class declared by a normal class declaration
A local class declared by an enum declaration
A local class declared by an record declaration
A local interface declared by a normal interface declaration
Constructors (§8.8, §8.10.4) are also introduced by declarations, but use the name of the class in which they are declared rather than introducing a new name.
A declaration commonly includes an identifier (§3.8) that can be used in a name to refer to the declared entity. The identifier is constrained to avoid certain contextual keywords when the entity being introduced is a class, interface, or type parameter.
If a declaration does not include an identifier, but instead includes the keyword _ (underscore), then the entity cannot be referred to by name. The following kinds of entity may be declared using an underscore:
A local variable, one of the following:
A local variable declared by a local variable declaration statement (§14.4.2)
A local variable declared by a for statement or a try-with-resources statement (§14.14, §14.20.3)
A local variable declared by a pattern (§14.30.1)
An exception parameter of an exception handler declared in a catch clause of a try statement (§14.20)
A formal parameter of a lambda expression (§15.27.1)
A local variable, exception parameter, or lambda parameter that is declared using an underscore is called an unnamed local variable, unnamed exception parameter, or unnamed lambda parameter, respectively.
The declaration of a generic class or interface (class C<T> ... or interface C<T> ...) introduces both a class named C and a family of types: the raw type C, the parameterized type C<Foo>, the parameterized type C<Bar>, etc.
When a reference to C occurs where genericity is unimportant, identified below as one of the non-generic contexts, the reference to C denotes the class or interface C. In other contexts, the reference to C denotes a type, or part of a type, introduced by C.
The 15 non-generic contexts are as follows:
In a uses or provides directive in a module declaration (§7.7.1)
In a single-type-import declaration (§7.5.1)
To the left of the . in a single-static-import declaration (§7.5.3)
To the left of the . in a static-import-on-demand declaration (§7.5.4)
In a permits clause of a sealed class or interface declaration (§8.1.6, §9.1.4).
To the left of the ( in a constructor declaration (§8.8)
After the @ sign in an annotation (§9.7)
To the left of .class in a class literal (§15.8.2)
To the left of .this in a qualified this expression (§15.8.4)
To the left of .super in a qualified superclass field access expression (§15.11.2)
To the left of .Identifier or .super.Identifier in a qualified method invocation expression (§15.12)
To the left of .super:: in a method reference expression (§15.13)
In a qualified expression name in a postfix expression or a try-with-resources statement (§15.14.1, §14.20.3)
In a throws clause of a method or constructor (§8.4.6, §8.8.5, §9.4)
In an exception parameter declaration (§14.20)
The first twelve non-generic contexts correspond to the first twelve syntactic contexts for a TypeName in §6.5.1. The thirteenth non-generic context is where a qualified ExpressionName such as C.x may include a TypeName C to denote static member access. The common use of TypeName in these thirteen contexts is significant: it indicates that these contexts involve a less-than-first-class use of a type. In contrast, the fourteenth and fifteenth non-generic contexts employ ClassType, indicating that throws and catch clauses use types in a first-class way, in line with, for example, field declarations. The characterization of these two contexts as non-generic is due to the fact that an exception type cannot be parameterized (§8.1.2).
Note that the ClassType production allows annotations, so it is possible to annotate the use of a type in a throws or catch clause, whereas the TypeName production disallows annotations, so it is not possible to annotate the name of a type in, for example, a single-type-import declaration.
Naming Conventions
The class libraries of the Java SE Platform attempt to use, whenever possible, names chosen according to the conventions presented below. These conventions help to make code more readable and avoid certain kinds of name conflicts.
We recommend these conventions for use in all programs written in the Java programming language. However, these conventions should not be followed slavishly if long-held conventional usage dictates otherwise. So, for example, the sin and cos methods of the class java.lang.Math have mathematically conventional names, even though these method names flout the convention suggested here because they are short and are not verbs.
Package Names and Module Names
Programmers should take steps to avoid the possibility of two published packages having the same name by choosing unique package names for packages that are widely distributed. This allows packages to be easily and automatically installed and catalogued. This section specifies a suggested convention for generating such unique package names. Implementations of the Java SE Platform are encouraged to provide automatic support for converting a set of packages from local and casual package names to the unique name format described here.
If unique package names are not used, then package name conflicts may arise far from the point of creation of either of the conflicting packages. This may create a situation that is difficult or impossible for the user or programmer to resolve. The classes ClassLoader and ModuleLayer can be used to isolate packages with the same name from each other in those cases where the packages will have constrained interactions, but not in a way that is transparent to a naïve program.
You form a unique package name by first having (or belonging to an organization that has) an Internet domain name, such as oracle.com. You then reverse this name, component by component, to obtain, in this example, com.oracle, and use this as a prefix for your package names, using a convention developed within your organization to further administer package names. Such a convention might specify that certain package name components be division, department, project, machine, or login names.
Example 6.1-1. Unique Package Names
com.nighthacks.scrabble.dictionary
org.openjdk.compiler.source.tree
net.jcip.annotations
edu.cmu.cs.bovik.cheese
gov.whitehouse.socks.mousefinder
The first component of a unique package name is always written in all-lowercase ASCII letters and should be one of the top level domain names, such as com, edu, gov, mil, net, or org, or one of the English two-letter codes identifying countries as specified in ISO Standard 3166.
In some cases, the Internet domain name may not be a valid package name. Here are some suggested conventions for dealing with these situations:
If the domain name contains a hyphen, or any other special character not allowed in an identifier (§3.8), convert it into an underscore.
If any of the resulting package name components are keywords (§3.9), append an underscore to them.
If any of the resulting package name components start with a digit, or any other character that is not allowed as an initial character of an identifier, have an underscore prefixed to the component.
The name of a module should correspond to the name of its principal exported package. If a module does not have such a package, or if for legacy reasons it must have a name that does not correspond to one of its exported packages, then its name should still start with the reversed form of an Internet domain with which its author is associated.
Example 6.1-2. Unique Module Names
com.nighthacks.scrabble
org.openjdk.compiler
net.jcip.annotations
The first component of a package or module name must not be the identifier java. Package and module names that start with the identifier java are reserved for packages and modules of the Java SE Platform.
The name of a package or module is not meant to imply where the package or module is stored on the Internet. For example, a package named edu.cmu.cs.bovik.cheese is not necessarily obtainable from the host cmu.edu or cs.cmu.edu or bovik.cs.cmu.edu. The suggested convention for generating unique package and module names is merely a way to piggyback a package and module naming convention on top of an existing, widely known unique name registry instead of having to create a separate registry for package and module names.
Class and Interface Names
Names of class should be descriptive nouns or noun phrases, not overly long, in mixed case with the first letter of each word capitalized.
Example 6.1-3. Descriptive Class Names
ClassLoader
SecurityManager
Thread
Dictionary
BufferedInputStream
Likewise, names of interface should be short and descriptive, not overly long, in mixed case with the first letter of each word capitalized. The name may be a descriptive noun or noun phrase, which is appropriate when an interface is used as if it were an abstract superclass, such as interfaces java.io.DataInput and java.io.DataOutput; or it may be an adjective describing a behavior, as for the interfaces Runnable and Cloneable.
Type Variable Names
Type variable names should be pithy (single character if possible) yet evocative, and should not include lower case letters. This makes it easy to distinguish type parameters from ordinary classes and interfaces.
Container classes and interfaces should use the name E for their element type. Maps should use K for the type of their keys and V for the type of their values. The name X should be used for arbitrary exception types. We use T for type, whenever there is not anything more specific about the type to distinguish it. (This is often the case in generic methods.)
If there are multiple type parameters that denote arbitrary types, one should use letters that neighbor T in the alphabet, such as S. Alternately, it is acceptable to use numeric subscripts (e.g., T1, T2) to distinguish among the different type variables. In such cases, all the variables with the same prefix should be subscripted.
If a generic method appears inside a generic class, it is a good idea to avoid using the same names for the type parameters of the method and class, to avoid confusion. The same applies to nested generic classes.
Example 6.1-4. Conventional Type Variable Names
public class HashSet<E> extends AbstractSet<E> { ... }
public class HashMap<K,V> extends AbstractMap<K,V> { ... }
public class ThreadLocal<T> { ... }
public interface Functor<T, X extends Throwable> {
T eval() throws X;
}
When type parameters do not fall conveniently into one of the categories mentioned, names should be chosen to be as meaningful as possible within the confines of a single letter. The names mentioned above (E, K, V, X, T) should not be used for type parameters that do not fall into the designated categories.
Method Names
Method names should be verbs or verb phrases, in mixed case, with the first letter lowercase and the first letter of any subsequent words capitalized. Here are some additional specific conventions for method names:
Methods to get and set an attribute that might be thought of as a variable V should be named getV and setV. An example is the methods getPriority and setPriority of class Thread.
A method that returns the length of something should be named length, as in class String.
A method that tests a boolean condition V about an object should be named isV. An example is the method isInterrupted of class Thread.
A method that converts its object to a particular format F should be named toF. Examples are the method toString of class Object and the methods toLocaleString and toGMTString of class java.util.Date.
Whenever possible and appropriate, basing the names of methods in a new class on names in an existing class that is similar, especially a class from the Java SE Platform API, will make it easier to use.
Field Names
Names of fields that are not final should be in mixed case with a lowercase first letter and the first letters of subsequent words capitalized. Note that well-designed classes have very few public or protected fields, except for fields that are constants (static final fields).
Fields should have names that are nouns, noun phrases, or abbreviations for nouns.
Examples of this convention are the fields buf, pos, and count of the class java.io.ByteArrayInputStream and the field bytesTransferred of the class java.io.InterruptedIOException.
Constant Names
The names of constants in interfaces should be, and final variables of classes may conventionally be, a sequence of one or more words, acronyms, or abbreviations, all uppercase, with components separated by underscore "_" characters. Constant names should be descriptive and not unnecessarily abbreviated. Conventionally they may be any appropriate part of speech.
Examples of names for constants include MIN_VALUE, MAX_VALUE, MIN_RADIX, and MAX_RADIX of the class Character.
A group of constants that represent alternative values of a set, or, less frequently, masking bits in an integer value, are sometimes usefully specified with a common acronym as a name prefix.
For example:
interface ProcessStates {
int PS_RUNNING = 0;
int PS_SUSPENDED = 1;
}
Local Variable and Parameter Names
Local variable and parameter names should be short, yet meaningful. They are often short sequences of lowercase letters that are not words, such as:
Acronyms, that is the first letter of a series of words, as in cp for a variable holding a reference to a ColoredPoint
Abbreviations, as in buf holding a pointer to a buffer of some kind
Mnemonic terms, organized in some way to aid memory and understanding, typically by using a set of local variables with conventional names patterned after the names of parameters to widely used classes. For example:
in and out, whenever some kind of input and output are involved, patterned after the fields of System
off and len, whenever an offset and length are involved, patterned after the parameters to the read and write methods of the interfaces DataInput and DataOutput of java.io
One-character local variable or parameter names should be avoided, except for temporary and looping variables, or where a variable holds an undistinguished value of a type. Conventional one-character names are:
b for a byte
c for a char
d for a double
e for an Exception
f for a float
i, j, and k for ints
l for a long
o for an Object
s for a String
v for an arbitrary value of some type
Local variable or parameter names that consist of only two or three lowercase letters should not conflict with the initial country codes and domain names that are the first component of unique package names.
6.2. Names and Identifiers
A name is used to refer to an entity declared in a program.
There are two forms of names: simple names and qualified names.
A simple name is a single identifier.
A qualified name consists of a name, a "." token, and an identifier.
In determining the meaning of a name (§6.5), the context in which the name appears is taken into account. The rules of §6.5 distinguish among contexts where a name must denote (refer to) a package (§6.5.3); a class, interface, or type parameter (§6.5.5); a variable or value in an expression (§6.5.6); or a method (§6.5.7).
Packages, classes, interfaces, and type parameters have members which may be accessed by qualified names. As background for the discussion of qualified names and the determination of the meaning of names, see the descriptions of membership in §4.4, §4.5.2, §4.8, §4.9, §7.1, §8.2, §9.2, and §10.7.
Not all identifiers in a program are a part of a name. Identifiers are also used in the following situations:
In declarations (§6.1), where an identifier may occur to specify the name by which the declared entity will be known.
As labels in labeled statements (§14.7) and in break and continue statements (§14.15, §14.16) that refer to statement labels.
The identifiers used in labeled statements and their associated break and continue statements are completely separate from those used in declarations.
In field access expressions (§15.11), where an identifier occurs after a "." token to indicate a member of the object denoted by the expression before the "." token, or the object denoted by the super or TypeName.super before the "." token.
In some method invocation expressions (§15.12), wherever an identifier occurs after a "." token and before a "(" token to indicate a method to be invoked for the object denoted by the expression before the "." token, or the type denoted by the TypeName before the "." token, or the object denoted by the super or TypeName.super before the "." token.
In some method reference expressions (§15.13), wherever an identifier occurs after a "::" token to indicate a method of the object denoted by the expression before the "::" token, or the type denoted by the TypeName before the "::" token, or the object denoted by the super or TypeName.super before the "::" token.
In qualified class instance creation expressions (§15.9), where an identifier occurs to the right of the new token to indicate a type that is a member of the compile-time type of the expression preceding the new token.
In element-value pairs of annotations (§9.7.1), to denote an element of the corresponding annotation interface.
In this program:
class Test {
public static void main(String[] args) {
Class c = System.out.getClass();
System.out.println(c.toString().length() +
args[0].length() + args.length);
}
}
the identifiers Test, main, and the first occurrences of args and c are not names. Rather, they are identifiers used in declarations to specify the names of the declared entities. The names String, Class, System.out.getClass, System.out.println, c.toString, args, and args.length appear in the example.
The occurrence of length in args.length is a name because args.length is a qualified name (§6.5.6.2) and not a field access expression (§15.11). A field access expression, as well as a method invocation expression, a method reference expression, and a qualified class instance creation expression, uses an identifier rather than a name to denote the member of interest. Thus, the occurrence of length in args[0].length() is not a name, but rather an identifier appearing in a method invocation expression.
One might wonder why these kinds of expression use an identifier rather than a simple name, which is after all just an identifier. The reason is that a simple expression name is defined in terms of the lexical environment; that is, a simple expression name must be in the scope of a variable declaration (§6.5.6.1). On the other hand, field access, qualified method invocation, method references, and qualified class instance creation all refer to members whose names are not in the lexical environment. By definition, such names are bound only in the context provided by the Primary of the field access expression, method invocation expression, method reference expression, or class instance creation expression; or by the super of the field access expression, method invocation expression, or method reference expression; and so on. Thus, we denote such members with identifiers rather than simple names.
To complicate things further, a field access expression is not the only way to denote a field of an object. For parsing reasons, a qualified name is used to denote a field of an in-scope variable. (The variable itself is denoted with a simple name, alluded to above.) It is necessary for access control (§6.6) to apply to both denotations of a field.
6.3. Scope of a Declaration
The scope of a declaration is the region of the program within which the entity declared by the declaration can be referred to using a simple name, provided it is not shadowed (§6.4.1).
A declaration is said to be in scope at a particular point in a program if and only if the declaration's scope includes that point.
The scope of the declaration of an observable top level package (§7.4.3) is all observable compilation units associated with modules to which the package is uniquely visible (§7.4.3).
The declaration of a package that is not observable is never in scope.
The declaration of a subpackage is never in scope.
The package java is always in scope.
The scope of a class or interface imported by a single-type-import declaration (§7.5.1) or a type-import-on-demand declaration (§7.5.2) is the module declaration (§7.7) and all the class and interface declarations (§8.1, §9.1) of the compilation unit in which the import declaration appears, as well as any annotations on the module declaration or package declaration of the compilation unit.
The scope of a member imported by a single-static-import declaration (§7.5.3) or a static-import-on-demand declaration (§7.5.4) is the module declaration and all the class and interface declarations of the compilation unit in which the import declaration appears, as well as any annotations on the module declaration or package declaration of the compilation unit.
The scope of a top level class or interface (§7.6) is all class and interface declarations in the package in which the top level class or interface is declared.
The scope of a declaration of a member m declared in or inherited by a class or interface C (§8.2, §9.2) is the entire body of C, including any nested class or interface declarations. If C is a record class, then the scope of m additionally includes the header of the record declaration of C.
The scope of a formal parameter of a method (§8.4.1), constructor (§8.8.1), or lambda expression (§15.27) is the entire body of the method, constructor, or lambda expression.
The scope of a class's type parameter (§8.1.2) is the type parameter section of the class declaration, and the type parameter section of any superclass type or superinterface type of the class declaration, and the class body. If the class is a record class (§8.10), then the scope of the type parameter additionally includes the header of the record declaration (§8.10.1).
The scope of an interface's type parameter (§9.1.2) is the type parameter section of the interface declaration, and the type parameter section of any superinterface type of the interface declaration, and the interface body.
The scope of a method's type parameter (§8.4.4) is the entire declaration of the method, including the type parameter section, but excluding the method modifiers.
The scope of a constructor's type parameter (§8.8.4) is the entire declaration of the constructor, including the type parameter section, but excluding the constructor modifiers.
The scope of a local class or interface declaration immediately enclosed by a block (§14.2) is the rest of the immediately enclosing block, including the local class or interface declaration itself.
The scope of a local class or interface declaration immediately enclosed by a switch block statement group (§14.11) is the rest of the immediately enclosing switch block statement group, including the local class or interface declaration itself.
The scope of a local variable declared in a block by a local variable declaration statement (§14.4.2) is the rest of the block, starting with the declaration's own initializer and including any further declarators to the right in the local variable declaration statement.
The scope of a local variable declared in the ForInit part of a basic for statement (§14.14.1) includes all of the following:
Its own initializer
Any further declarators to the right in the ForInit part of the for statement
The Expression and ForUpdate parts of the for statement
The contained Statement
The scope of a local variable declared in the header of an enhanced for statement (§14.14.2) is the contained Statement.
The scope of a local variable declared in the resource specification of a try-with-resources statement (§14.20.3) is from the declaration rightward over the remainder of the resource specification and the entire try block associated with the try-with-resources statement.
The translation of a try-with-resources statement implies the rule above.
The scope of a parameter of an exception handler that is declared in a catch clause of a try statement (§14.20) is the entire block associated with the catch.
Example 6.3-1. Scope of Class Declarations
These rules imply that declarations of class and interface types need not appear before uses of the types. In the following program, the use of PointList in class Point is valid, because the scope of the class declaration PointList includes both class Point and class PointList, as well as any other class or interface declarations in other compilation units of package points.
package points;
class Point {
int x, y;
PointList list;
Point next;
}
class PointList {
Point first;
}
Example 6.3-2. Scope of Local Variable Declarations
The following program causes a compile-time error because the initialization of local variable x is within the scope of the declaration of local variable x, but the local variable x does not yet have a value and cannot be used. The field x has a value of 0 (assigned when Test1 was initialized) but is a red herring since it is shadowed (§6.4.1) by the local variable x.
class Test1 {
static int x;
public static void main(String[] args) {
int x = x;
}
}
The following program does compile:
class Test2 {
static int x;
public static void main(String[] args) {
int x = (x=2)*2;
System.out.println(x);
}
}
because the local variable x is definitely assigned (§16 (Definite Assignment)) before it is used. It prints:
4
In the following program, the initializer for three can correctly refer to the variable two declared in an earlier declarator, and the method invocation in the next line can correctly refer to the variable three declared earlier in the block.
class Test3 {
public static void main(String[] args) {
System.out.print("2+1=");
int two = 2, three = two + 1;
System.out.println(three);
}
}
This program produces the output:
2+1=3
The scope of a pattern variable declaration (that is, a local variable declared by a pattern) is the part of the program that might be executed after the matching of a value against the pattern has succeeded (§14.30.2). It is determined by considering the program points where the pattern variable is definitely matched in a region beginning with the pattern that declares the pattern variable.
The remainder of this section is devoted to a precise explanation of the words "definitely matched". The analysis takes into account the structure of statements and expressions, with a special treatment for the boolean expression operators and certain statement forms.
It will be seen that the scope of a pattern variable declaration is a flow-dependent concept similar to definite assignment (§16 (Definite Assignment)). The rules defined in the rest of this section deliberately have a similar form to the rules of definite assignment.
The analysis relies on the technical term "introduced by", which has the following form:
a pattern variable is introduced by an expression when true
a pattern variable is introduced by an expression when false
a pattern variable is introduced by a statement
The simplest example is that the pattern variable s is introduced by the expression a instanceof String s when true. In other words, if the value of the expression is true then the pattern matching must have succeeded, and thus the pattern variable must have been assigned a value.
In contrast, the pattern variable t is introduced by the expression !(b instanceof Integer t) when false. This is because the pattern matching could only have succeeded if the value of the expression is false.
6.3.1. Scope for Pattern Variables in Expressions
Only certain kinds of boolean expressions are involved in introducing pattern variables and determining where those variables are definitely matched. If an expression is not a conditional-and expression, conditional-or expression, logical complement expression, conditional expression, instanceof expression, switch expression, or parenthesized expression, then no scope rules apply.
6.3.1.1. Conditional-And Operator &&
The following rules apply to a conditional-and expression a && b (§15.23):
A pattern variable introduced by a when true is definitely matched at b.
A pattern variable is introduced by a && b when true iff either (i) it is introduced by a when true or (ii) it is introduced by b when true.
It should be noted that there is no rule for introducing a pattern variable by a && b when false. This is because it cannot be determined at compile time which operand will evaluate to false.
It is a compile-time error if any of the following conditions hold:
A pattern variable is both (i) introduced by a when true and (ii) introduced by b when true.
A pattern variable is both (i) introduced by a when false and (ii) introduced by b when false.
These two error cases exclude the possibility of both operands of the && operator declaring a pattern variable of the same name. For example, consider the problematic expression (a instanceof String s) && (b instanceof String s). The first error case covers the entire expression evaluating to true, where (if the code were legal) two declarations of a pattern variable s would need to be initialized, given that both the left-hand operand and the right-hand operand evaluated to true. Since there is no way to distinguish the two variables called s in the rest of the program, the entire expression is considered erroneous. The second error case covers the opposite scenario where the entire expression evaluates to false.
6.3.1.2. Conditional-Or Operator ||
The following rules apply to a conditional-or expression a || b (§15.24):
A pattern variable introduced by a when false is definitely matched at b.
A pattern variable is introduced by a || b when false iff either (i) it is introduced by a when false or (ii) it is introduced by b when false.
It should be noted that there is no rule for introducing a pattern variable by a || b when true. This is because it cannot be determined at compile time which operand will evaluate to true.
It is a compile-time error if any of the following conditions hold:
A pattern variable is both (i) introduced by a when true and (ii) introduced by b when true.
A pattern variable is both (i) introduced by a when false and (ii) introduced by b when false.
These two error cases exclude the possibility of both operands of the || operator declaring a pattern variable of the same name. For example, consider the problematic expression (a instanceof String s) || (b instanceof String s). The first error case covers the entire expression evaluating to true, where (if the code were legal) exactly one declaration of a pattern variable s would be initialized depending on whether the left-hand operand or the right-hand operand evaluated to true. Since it cannot be determined at compile time which operand will evaluate to true, and therefore which declaration of s will be initialized, the entire expression is considered erroneous. The second error case covers the opposite scenario where the entire expression evaluates to false.
6.3.1.3. Logical Complement Operator !
The following rules apply to a logical complement expression !a (§15.15.6):
A pattern variable is introduced by !a when true iff it is introduced by a when false.
A pattern variable is introduced by !a when false iff it is introduced by a when true.
6.3.1.4. Conditional Operator ? :
The following rules apply to a conditional expression a ? b : c (§15.25):
A pattern variable introduced by a when true is definitely matched at b.
A pattern variable introduced by a when false is definitely matched at c.
It should be noted that there are no rules for introducing a pattern variable by a ? b : c when true or false. This is because it cannot be determined at compile time whether the operand a will evaluate to true.
It is a compile-time error if any of the following conditions hold:
A pattern variable is both (i) introduced by a when true and (ii) introduced by c when true.
A pattern variable is both (i) introduced by a when true and (ii) introduced by c when false.
A pattern variable is both (i) introduced by a when false and (ii) introduced by b when true.
A pattern variable is both (i) introduced by a when false and (ii) introduced by b when false.
A pattern variable is both (i) introduced by b when true and (ii) introduced by c when true.
A pattern variable is both (i) introduced by b when false and (ii) introduced by c when false.
These error cases are analogous to similar error cases for the && and || operators. They eliminate confusing cases where multiple declarations of the same pattern variable may occur across the operands of the ? : operator.
6.3.1.5. Pattern Match Operator instanceof
The following rule applies to an instanceof expression with a pattern operand, a instanceof p (§15.20.2):
A pattern variable is introduced by a instanceof p when true iff the pattern p contains a declaration of the pattern variable (§14.30.1).
A pattern variable is not permitted to shadow another local variable (§6.4).
It should be noted that there is no rule for introducing a pattern variable by a instanceof p when false.
6.3.1.6. switch Expressions
The following rule applies to a switch expression with a switch block consisting of switch rules (§14.11.1):
A pattern variable introduced by a switch label is definitely matched in the associated switch rule expression, switch rule block, or switch rule throw statement.
The following rules apply to a switch expression with a switch block consisting of switch labeled statement groups (§14.11.1):
A pattern variable introduced by a switch label is definitely matched in all the statements of the associated switch labeled statement group.
A pattern variable introduced by a statement S contained in a switch labeled statement group is definitely matched at all the statements following S, if any, in the switch labeled statement group.
6.3.1.7. Parenthesized Expressions
The following rules apply to a parenthesized expression (a) (§15.8.5):
A pattern variable is introduced by (a) when true iff it is introduced by a when true.
A pattern variable is introduced by (a) when false iff it is introduced by a when false.
6.3.2. Scope for Pattern Variables in Statements
Only a few kinds of statements play a significant role in determining the scope of pattern variables.
Where an if, while, do, or for statement contains an expression that introduces pattern variables, the scope of those variables can, in certain circumstances, include substatements of the statement.
For example, in the following if-then-else statement, the scope of the pattern variable s includes one substatement but not another:
Object o = ...
if (o instanceof String s)
// s in scope for this substatement; no cast of o needed
System.out.println(s.replace('*', '_'));
else
// s not in scope for this substatement (hence, error)
System.out.println(s);
Also, in certain circumstances, a pattern variable can be introduced by a statement itself, rather than by an expression within the statement. A pattern variable introduced by a statement is in scope at the following statements in the enclosing block.
For example, in the following method, the scope of the pattern variable s includes the method body following the if statement:
void test(Object o) {
if (!(o instanceof String s)) {
throw new IllegalArgumentException();
}
// This point is only reachable if the pattern match succeeded
// Thus, s is in scope for the rest of the block
...
System.out.println(s.repeat(5));
...
}
6.3.2.1. Blocks
The following rule applies to a block statement S contained in a block (§14.2) that is not a switch block (§14.11.1):
A pattern variable introduced by S is definitely matched at all the block statements following S, if any, in the block.
6.3.2.2. if Statements
The following rules apply to a statement if (e) S (§14.9.1):
A pattern variable introduced by e when true is definitely matched at S.
A pattern variable is introduced by if (e) S iff (i) it is introduced by e when false and (ii) S cannot complete normally.
The rule about an if-then statement introducing a pattern variable relies on the notion of "cannot complete normally" (§14.22), which in turn relies on the concept of a constant expression (§15.29). This means that calculating the scope of a pattern variable may require determining whether a simple name, or a qualified name of the form TypeName . Identifier, refers to a constant variable. As pattern variables can never refer to a constant variable, there is no circularity.
The following rules apply to a statement if (e) S else T (§14.9.2):
A pattern variable introduced by e when true is definitely matched at S.
A pattern variable introduced by e when false is definitely matched at T.
A pattern variable is introduced by if (e) S else T iff either:
It is introduced by e when true, and S can complete normally, and T cannot complete normally; or
It is introduced by e when false, and S cannot complete normally, and T can complete normally.
These rules highlight the flow-like nature of scoping for pattern variables. For example, in the following statement:
if (e instanceof String s) {
counter += s.length();
} else {
System.out.println(e); // s not in scope
}
The pattern variable s is introduced by the instanceof expression and is in scope in the first contained statement (the assignment statement in the then block), but it is not in scope in the second contained statement (the expression statement in the else block).
Moreover, combined with the treatment for boolean expressions, the scope of pattern variables is robust against code refactorings that exploit the familar boolean logical equivalences. For example, the previous code can be rewritten as:
if (!(e instanceof String s)) {
System.out.println(e); // s not in scope
} else {
counter += s.length();
}
The code can even be rewritten as follows, though double use of the ! operator is not necessarily recommended:
if (!!(e instanceof String s)) {
counter += s.length();
} else {
System.out.println(e); // s not in scope
}
6.3.2.3. while Statements
The following rules apply to a statement while (e) S (§14.12):
A pattern variable introduced by e when true is definitely matched at S.
A pattern variable is introduced by while (e) S iff (i) it is introduced by e when false and (ii) S does not contain a reachable break statement for which the while statement is the break target (§14.15).
6.3.2.4. do Statements
The following rule applies to a statement do S while (e) (§14.13):
A pattern variable is introduced by do S while (e) iff (i) it is introduced by e when false and (ii) S does not contain a reachable break statement for which the do statement is the break target (§14.15).
6.3.2.5. for Statements
The following rules apply to a basic for statement (§14.14.1):
A pattern variable introduced by the condition expression when true is definitely matched at both the incrementation part and the contained statement.
A pattern variable is introduced by a basic for statement iff (i) it is introduced by the condition expression when false and (ii) the contained statement, S, does not contain a reachable break for which the basic for statement is the break target (§14.15).
An enhanced for statement (§14.14.2) is defined by translation to a basic for statement, so no special rules need to be provided for it.
6.3.2.6. switch Statements
The following rule applies to a switch statement with a switch block consisting of switch rules (§14.11.1):
A pattern variable introduced by a switch label is definitely matched in the associated switch rule expression, switch rule block, or switch rule throw statement.
The following rules apply to a switch statement with a switch block consisting of switch labeled statement groups (§14.11.1):
A pattern variable introduced by a switch label is definitely matched in all the statements of the associated switch labeled statement group.
A pattern variable introduced by a statement S contained in a switch block statement group is definitely matched at all the statements following S, if any, in the switch block statement group.
6.3.2.7. Labeled Statements
The following rule applies to a labeled statement (§14.7):
A pattern variable is introduced by a labeled statement L: S (where L is a label) iff (i) it is introduced by the statement S, and (ii) S does not contain a reachable break statement for which the labeled statement is the break target (§14.15).
6.3.3. Scope for Pattern Variables in case Labels
Pattern variables can be introduced by case labels with a case pattern, either by the pattern itself or by a guard, and are in scope for the relevant parts of the associated switch expression (§6.3.1.6) or switch statement (§6.3.2.6).
The following rules applies to case labels:
A pattern variable is introduced by a case label with a case pattern p if p contains a declaration of the pattern variable.
If a case pattern in a guarded case label contains a declaration of a pattern variable then the pattern variable is definitely matched in the associated guard.
A pattern variable is introduced by a guarded case label if it is introduced by the associated guard when true (§6.3.1).
6.4. Shadowing and Obscuring
A local variable (§14.4), formal parameter (§8.4.1, §8.8.1, §15.27.1), exception parameter (§14.20), local class, or local interface (§14.3) can only be referred to using a simple name, not a qualified name (§6.2).
Some declarations are not permitted within the scope of a local variable declaration, formal parameter declaration, exception parameter declaration, local class declaration, or local interface declaration because it would be impossible to distinguish between the declared entities using only simple names.
For example, if the name of a formal parameter of a method could be redeclared as the name of a local variable in the method body, then the local variable would shadow the formal parameter and there would be no way to refer to the formal parameter - an undesirable outcome.
It is a compile-time error if the name of a formal parameter is used to declare a new variable within the body of the method, constructor, or lambda expression, unless the new variable is declared within a class or interface declaration contained by the method, constructor, or lambda expression.
It is a compile-time error if the name of a local variable v is used to declare a new variable within the scope of v, unless the new variable is declared within a class or interface declaration appearing within the scope of v.
It is a compile-time error if the name of an exception parameter is used to declare a new variable within the Block of the catch clause, unless the new variable is declared within a class or interface declaration contained by the Block of the catch clause.
It is a compile-time error if the name of a local class or interface C is used to declare a new local class or interface within the scope of C, unless the new local class or interface is declared within a class or interface declaration appearing within the scope of C.
These rules allow redeclaration of a variable, local class, or local interface in nested class or interface declarations that occur in the scope of the variable, local class, or local interface; such nested class or interface declarations may be local class or interface declarations (§14.3) or anonymous class declarations (§15.9.5). Thus, the declaration of a formal parameter, local variable, local class, or local interface may be shadowed in a class or interface declaration nested within a method, constructor, or lambda expression; and the declaration of an exception parameter may be shadowed in a class or interface declaration nested within the Block of the catch clause.
There are two design alternatives for handling name clashes created by lambda parameters and other variables declared in lambda expressions. One is to mimic class declarations: like local classes, lambda expressions introduce a new "level" for names, and all variable names outside the expression can be redeclared. Another is a "local" strategy: like catch clauses, for loops, and blocks, lambda expressions operate at the same "level" as the enclosing context, and local variables outside the expression cannot be shadowed. The above rules use the local strategy; there is no special dispensation that allows a variable declared in a lambda expression to shadow a variable declared in an enclosing method.
Example 6.4-1. Attempted Shadowing Of A Local Variable
Because a declaration of an identifier as a local variable of a method, constructor, or initializer block must not appear within the scope of a parameter or local variable of the same name, a compile-time error occurs for the following program:
class Test1 {
public static void main(String[] args) {
int i;
for (int i = 0; i < 10; i++)
System.out.println(i);
}
}
This restriction helps to detect some otherwise very obscure bugs. A similar restriction on shadowing of members by local variables was judged impractical, because the addition of a member in a superclass could cause subclasses to have to rename local variables. Related considerations make restrictions on shadowing of local variables by members of nested classes, or on shadowing of local variables by local variables declared within nested classes unattractive as well.
Hence, the following program compiles without error:
class Test2 {
public static void main(String[] args) {
int i;
class Local {
{
for (int i = 0; i < 10; i++)
System.out.println(i);
}
}
new Local();
}
}
On the other hand, local variables with the same name may be declared in two separate blocks or for statements, neither of which contains the other:
class Test3 {
public static void main(String[] args) {
for (int i = 0; i < 10; i++)
System.out.print(i + " ");
for (int i = 10; i > 0; i--)
System.out.print(i + " ");
System.out.println();
}
}
This program compiles without error and, when executed, produces the output:
0 1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 4 3 2 1
This style is also common with pattern matching, where repeated patterns often employ the same name:
class Point {
int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
}
class Test4 {
static void test(Object a, Object b, Object c) {
if (a instanceof Point p) {
System.out.println("a is a point ("+p.x+","+p.y+")");
}
if (b instanceof Point p){
System.out.println("b is a point ("+p.x+","+p.y+")");
} else if (c instanceof Point p) {
System.out.println("c is a point ("+p.x+","+p.y+")");
}
}
public static void main(String[] args) {
Point p = new Point(2,3);
Point q = new Point(4,5);
Point r = new Point(6,7);
test(p, q, r);
}
}
However, pattern variables are not allowed to shadow local variables, including other pattern variables, so two compile-time errors occur for the following program:
class Point {
int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
}
class Test5 {
static void test(Object a, Object b, Object c) {
if (a instanceof Point p) {
System.out.println("a is a point ("+p.x+","+p.y+")");
if (b instanceof Point p) { // compile-time error
System.out.println("b is a point ("+p.x+","+p.y+")");
}
}
}
public static void main(String[] args) {
Point p = new Point(2,3);
Point q = new Point(4,5);
Point r = new Point(6,7);
test(p, q, r);
if (new Object() instanceof Point q) // compile-time error
System.out.println("I get your point");
}
}
6.4.1. Shadowing
Some declarations may be shadowed in part of their scope by another declaration of the same name, in which case a simple name cannot be used to refer to the declared entity.
Shadowing is distinct from hiding (§8.3, §8.4.8.2, §8.5, §9.3, §9.5), which applies only to members which would otherwise be inherited but are not because of a declaration in a subclass. Shadowing is also distinct from obscuring (§6.4.2).
A declaration d of a type named n shadows the declarations of any other types named n that are in scope at the point where d occurs throughout the scope of d.
A declaration d of a field or formal parameter named n shadows, throughout the scope of d, the declarations of any other variables named n that are in scope at the point where d occurs.
A declaration d of a local variable or exception parameter named n shadows, throughout the scope of d, (a) the declarations of any other fields named n that are in scope at the point where d occurs, and (b) the declarations of any other variables named n that are in scope at the point where d occurs but are not declared in the innermost class in which d is declared.
A declaration d of a method named n shadows the declarations of any other methods named n that are in an enclosing scope at the point where d occurs throughout the scope of d.
A package declaration never shadows any other declaration.
A type-import-on-demand declaration never causes any other declaration to be shadowed.
A static-import-on-demand declaration never causes any other declaration to be shadowed.
A single-type-import declaration d in a compilation unit c of package p that imports a type named n shadows, throughout c, the declarations of:
any top level type named n declared in another compilation unit of p
any type named n imported by a type-import-on-demand declaration in c
any type named n imported by a static-import-on-demand declaration in c
A single-static-import declaration d in a compilation unit c of package p that imports a field named n shadows the declaration of any static field named n imported by a static-import-on-demand declaration in c, throughout c.
A single-static-import declaration d in a compilation unit c of package p that imports a method named n with signature s shadows the declaration of any static method named n with signature s imported by a static-import-on-demand declaration in c, throughout c.
A single-static-import declaration d in a compilation unit c of package p that imports a type named n shadows, throughout c, the declarations of:
any static type named n imported by a static-import-on-demand declaration in c;
any top level type (§7.6) named n declared in another compilation unit (§7.3) of p;
any type named n imported by a type-import-on-demand declaration (§7.5.2) in c.
Example 6.4.1-1. Shadowing of a Field Declaration by a Local Variable Declaration
class Test {
static int x = 1;
public static void main(String[] args) {
int x = 0;
System.out.print("x=" + x);
System.out.println(", Test.x=" + Test.x);
}
}
This program produces the output:
x=0, Test.x=1
This program declares:
a class Test
a class (static) variable x that is a member of the class Test
a class method main that is a member of the class Test